从零开始学C++之继承(三):多重继承、虚继承与虚基类
来源:互联网 发布:JAVA在数据库创建表 编辑:程序博客网 时间:2024/05/16 09:57
一、多重继承
单重继承——一个派生类最多只能有一个基类
多重继承——一个派生类可以有多个基类
class 类名: 继承方式 基类1,继承方式 基类2,…. {….};
派生类同时继承多个基类的成员,更好的软件重用
可能会有大量的二义性,多个基类中可能包含同名变量或函数
多重继承中解决访问歧义的方法:
基类名::数据成员名(或成员函数(参数表))
明确指明要访问定义于哪个基类中的成员
#include <iostream>using namespace std;class Bed{public: Bed(int weight) : weight_(weight) { } void Sleep() { cout << "Sleep ..." << endl; } int weight_;};class Sofa{public: Sofa(int weight) : weight_(weight) { } void WatchTV() { cout << "Watch TV ..." << endl; } int weight_;};class SofaBed : public Bed, public Sofa{public: SofaBed() : Bed(0), Sofa(0) { FoldIn(); } void FoldOut() { cout << "FoldOut ..." << endl; } void FoldIn() { cout << "FoldIn ..." << endl; }};int main(void){ SofaBed sofaBed; //sofaBed.weight_ = 10; error //sofaBed.weight_ = 20; error sofaBed.Bed::weight_ = 10; sofaBed.Sofa::weight_ = 20; sofaBed.WatchTV(); sofaBed.FoldOut(); sofaBed.Sleep(); return 0;}
不能直接写 sofaBed.weight_ = 10; 因为sofaBed 继承了Sofa 和 Bed ,实际上有weigh_的两份拷贝,这样指向不明。只能通过
sofaBed.Bed::weight_ = 10; 访问,但实际上一个sofaBed理应只有一个weight_,下面通过虚基类和虚继承可以解决这个问题。
二、虚继承与虚基类
当派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中的成员时,将产生二义性,可以采用虚基类来解决。
虚基类的引入
用于有共同基类的场合
声明
以virtual修饰说明基类 例:class B1:virtual public BB
作用
主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题.
为最远的派生类提供唯一的基类成员,而不重复产生多次拷贝
#include <iostream>using namespace std;class Furniture{public: Furniture(int weight) : weight_(weight) { cout << "Furniture ..." << endl; } ~Furniture() { cout << "~Furniture ..." << endl; } int weight_;};class Bed : virtual public Furniture{public: Bed(int weight) : Furniture(weight) { cout << "Bed ..." << endl; } ~Bed() { cout << "~Bed ..." << endl; } void Sleep() { cout << "Sleep ..." << endl; }};class Sofa : virtual public Furniture{public: Sofa(int weight) : Furniture(weight) { cout << "Sofa ..." << endl; } ~Sofa() { cout << "~Sofa ..." << endl; } void WatchTV() { cout << "Watch TV ..." << endl; }};class SofaBed : public Bed, public Sofa{public: SofaBed(int weight) : Bed(weight), Sofa(weight), Furniture(weight) { cout << "SofaBed ..." << endl; FoldIn(); } ~SofaBed() { cout << "~SofaBed ..." << endl; } void FoldOut() { cout << "FoldOut ..." << endl; } void FoldIn() { cout << "FoldIn ..." << endl; }};int main(void){ SofaBed sofaBed(5); sofaBed.weight_ = 10; sofaBed.WatchTV(); sofaBed.FoldOut(); sofaBed.Sleep(); return 0;}
此时只有一份weigh_,不存在访问歧义的问题。
从输出可以总结出:
1、虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。
2、在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出对虚基类的构造函数的调用。如果未列出,则表示调用该虚基类的默认构造函数。
3、在建立对象时,只有最远派生类的构造函数调用虚基类的构造函数,该派生类的其他基类对虚基类构造函数的调用被忽略。
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范
- 从零开始学C++之继承(三):多重继承、虚继承与虚基类
- 从零开始学C++之继承(三):多重继承、虚继承与虚基类
- 从零开始学C++之继承(三):多重继承、虚继承与虚基类
- 多重继承与虚继承
- 多重继承与虚继承
- 多重继承与虚继承
- 多重继承与虚继承
- 多重继承与虚继承
- 多重继承与虚继承
- 多重继承与虚继承
- 11 继承,多重继承与虚继承
- 从零开始学C++之异常(三):异常与继承、异常与指针、异常规格说明
- 从零开始学C++之异常(三):异常与继承、异常与指针、异常规格说明
- 从零开始学C++之异常(三):异常与继承、异常与指针、异常规格说明
- 从零开始学_JavaScript_系列(65)——class的继承(2)super、extends与多重继承
- (C++)多重继承
- 从零开始学C++之继承(二):继承与构造函数、派生类到基类的转换
- 从零开始学C++之继承(二):继承与构造函数、派生类到基类的转换
- 【Python】Web服务器网关接口(WSGI)的简介及wsgiref模块
- 欧拉工程第27题 找出为连续数字产生最多质数的二次公式
- 嵌入式系统 Boot Loader 技术内幕
- 1619-7 张良 十月二十五号总结 [连续第二十五天]
- 359_EditText文本显示隐藏
- 从零开始学C++之继承(三):多重继承、虚继承与虚基类
- Codeforces 731F Video cards 筛法
- 第001节 java中String、StringBuffer、StringBuilder的区别
- C++格式化输出
- 浅析Java接口与抽象类的区别
- 360_FragmentStatePagerAdapter
- web.xml配置详解
- 清空数据表(实则更改状态)
- BZOJ2815 ZJOI2012 灾难 构造+LCA+树形dp+拓扑排序