【ThinkingInC++】75、多重继承
第九章 多重继承
9.2 接口继承
Intertfacees.cpp
/**
* 书本:【ThinkingInC++】
* 功能:接口继承Interfaces.cpp
* 时间:2014年10月28日20:06:31
* 作者:cutter_point
*/
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class Printable //抽象类
{
public:
virtual ~Printable() {} //虚函数
virtual void print(ostream&) const=0; //纯虚函数
};
class Intable
{
public:
virtual ~Intable() {}
virtual int toInt() const=0;
};
class Stringable
{
public:
virtual ~Stringable() {}
virtual string toString() const=0;
};
class Able : public Printable, publicIntable, public Stringable
{
int myData;
public:
Able(int x) { myData=x; }
void print(ostream& os) const { os<<myData; }
int toInt() const { return myData; }
string toString() const
{
ostringstream os;
os<<myData;
return os.str();
}
};
void testPrintable(const Printable& p)
{
p.print(cout);
cout<<endl;
}
void testIntable(const Intable& n)
{
cout<<n.toInt()+1<<endl;
}
void testStringable(const Stringable&s)
{
cout<<s.toString()+"th"<<endl;
}
int main()
{
Able a(7);
testPrintable(a);
testIntable(a);
testStringable(a);
return 0;
}
9.5 虚基类
虚拟继承的机制。
实际上造成上边的二义性的根本原因是在这样的继承的特殊模式下。A这个父类分别伴随B和C产生了两个拷贝。在调用拷贝中的方法时产生了矛盾。究竟是调用哪一个拷贝中的print()呢?于是,全部人都会想,要是仅仅有一个拷贝就好了,就没有矛盾了。虚拟继承就提供了这样的机制,按上面的样例,仅仅需改动B和C对A的继承方式,即加一个keyword
virtual
class B: virtual public A
{
public:
B(){cout << "B called"<< endl;}
private:
};
class C: virtual public A
{
public:
C(){cout << "C called"<< endl;}
private:
};
这样就相当于说。在没有A类的拷贝时就构造一个,假设已经有了,就用已经有的那一个,这样一来,拷贝仅仅有一份了。二义性消除了。
static_cast 和 dynamic_cast
http://www.cnblogs.com/chio/archive/2007/07/18/822389.html
dynamic_cast主要用于类层次间的上行转换和下行转换。还能够用于类之间的交叉转换。
在类层次间进行上行转换时。dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
子对象的初始化顺序遵循例如以下规则:
1) 全部虚基类子对象,依照他们在类定义中出现的位置,重上到下、从左到右初始化
2) 然后非虚基类按通常顺序初始化
3) 全部的成员对象按声明的顺序初始化
4) 完整的对象的构造函数运行
前面讲过,为了初始化基类的子对象。派生类的构造函数要调用基类的构造函数。
对于虚基类来讲,因为派生类的对象中仅仅有一个虚基类子对象。为保证虚基类子对象仅仅被初始化一次,这个虚基类构造函数必须仅仅被调用一次。
http://blog.csdn.net/maojudong/article/details/8169240
假设类继承中包含多个虚基类的实例。基类仅仅被初始化一次。
|
1、假设类里面有成员类,成员类的构造函数优先被调用。 2、创建派生类的对象。基类的构造函数函数优先被调用(也优先于派生类里的成员类); 3、 基类构造函数假设有多个基类则构造函数的调用顺序是某类在类派生表中出现的 4、成员类对象构造函数假设有多个成员类对象则构造函数的调用顺序是对象在类中 5、派生类构造函数 (基类设计者的责任是提供一组适当的基类构造函数) |
VirtInit.cpp
//关于虚基类的初始化问题
/**
* 书本:【ThinkingInC++】
* 功能:关于虚基类的初始化问题
* 时间:2014年10月28日20:07:25
* 作者:cutter_point
*/ #include <iostream>
#include <string> using namespace std; class M
{
public:
M(const string& s) { cout<<"M "<<s<<endl; } //每个类都有嵌入的M类型成员
}; class A
{
M m; //这里是一个类的组合
public:
A(const string& s) : m("in A")
{
cout<<"A "<<s<<endl; //跟踪类A的初始化
}
virtual ~A() { cout<<"析构A"<<endl; } //这是一个虚基类
}; class B
{
M m; //这里是一个类的组合
public:
B(const string& s) : m("in B")
{
cout<<"B "<<s<<endl; //跟踪类A的初始化
}
virtual ~B() { cout<<"析构B"<<endl; } //这是一个虚基类
}; class C
{
M m; //这里是一个类的组合
public:
C(const string& s) : m("in C")
{
cout<<"C "<<s<<endl; //跟踪类A的初始化
}
virtual ~C() { cout<<"析构C"<<endl; } //这是一个虚基类
}; class D
{
M m; //这里是一个类的组合
public:
D(const string& s) : m("in D")
{
cout<<"D "<<s<<endl; //跟踪类A的初始化
}
virtual ~D() { cout<<"析构D"<<endl; } //这是一个虚基类
}; class F : virtual public B, virtual public C, public D //虚继承
{
M m;
public:
F(const string& s) : B("from F"), C("from F"), D("from F"), m("in F")
{
cout<<"F "<<s<<endl;
}
}; //開始多重继承
class E : public A, virtual public B, virtual public C //虚继承
{
M m;
public:
E(const string& s) : A("from E"), B("from E"), C("from E"), m("in E")
{
cout<<"E "<<s<<endl;
}
}; //终于的继承E,F
class G : public E, public F
{
M m;
public:
//这里初始化的顺序和继承的顺序不同。看看结果,结果是按继承的顺序初始化
G(const string& s) : B("from G"), C("from G"), F("from G"), E("from G"), m("in G")
{
cout<<"G "<<s<<endl;
}
}; int main()
{
//构造函数的调用顺序是某类在类派生表中出现的顺序 G g("from main"); return 0;
}
重要结论:
基类构造函数假设有多个基类则构造函数的调用顺序是某类在类派生表中出现的
顺序而不是它们在成员初始化表中的顺序。
【ThinkingInC++】75、多重继承的更多相关文章
- c#继承、多重继承
c#类 1.c#类的继承 在现有类(基类.父类)上建立新类(派生类.子类)的处理过程称为继承.派生类能自动获得基类的除了构造函数和析构函数以外的所有成员,可以在派生类中添加新的属性和方法扩展其功能.继 ...
- 编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议75~78)
建议75:集合中的元素必须做到compareTo和equals同步 实现了Comparable接口的元素就可以排序,compareTo方法是Comparable接口要求必须实现的,它与equals方法 ...
- J a v a 的“多重继承”
接口只是比抽象类“更纯”的一种形式.它的用途并不止那些.由于接口根本没有具体的实施细节——也就是说,没有与存储空间与“接口”关联在一起——所以没有任何办法可以防止多个接口合并到一起.这一点是至关重要的 ...
- 75篇关于Tomcat源码和机制的文章
75篇关于Tomcat源码和机制的文章 标签: tomcat源码机制 2016-12-30 16:00 10083人阅读 评论(1) 收藏 举报 分类: tomcat内核(82) 版权声明:本文为 ...
- java提高篇(九)-----实现多重继承
多重继承指的是一个类可以同时从多于一个的父类那里继承行为和特征,然而我们知道Java为了保证数据安全,它只允许单继承.有些时候我们会认为如果系统中需要使用多重继承往往都是糟糕的设计,这个时候我们往往需 ...
- 不可或缺 Windows Native (22) - C++: 多重继承, 虚基类
[源码下载] 不可或缺 Windows Native (22) - C++: 多重继承, 虚基类 作者:webabcd 介绍不可或缺 Windows Native 之 C++ 多重继承 虚基类 示例1 ...
- scala 学习笔记(06) OOP(下)多重继承 及 AOP
一.多继承 上篇trait中,已经看到了其用法十分灵活,可以借此实现类似"多重继承"的效果,语法格式为: class/trait A extends B with C with D ...
- Effective C++ -----条款40:明智而审慎地使用多重继承
多重继承比单一继承复杂.它可能导致新的歧义性,以及对virtual继承的需要. virtual继承会增加大小.速度.初始化(及赋值)复杂度等等成本.如果virtual base classes不带任何 ...
- python基础——多重继承
python基础——多重继承 继承是面向对象编程的一个重要的方式,因为通过继承,子类就可以扩展父类的功能. 回忆一下Animal类层次的设计,假设我们要实现以下4种动物: Dog - 狗狗: Bat ...
随机推荐
- opencv3.2.0图像离散傅里叶变换
源码: ##名称:离散傅里叶变换 ##平台:QT5.7.1+opencv3.2.0 ##日期:2017年12月13. /**** 新建QT控制台程序****/ #include <QCoreAp ...
- 网络基础 Windows下安装和配置net-snmp 代理
Windows 下安装和配置net-snmp 代理[摘录] by:授客 QQ:1033553122 A. 安装 1. 安装前准备 ActivePerl-5.10.0.1004-MSWin ...
- linux vim 快捷键
vim命令模式输入a i o 这些命令进入插入模式 编辑模式命令模式输入双引号进入编辑模式 命令模式命令 命令 作用 :map Ctrl+V Ctrl+P I#<ESC> 自定义注释快捷键 ...
- TYPE_SCROLL_INSENSITIVE is not compatible with CONCUR_UPDATABLE
There are two options when setting ResultSet to be scrollable: TYPE_SCROLL_INSENSITIVE - The result ...
- Java设计模式----初识适配器模式
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...
- Oracle EBS 键弹性域 段限定词取值
中间是回车符 对应编码时 Chr(10) substr(replace(t.compiled_value_attributes, Chr(10), ''), 3, 1)
- Excel数据导入PG库,字符串正则表达式
1.Excel数据导入到PG库的某张表中:先将Excel文件转换为CSV格式,打开SQL Shell(psql),连接数据库(输入server,database,Port,username),然后再执 ...
- 转:C# 线程同步技术 Monitor 和Lock
原文地址:http://www.cnblogs.com/lxblog/archive/2013/03/07/2947182.html 今天我们总结一下 C#线程同步 中的 Monitor 类 和 Lo ...
- Fiddler下Firefox提示“您的连接并不安全”的解决办法
一.版本信息 Firefox 最新版本V46.0.1 Fiddler 最新版本V4.6.2.3 二.错误信息 开启fiddlers的https协议捕获的方法,百度上可以查到不再赘述,直接放张图(Too ...
- Redis学习---Redis的免密操作
Redis的免密操作 问题解决[方式一]:当前这种linux配置redis密码的方法是一种临时的,如果redis重启之后密码就会失效 1.首先进入redis,如果没有开启redis则需要先开启: [r ...