开发者社区> 伍工> 正文

十个例子让你完全搞懂 C++ 的虚函数(不懂来找我)

简介: Author: bakari  Date: 2012.4.8 装载引用请注明出处:http://www.cnblogs.com/bakari/archive/2012/08/12/2635369.html   谢谢! 虚函数是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  谢谢!

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
转发参数包的例子
16.58 为你的StrVec类添加emplace_back函数。 StrVec.h(注意,函数模板和模板成员函数的定义和声明要放在一起,通常都放在头文件中) #ifndef STRVEC_H #define STRVEC_H #include #include #include ...
619 0
客户端自动升级的一个代码例子【C/S】
经常看到有问客户端自动更新问题,把一个以前看到的常用的方法整理了一下,放在网上供大家使用。 详细代码下载地址 http://cid-56b433ad3d1871e3.office.live.com/self.
647 0
开发指南—函数—拆分函数—RANGE_HASH
本文将介绍RANGE_HASH函数的使用方式。
86 0
32、C++ Primer 4th 笔记,多重继承与虚函数
1、只有在定义之后,类才可以用作多重继承的基类。按照基类构造函数在派生列表中的出现次序调用。 2、多重继承中,派生类的指针或引用可以转换为任意基类的指针或引用。 3、当一个类继承于多个基类的时候,那些基类之间没有隐含的关系,不允许使用一个基类的指针访问其它基类的成员。
730 0
linux下练习 c++ 栈中使用类模版例子
//栈中使用类模版例子 #include #include using namespace std; //typedef char T; template//可以有默认值,有默认值的参数靠右 //如果成员函数在类外写,那么每个...
655 0
使用标准库函数对象的例子
14.42 使用标准库函数对象及适配器定义一条表达式,令其 1 统计打于1024的值有多少个。 2 找到第一个不等于pooh的字符串 3 将所有的值乘以2 14.43 使用标准库函数对象判断一个给定的int值是否能被int容器中的所有元素整除 #include #include #...
545 0
+关注
伍工
公众号【5分钟学网络】和【5分钟学Go】的作者,力求用最简洁的语言讲懂最复杂的逻辑!欢迎你的关注!
136
文章
1
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载