zoukankan      html  css  js  c++  java
  • 十个例子让你完全搞懂 C++ 的虚函数(不懂来找我)

     


    我的公众号 「Linux云计算网络」(id: cloud_dev),号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,分享的内容包括但不限于 Linux、网络、云计算虚拟化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++编程技术等内容,欢迎大家关注。


    Author: bakari  Date: 2012.4.8

    装载引用请注明出处:http://www.cnblogs.com/bakari/archive/2012/08/12/2635369.html   谢谢!

    虚函数是C++中非常重要的一个概念,它最大的好处是能够触发动态绑定。C++中的函数默认不使用动态绑定,要触发动态绑定,必须满足 两个条件:

    第一,只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不进行动态绑定;

    第二,必须通过基类类型的指针或引用进行函数的调用。具体理解指针或引用在使用继承层次中某一类型的对象时会发生什么,本文不展开讨论,

    这两天主要研习了虚函数的具体应用这一块,而它的应用又非常广泛,学MFC的应该能够感受到它的强大,要说是总结也不一定能够总结全,本人目前也处在studying中,所以用10个具体的例子来说明。例子是从难 到易,看到的朋友如果懂前面的可以不用看后面的。每一个例子就是一个类,通过类在内存中的布局来形象地分析虚函数究竟是如何运作的。图表示可能抽象一点,一般带有V开头的表示一个虚函数表,如果是学过编译原理这门课就很容易看懂,没学过的只要懂虚函数的一些机制,耐着性子也是没问题的。每个图示都配有相应的代码。可以对照着代码来看。

    1、  虚函数继承的复杂例子

    2、  菱形继承无虚拟继承的情况

    3、  虚拟继承的简单情况

    4、  单一普通继承(无虚函数)

    5、  单一继承(含虚函数)(虚函数表只有一个)

    6、  多重继承(不含虚函数)

    7、  多重继承(一个含虚函数,一个不含虚函数)

    8、  多重继承(两个都含有虚函数)

    9、  纯虚汗继承

    10、 private 的虚函数

     

    1、虚函数继承的复杂例子,见下图:

    见图:左边是这个类的内存布局,右边是继承图示。 farther类和Uncle类都是虚拟继承,其内部也都有偏移表,但我觉得这两个表只是内部隐藏的,不在Son的内存布局中表示出来,本题Son的内存只有32个字节,如果表示出来就不止32个了,但是下面这个地方在内存中显示是00 00 00 00,我猜想是不是GrandFather的偏移地址。

    VbtSon(Father)

    Farther~Num

    VbtSon(Uncle)

    Uncle~Num

    Son~Num

    Offset(这个地方??)

    Vftable(GrandFather)

    GrandFather~Num

                                            

     例子代码:

     1 class GrandFather
     2 {
     3 public:
     4     GrandFather():i_G(5){cout<<"GrandFather() is called!"<<endl;}
     5     virtual ~GrandFather(){cout<<"~GrandFather() is called!"<<endl;}
     6 public:
     7     virtual void Test(){cout<<"GrandFather::Test() is called!"<<endl;}
     8 private:
     9     int i_G;
    10 };
    11 
    12 class Father: virtual public GrandFather             //虚拟继承
    13 {
    14 public:
    15     Father():i_F(7){cout<<"Father() is called!"<<endl;};
    16     virtual ~Father(){cout<<"~Father() is called!"<<endl;}
    17 public:
    18     virtual void Test(){cout<<"Father::Test() is called!"<<endl;}
    19 private:
    20     int i_F;
    21 };
    22 
    23 class Uncle: virtual public GrandFather                          //虚拟继承
    24 {
    25 public:
    26     Uncle():i_U(3){cout<<"Uncle is called!"<<endl;}
    27     virtual ~Uncle(){cout<<"~Uncle  is called!"<<endl;}
    28 public:
    29     virtual void Test(){cout<<"Uncle ::Test() is called!"<<endl;}
    30 private:
    31     int i_U;
    32 };
    33 
    34 class Son:public Father,public Uncle                    
    35 {
    36 public:
    37     Son():i_S(9){cout<<"Son is called!"<<endl;};
    38     virtual ~Son(){cout<<"~Son  is called!"<<endl;}
    39 public:
    40     virtual void Test(){cout<<"Son ::Test() is called!"<<endl;}
    41 private:
    42     int i_S;
    43 };
    44 
    45 int main(void)
    46 {
    47     Son p;
    48     p.Test();
    49     cout<<sizeof(Son)<<endl;
    50     cout<<sizeof(Father)<<endl;
    51     cout<<sizeof(GrandFather)<<endl;
    52     return 0;
    53 }

    运行情况:

    2、  菱形继承无虚拟继承的情况

    VPTr1(Father)

    GrandFarther~Num

    Father~Num

    VPtr(Uncle)

    GrandFarther~Num

    Uncle~Num

    Son~Num

                             

     1 #include<iostream>
     2 using namespace std;
     3 class GrandFather
     4 {
     5 public:
     6     GrandFather():i_G(5){cout<<"GrandFather() is called!"<<endl;}
     7     virtual ~GrandFather(){cout<<"~GrandFather() is called!"<<endl;}
     8 public:
     9     virtual void Test(){cout<<"GrandFather::Test() is called!"<<endl;}
    10 private:
    11     int i_G;
    12 };
    13 class Father:   public GrandFather          //无虚拟继承
    14 {
    15 public:
    16     Father():i_F(7){cout<<"Father() is called!"<<endl;};
    17     virtual ~Father(){cout<<"~Father() is called!"<<endl;}
    18 public:
    19     virtual void Test(){cout<<"Father::Test() is called!"<<endl;}
    20 private:
    21     int i_F;
    22 };
    23 
    24 class Uncle:   public GrandFather             //无虚拟继承
    25 {
    26 public:
    27     Uncle():i_U(3){cout<<"Uncle is called!"<<endl;}
    28     virtual ~Uncle(){cout<<"~Uncle  is called!"<<endl;}
    29 public:
    30     virtual void Test(){cout<<"Uncle ::Test() is called!"<<endl;}
    31 private:
    32     int i_U;
    33 };
    34 
    35 class Son:public Father,public Uncle
    36 {
    37 public:
    38     Son():i_S(9){cout<<"Son is called!"<<endl;};
    39     virtual ~Son(){cout<<"~Son  is called!"<<endl;}
    40 public:
    41     virtual void Test(){cout<<"Son ::Test() is called!"<<endl;}
    42 private:
    43     int i_S;
    44 };
    45 
    46 int main(void)
    47 {
    48     Son p;
    49     p.Test();
    50     cout<<sizeof(Son)<<endl;
    51     cout<<sizeof(Father)<<endl;
    52     cout<<sizeof(GrandFather)<<endl;
    53     
    54     return 0;
    55 }

    运行情况:

                

    3、  虚拟继承的简单情况 见下图:

    VPTrD(A)              4      

    Offset(A)              4

    A~number             4

    D~number             4

    VPtr(Base)            4

    Base~Number  

     

    12 + 3cc + 4 = 40

                                    

     1 class Base
     2 {
     3 public:
     4     Base(){strcpy_s(ch_rc,"abcdefg");}                  //初始化Base()::im
     5 public:
     6    virtual void Read(){cout<<"Base::Read()is called!"<<endl;}
     7 private:
     8     char ch_rc[12];
     9     bool ir;
    10     int  im;                   
    11 };
    12 class A: virtual public Base     //虚拟继承
    13 {
    14 public:
    15     A():im_A(5){}                        //初始化A()::im_A
    16 public:
    17     virtual void Read(){cout<<"A::Read()is called!"<<endl;}
    18 private:
    19     int im_A;
    20 };
    21 class D:public A
    22 {
    23 public:
    24     D():im_D(3){}          
    25 public:
    26     virtual void Read(){cout<<"D::Read()is called!"<<endl;}
    27 private:
    28     int im_D;
    29 };
    30 int _tmain(int argc, _TCHAR* argv[])
    31 {
    32     D obj;
    33     cout<<sizeof(D)<<endl;
    34     return 0;
    35 }

    运行情况:

    4、单一普通继承(无虚函数)(这个没什么好说的)

                                                                                                          内存布局

    Father~Number

    Son~Number

     1 class Father
     2 {
     3 public:
     4     Father(){cout<<"Father() is called!"<<endl;}
     5     void TestF(const int &m){
     6         i_B=m;
     7         cout<<"Father::TestF() is called!"<<endl;
     8     }
     9     void Test(){cout<<"Base::Test() is called!"<<endl;}
    10     ~Father(){cout<<"~Father() is called!"<<endl;}
    11 private:
    12     int i_B;
    13 };
    14  
    15 class Son:public Father
    16 {
    17 public:
    18     Son():i_A(5){cout<<"Son() is called!"<<endl;}
    19      void Test(){cout<<"Son::Test() is called!"<<endl;}
    20      ~Son(){cout<<"~Son() is called!"<<endl;}
    21 private:
    22     int i_A;
    23 };
    24 int main(int argc,char *argv[])
    25 {
    26     Father *p=new Son;
    27     //Father *p=NULL;
    28     p->Test();
    29     delete p;
    30     p=NULL;
    31     cout<<sizeof(Son)<<endl;
    32     return 0;
    33 }

    5、单一继承(含虚函数)(虚函数表只有一个)见图:

    VPTr(father)

    Father~number

    Son~number

    Child~number

                            

     1 #include<iostream>
     2 using namespace std;
     3 class Father
     4 {
     5 public:
     6     Father(){cout<<"Father() is called!"<<endl;}
     7     virtual  void Test(){cout<<"Base::Test() is called!"<<endl;}
     8     virtual ~Father(){cout<<"~Father() is called!"<<endl;}
     9 private:
    10     int i_B;
    11 };
    12  
    13 class Son:public Father
    14 {
    15 public:
    16     Son():i_A(5){cout<<"Son() is called!"<<endl;}
    17      void Test(){cout<<"Son::Test() is called!"<<endl;}
    18      ~Son(){cout<<"~Son() is called!"<<endl;}
    19 private:
    20     int i_A;
    21 };
    22 int main(int argc,char *argv[])
    23 {
    24     Father *p=new Son;
    25     //Father *p=NULL;
    26     p->Test();
    27     delete p;
    28     p=NULL;
    29     cout<<sizeof(Son)<<endl;
    30     return 0;
    31 }

    运行情况:

    6、多重继承(不含虚函数)(这个也没什么好说的)

    直接看代码:

     1 #include<iostream>
     2 using namespace std;
     3 class Father
     4 {
     5 public:
     6     Father():i_B(6){cout<<"Father() is called!"<<endl;}
     7      void TestF(const int &m){
     8         i_B=m;
     9         cout<<"Father::TestF() is called!"<<endl;
    10     }
    11       void Test(){cout<<"Father::Test() is called!"<<endl;}
    12      ~Father(){cout<<"~Father() is called!"<<endl;}
    13 private:
    14     int i_B;
    15 };
    16 class Son
    17 {
    18 public:
    19     Son():i_A(5){cout<<"Son() is called!"<<endl;}
    20       void Test(){cout<<"Son::Test() is called!"<<endl;}
    21       ~Son(){cout<<"~Son() is called!"<<endl;}
    22 private:
    23     int i_A;
    24 };
    25 
    26 class Child:public  Father,public Son      //多重继承
    27 {
    28 public:
    29     Child():i_C(5){cout<<"Child() is called!"<<endl;}
    30      void Test(){cout<<"Child::Test() is called!"<<endl;}
    31      ~Child(){cout<<"~Child() is called!"<<endl;}
    32 private:
    33     int i_C;
    34 };
    35 int main(int argc,char *argv[])
    36 {
    37     Father *p=new Child;
    38     //Father *p=NULL;
    39     p->Test();
    40     cout<<sizeof(Son)<<endl;
    41     cout<<sizeof(Child)<<endl;
    42     return 0;
    43 }

    7、多重继承(一个含虚函数,一个不含虚函数)(类似单一继承)

    VPTr(father)

    Father~number

    Son~number

    Child~number

                             

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class Father
     5 {
     6 public:
     7     Father():i_B(6){cout<<"Father() is called!"<<endl;}
     8     virtual  void TestF(const int &m){
     9         i_B=m;
    10         cout<<"Father::TestF() is called!"<<endl;
    11     }
    12       virtual void Test(){cout<<"Father::Test() is called!"<<endl;}
    13      virtual  ~Father(){cout<<"~Father() is called!"<<endl;}
    14 private:
    15     int i_B;
    16 };
    17  
    18 class Son
    19 {
    20 public:
    21     Son():i_A(5){cout<<"Son() is called!"<<endl;}
    22       void Test(){cout<<"Son::Test() is called!"<<endl;}
    23       ~Son(){cout<<"~Son() is called!"<<endl;}
    24 private:
    25     int i_A;
    26 };
    27 
    28 class Child:public  Father,public Son
    29 {
    30 public:
    31     Child():i_C(5){cout<<"Child() is called!"<<endl;}
    32      void Test(){cout<<"Child::Test() is called!"<<endl;}
    33      ~Child(){cout<<"~Child() is called!"<<endl;}
    34 private:
    35     int i_C;
    36 };
    37 int main(int argc,char *argv[])
    38 {
    39     Father *p=new Child;
    40     //Father *p=NULL;
    41     p->Test();
    42     cout<<sizeof(Son)<<endl;
    43     cout<<sizeof(Child)<<endl;
    44     return 0;
    45 }

    运行情况:

    8、多重继承(两个都含有虚函数)

    VPTr(father)

    Father~number

    VPTr(Son)

    Son~number Child~number

     

    20个字节

                             

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class Father
     5 {
     6 public:
     7     Father():i_B(6){cout<<"Father() is called!"<<endl;}
     8     virtual  void TestF(const int &m){
     9         i_B=m;
    10         cout<<"Father::TestF() is called!"<<endl;
    11     }
    12       virtual void Test(){cout<<"Father::Test() is called!"<<endl;}
    13      virtual  ~Father(){cout<<"~Father() is called!"<<endl;}
    14 private:
    15     int i_B;
    16 };
    17 class Son
    18 {
    19 public:
    20      Son():i_A(5){cout<<"Son() is called!"<<endl;}
    21       virtual void Test(){cout<<"Son::Test() is called!"<<endl;}
    22       virtual ~Son(){cout<<"~Son() is called!"<<endl;}
    23 private:
    24     int i_A;
    25 };
    26 
    27 class Child:public  Father,public Son
    28 {
    29 public:
    30     Child():i_C(7){cout<<"Child() is called!"<<endl;}
    31      void Test(){cout<<"Child::Test() is called!"<<endl;}
    32      ~Child(){cout<<"~Child() is called!"<<endl;}
    33 private:
    34     int i_C;
    35 };
    36 int main(int argc,char *argv[])
    37 {
    38     //Father *p=new Child;
    39     Child p;
    40     //Father *p=NULL;
    41     p.Test();
    42     cout<<sizeof(Son)<<endl;
    43     cout<<sizeof(Child)<<endl;
    44     return 0;
    45 }

    运行情况:

    9、纯虚汗继承

    (只在父类中申明,并在子类中实现申明的函数才可以用)

    内存分配与前面只含虚函数的情况类似

     1 #include<iostream>
     2 using namespace std;
     3 class A
     4 {
     5 public:
     6     A():i_A(5){cout<<"A() is called!"<<endl;}
     7 public:
     8 virtual void Test()= 0; //prue virtual function
     9 virtual void Base() {cout<<"this is farther class"<<endl;}
    10 private:
    11     int i_A;
    12 };
    13 
    14 class B:public A
    15 {
    16 public:
    17     B():i_B(9){}
    18 public:
    19     void Test() { cout<<" this is SubVirtual!"<<endl;}                          //必须在子类中实现该函数才可以用
    20 void Base() { 
    21 cout<<"this is subclass Base"<<endl;
    22 }
    23 private:
    24     int i_B;
    25 };
    26 
    27 int  main(void)
    28 {
    29     A* p = new B; //multstate pointer
    30     p->Test();
    31     p->Base();
    32     cout<<sizeof(B)<<endl;
    33     return 0 ;
    34 }

    10、private 的虚函数

     1 #include<iostream>
     2 using namespace std;
     3 
     4 class A
     5 {
     6 public:
     7 virtual void Test() { func();}
     8 private:
     9     int i_A;
    10     virtual void func() {cout<<"A::func () is Called!"<<endl; }
    11 };
    12 class B: public A
    13 {
    14 private:
    15 //虽然func()在A类中是private的,但是仍然可以出现在派生类中,并仍然可以与public或者protected的虚函数一样产生多态的效果。
    16     virtual void func() { cout<<"B::func() is Called!"<<endl;} private:
    17     int i_B;
    18 };
    19 
    20 int main(void)
    21 {
    22     //A *p=new B;
    23     A p;
    24     //B p;
    25     //p->func();
    26     p.Test();
    27     cout<<sizeof(B)<<endl;
    28     return 0;
    29 }

    运行情况:

    OK,做这个东西很辛苦,没办法,搞技术的就得这样。

    写这些程序然后进行测试是很轻松的一件事,然而要把这些东西以文字的方式整理出来,的确不是一件容易的事。所以,就有很多IT高手,技术流,Coding很厉害,但对于文字的东西就不是很感冒,不过没关系,每个人有每个人的不同的需求,我是喜欢没事总喜欢写写的人,我想写的越多思路就不会堵塞

    祝愿每一个朋友学习愉快,技术成精!

    每一个人的辛苦都是值得肯定的,装载引用请注明出处:http://www.cnblogs.com/bakari/archive/2012/08/12/2635369.html  谢谢!


    我的公众号 「Linux云计算网络」(id: cloud_dev),号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,分享的内容包括但不限于 Linux、网络、云计算虚拟化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++编程技术等内容,欢迎大家关注。

    stay hungry stay foolish ----jobs 希望多多烧香!
  • 相关阅读:
    文件内容排名算法,输入排名函数,返回排名后的文件名
    线段树做大数据排序
    给字符排序-基类排序二分查找-JavaScript
    后缀数组、名次数组-JavaScript
    二分查找法、二分去重排序法,返回最接近的位置和实际位置
    用四叉树对图像分类,获取tag和key
    Linux显示所在Git分支
    Linux中设置Git显示颜色
    屏蔽网页广告
    tf.add_to_collection,tf.get_collection简介
  • 原文地址:https://www.cnblogs.com/bakari/p/2635369.html
Copyright © 2011-2022 走看看