C++多重继承与虚继承分析
本文以实例形式较为全面的讲述了C++的多重继承与虚继承,是大家深入学习C++面向对象程序设计所必须要掌握的知识点,具体内容如下:
一、多重继承
我们知道,在单继承中,派生类的对象中包含了基类部分 和 派生类自定义部分。同样的,在多重继承(multiple inheritance)关系中,派生类的对象包含了每个基类的子对象和自定义成员的子对象。下面是一个多重继承关系图:
class A{ /* */ }; class B{ /* */ }; class C : public A { /* */ }; class D : public B, public C { /* */ };
C继承了A,派生类D又继承了B和C,如图所示,一个D对象中含有一个B部分、一个C部分(其中又含有一个A部分)以及在D中声明的非静态数据成员:
构造与析构:
构造一个派生类对象将首先构造它的所有基类子对象,其中基类的构造顺序与派生列表中基类的出现顺序保持一致,即B –> A –> C –> D。
销毁一个派生类对象的顺序正好与其创建的顺序相反,即析构函数的调用顺序正好与构造函数相反,即D –> C –> A –> B。注意派生类的析构函数只负责清除派生类本身分配的资源(析构函数体),派生类的成员及基类都是自动销毁的(隐式析构阶段)。
类型转换:
在多重继承的情况下,可以令某个可访问基类的指针或引用直接指向一个派生类对象。编译器不会在派生类向基类的几种转换中进行比较和选择,在它看来转换到任意一种基类都一样好。
二、虚继承
尽管在派生列表中不允许同一个基类出现两次,但实际上派生类可以多次继承同一个类。
派生类通常会含有继承链上每个类对应的子部分。在上面的两种情况中,class D都间接地继承了class A两次,那么意味着class D中包含了class A的两份拷贝。所以在一个class D的对象中将含有2组class A的成员,此时若不加前缀限定符直接使用某个成员将引发“二义性”错误:
class A{ public: A():str("name"){}; string str; void print(){cout << str << endl;}; }; class B : public A { }; class C : public A { }; class D : public B, public C { }; int main(){ D d; d.str = "songlee"; // 错误:对成员‘str'的请求有歧义 d.print(); // 错误:对成员‘print'的请求有歧义 return 0; }
当然你可以使用作用域 d.B::str="songlee"; 和 d.B::print(); 来规避“二义性”错误,但这并没有从根本上解决问题。
为了解决上述问题,C++提供了虚继承(virtual inheritance)的机制。虚继承的目的是令某个类作出声明,承诺愿意共享它的基类。其中,共享的基类子对象称为虚基类。在这种机制下,不论虚基类在继承体系中出现多少次,在派生类中都只包含唯一一个共享的虚基类子对象。我们指定虚基类的方式是在派生列表中添加关键字virtual:
class A{ public: A():str("name"){}; string str; void print(){cout << str << endl;}; }; class B : virtual public A { }; // 虚继承,A为虚基类 class C : virtual public A { }; // 关键字public和virtual的顺序随意 class D : public B, public C { }; int main(){ D d; d.str = "songlee"; // 正确 d.print(); // 正确 return 0; }
通过在派生列表中添加virtual(关键字public和virtual的顺序随意)指定A为虚基类,B和C将共享A的同一份实例,这样在D的对象中也将只有A的唯一一份实例,所以A的成员可以被直接访问,并且不会产生二义性。
虚继承最典型的应用是iostream继承于istream和ostream,而istream和ostream虚继承于ios:
class istream : virtual public ios { /* */ }; class ostream : virtual public ios { /* */ }; class iostream : public istream, public ostream { /* */ };
此外还需要注意:
1.支持向基类的常规类型转换。也就是说即使基类是虚基类,也能通过基类的指针或引用操作派生类的对象。
2.虚继承只是解决了一个派生类对象中存在同一个基类的多份拷贝的问题,并没有解决多个基类存在同名成员的二义性问题。
3.在虚继承中,虚基类是由最低层的派生类负责初始化的。如上例中,当创建一个D对象时,D位于派生的最低层并由它负责初始化共享的A基类部分。
4.含有虚基类的对象的构造顺序与一般的多重继承的构造顺序稍有区别:先初始化虚基类子对象(最低层派生类负责),然后按派生列表中的顺序依次对直接基类(非虚)进行初始化。
5.析构的顺序与构造的顺序正好相反。
上一篇:C++实现一维向量旋转算法
栏 目:C语言
下一篇:C++命名空间实例解析
本文标题:C++多重继承与虚继承分析
本文地址:https://www.xiuzhanwang.com/a1/Cyuyan/3502.html
您可能感兴趣的文章
- 04-02c语言没有round函数 round c语言
- 01-10深入理解C++中常见的关键字含义
- 01-10使用C++实现全排列算法的方法详解
- 01-10c++中inline的用法分析
- 01-10用C++实现DBSCAN聚类算法
- 01-10全排列算法的非递归实现与递归实现的方法(C++)
- 01-10C++大数模板(推荐)
- 01-10浅谈C/C++中的static与extern关键字的使用详解
- 01-10深入C/C++浮点数在内存中的存储方式详解
- 01-10深入理解C/C++混合编程
阅读排行
本栏相关
- 04-02c语言函数调用后清空内存 c语言调用
- 04-02func函数+在C语言 func函数在c语言中
- 04-02c语言的正则匹配函数 c语言正则表达
- 04-02c语言用函数写分段 用c语言表示分段
- 04-02c语言中对数函数的表达式 c语言中对
- 04-02c语言编写函数冒泡排序 c语言冒泡排
- 04-02c语言没有round函数 round c语言
- 04-02c语言分段函数怎么求 用c语言求分段
- 04-02C语言中怎么打出三角函数 c语言中怎
- 04-02c语言调用函数求fibo C语言调用函数求
随机阅读
- 04-02jquery与jsp,用jquery
- 01-10C#中split用法实例总结
- 01-10SublimeText编译C开发环境设置
- 08-05DEDE织梦data目录下的sessions文件夹有什
- 01-10delphi制作wav文件的方法
- 01-11Mac OSX 打开原生自带读写NTFS功能(图文
- 08-05dedecms(织梦)副栏目数量限制代码修改
- 01-10使用C语言求解扑克牌的顺子及n个骰子
- 08-05织梦dedecms什么时候用栏目交叉功能?
- 01-11ajax实现页面的局部加载