C++虚继承的概念
2016-02-25 15:38
295 查看
C++中虚拟继承的概念
为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样不仅就解决了二义性问题,也节省了内存,避免了数据不一致的问题。
class派生类名:virtual继承方式 基类名
virtual是关键字,声明该基类为派生类的虚基类。
在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。
声明了虚基类之后,虚基类在进一步派生过程中始终和派生类一起,维护同一个基类子对象的拷贝。
C++虚拟继承
◇概念:
C++使用虚拟继承(VirtualInheritance),解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。
◇解决问题:
解决了二义性问题,也节省了内存,避免了数据不一致的问题。
◇同义词:
虚基类(把一个动词当成一个名词而已)
当在多条继承路径上有一个公共的基类,在这些路径中的某几条汇合处,这个公共的基类就会产生多个实例(或多个副本),若只想保存这个基类的一个实例,可以将这个公共基类说明为虚基类。
◇语法:
class派生类:virtual基类1,virtual基类2,...,virtual基类n
{
...//派生类成员声明
};
◇执行顺序
首先执行虚基类的构造函数,多个虚基类的构造函数按照被继承的顺序构造;
执行基类的构造函数,多个基类的构造函数按照被继承的顺序构造;
执行成员对象的构造函数,多个成员对象的构造函数按照申明的顺序构造;
执行派生类自己的构造函数;
析构以与构造相反的顺序执行;
mark
从虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中都要列出对虚基类构造函数的调用。但只有用于建立对象的最派生类的构造函数调用虚基类的构造函数,而该派生类的所有基类中列出的对虚基类的构造函数的调用在执行中被忽略,从而保证对虚基类子对象只初始化一次。
在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行。
◇因果:
多重继承->二义性->虚拟继承解决
◇二义性:
1: //-----------------------------------------------------
2://名称:blog_virtual_inherit.cpp
3://说明:C++虚拟继承学习演示
4://环境:VS2005
5://blog:pppboy.blog.163.com
6://----------------------------------------------------
7:#include"stdafx.h"
8:#include<iostream>
9:usingnamespacestd;
10:
11://Base
12:classBase
13:{
14:public:
15:Base(){cout<<"Basecalled..."<<endl;}
16:voidprint(){cout<<"Baseprint..."<<endl;}
17:private:
18:};
19:
20://Sub
21:classSub//定义一个类Sub
22:{
23:public:
24:Sub(){cout<<"Subcalled..."<<endl;}
25:voidprint(){cout<<"Subprint..."<<endl;}
26:private:
27:};
28:
29://Child
30:classChild:publicBase,publicSub//定义一个类Child分别继承自Base,Sub
31:{
32:public:
33:Child(){cout<<"Childcalled..."<<endl;}
34:private:
35:};
36:
37:intmain(intargc,char*argv[])
38:{
39:Childc;
40:
41://不能这样使用,会产生二意性,VC下errorC2385
42://c.print();
43:
44://只能这样使用
45:c.Base::print();
46:c.Sub::print();
47:
48:system("pause");
49:return0;
50:}
◇多重继承:
1://-----------------------------------------------------
2://名称:blog_virtual_inherit.cpp
3://说明:C++虚拟继承学习演示
4://环境:VS2005
5://blog:pppboy.blog.163.com
6://----------------------------------------------------
7:#include"stdafx.h"
8:#include<iostream>
9:usingnamespacestd;
10:
11:intgFlag=0;
12:
13:classBase
14:{
15:public:
16:Base(){cout<<"Basecalled:"<<gFlag++<<endl;}
17:voidprint(){cout<<"Baseprint"<<endl;}
18:};
19:
20:classMid1:publicBase
21:{
22:public:
23:Mid1(){cout<<"Mid1called"<<endl;}
24:private:
25:};
26:
27:classMid2:publicBase
28:{
29:public:
30:Mid2(){cout<<"Mid2called"<<endl;}
31:};
32:
33:classChild:publicMid1,publicMid2
34:{
35:public:
36:Child(){cout<<"Childcalled"<<endl;}
37:};
38:
39:intmain(intargc,char*argv[])
40:{
41:Childd;
42:
43://不能这样使用,会产生二意性
//d.print();
45:
46://只能这样使用
47:d.Mid1::print();
48:d.Mid2::print();
49:
50:system("pause");
51:return0;
52:}
53:
//output
Basecalled:0
Mid1called
Basecalled:1
Mid2called
Childcalled
Baseprint
Baseprint
◇虚拟继承
在派生类继承基类时,加上一个virtual关键词则为虚拟继承
1://-----------------------------------------------------
2://名称:blog_virtual_inherit.cpp
3://说明:C++虚拟继承学习演示
4://环境:VS2005
5://blog:pppboy.blog.163.com
6://----------------------------------------------------
7:#include"stdafx.h"
8:#include<iostream>
9:usingnamespacestd;
10:
11:intgFlag=0;
12:
13:classBase
14:{
15:public:
16:Base(){cout<<"Basecalled:"<<gFlag++<<endl;}
17:voidprint(){cout<<"Baseprint"<<endl;}
18:};
19:
20:classMid1:virtualpublicBase
21:{
22:public:
23:Mid1(){cout<<"Mid1called"<<endl;}
24:private:
25:};
26:
27:classMid2:virtualpublicBase
28:{
29:public:
30:Mid2(){cout<<"Mid2called"<<endl;}
31:};
32:
33:classChild:publicMid1,publicMid2
34:{
35:public:
36:Child(){cout<<"Childcalled"<<endl;}
37:};
38:
39:intmain(intargc,char*argv[])
40:{
41:Childd;
42:
43://这里可以这样使用
44:d.print();
45:
46://也可以这样使用
47:d.Mid1::print();
48:d.Mid2::print();
49:
50:system("pause");
51:return0;
52:}
53:
//output
1:Basecalled:0
2:Mid1called
3:Mid2called
4:Childcalled
5:Baseprint
6:Baseprint
7:Baseprint
8:请按任意键继续...
◇通过输出的比较
1.在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。
2.声明了虚基类之后,虚基类在进一步派生过程中始终和派生类一起,维护同一个基类子对象的拷贝。
3.观察类构造函数的构造顺序,拷贝也只有一份。
◇与虚函数关系
虚拟继承与虚函数有一定相似的地方,但他们之间是绝对没有任何联系的。
再想一次:虚拟继承,虚基类,虚函数。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性