友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

深入浅出MFC第2版(PDF格式)-第23部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!




        class Class1 { 



             public  : 



             data1; 



             data2; 



             memfunc (); 



             virtual vfunc1(); 



             virtual vfunc2 (); 



             virtual vfunc3(); 



        }; 



    Class1 对象实体在内存中占据这样的空间: 



                                                                        77 


…………………………………………………………Page 140……………………………………………………………

                                         Class1 对象实体               vtable 



                                              vptr               (*vfunc1)()           Class1::vfunc1() 

                    class Class1            m_data1              (*vfunc2)()           Class1::vfunc2() 

                    { 

                      public :              m_data2              (*vfunc3)()           Class1::vfunc3() 

                         m_data1; 

                         m_data2;                                                      Class1::memfunc() 

                         memfunc(); 

                         virtual vfunc1(); 

                         virtual vfunc2(); 

                         virtual vfunc3(); 

                    } 



                   C++                                C  

                       类别的成员函数,你可以想象就是  语言中的函数。它只是被编译器改过名称, 



                   并增加一个参数(this 指针),因而可以处理调用者(C++ 对象)中的成员变量。所以, 



                   你并没有在Class1 对象的内存区块中看到任何与成员函数有关的任何东西。 



                  每一个由此类别衍生出来的对象,都有这么一个vptr 。当我们透过这个对象调用虚拟函 



                  数,事实上是透过vptr 找到虚拟函数表,再找出虚拟函数的真正地址。 



                   奥妙在于这个虚拟函数表以及这种间接调用方式。虚拟函数表的内容是依据类别中的虚 



                   拟函数声明次序,一一填入函数指针。衍生类别会继承基础类别的虚拟函数表(以及所 



                   有其它可以继承的成员),当我们在衍生类别中改写虚拟函数时,虚拟函数表就受了影 



                   响:表中元素所指的函数地址将不再是基础类别的函数地址,而是衍生类别的函数地址。 



                   看看这个例子: 



                       class Class2 : public Class1 { 

                         public : 

                           data3; 

                           memfunc(); 

                           virtual vfunc2(); 

                       }; 



78 


…………………………………………………………Page 141……………………………………………………………

 class Class2 : public Class1 

 {                                                   vtable 

   public :                     vptr                (*vfunc1)()           Class1::vfunc1() 

     m_data3; 

     memfunc();               m_data1               (*vfunc2)()           Class2::vfunc2() 

     virtual vfunc2(); 

 }                            m_data2               (*vfunc3)()           Class1::vfunc3() 



                              m_data3                                     Class2::memfunc() 



                          Class2 对象实体 



于是,一个「指向Class1 所生对象」的指针,所调用的vf unc2 就是Class1::vf unc2 ,而 



一个「指向Class2 所生对象」的指针,所调用的vf unc2 就是Class2::vf unc2 。 



动态绑定机制,在执行时期,根据虚拟函数表,做出了正确的选择。 



我们解开了第二道神秘。 



 口说无凭,何不看点实际。观其地址,物焉C哉,下面是一个测试程序: 



#0001  #include  

#0002  #include  

#0003 

#0004  class ClassA 

#0005  { 

#0006  public: 

#0007  int m_data1; 

#0008  int m_data2; 

#0009  void func1() {   } 

#0010  void func2() {   } 

#0011  virtual void vfunc1() {     } 

#0012  virtual void vfunc2() {     } 

#0013  }; 

#0014 

#0015  class ClassB : public ClassA 

#0016  { 

#0017  public: 

#0018  int m_data3; 

#0019  void func2() {  } 

#0020  virtual void vfunc1() {   } 

#0021  }; 

#0022 

#0023  class ClassC : public ClassB 

#0024  { 



                                                                                                79 


…………………………………………………………Page 142……………………………………………………………

                  #0025  public: 

                  #0026  int m_data1; 

                  #0027  int m_data4; 

                  #0028  void func2() {  } 

                  #0029  virtual void vfunc1() {    } 

                  #0030  }; 

                  #0031 

                  #0032  void main() 

                  #0033  { 

                  #0034    cout 
返回目录 上一页 下一页 回到顶部 0 0
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!