第九章 多重继承

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、派生类构造函数

作为一般规则派生类构造函数应该不能直接向一个基类数据成员赋值而是把值传递

给适当的基类构造函数否则两个类的实现变成紧耦合的(tightly coupled)将更加难于

正确地改动或扩展基类的实现。

(基类设计者的责任是提供一组适当的基类构造函数)

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、多重继承的更多相关文章

  1. c#继承、多重继承

    c#类 1.c#类的继承 在现有类(基类.父类)上建立新类(派生类.子类)的处理过程称为继承.派生类能自动获得基类的除了构造函数和析构函数以外的所有成员,可以在派生类中添加新的属性和方法扩展其功能.继 ...

  2. 编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议75~78)

    建议75:集合中的元素必须做到compareTo和equals同步 实现了Comparable接口的元素就可以排序,compareTo方法是Comparable接口要求必须实现的,它与equals方法 ...

  3. J a v a 的“多重继承”

    接口只是比抽象类“更纯”的一种形式.它的用途并不止那些.由于接口根本没有具体的实施细节——也就是说,没有与存储空间与“接口”关联在一起——所以没有任何办法可以防止多个接口合并到一起.这一点是至关重要的 ...

  4. 75篇关于Tomcat源码和机制的文章

    75篇关于Tomcat源码和机制的文章 标签: tomcat源码机制 2016-12-30 16:00 10083人阅读 评论(1) 收藏 举报  分类: tomcat内核(82)  版权声明:本文为 ...

  5. java提高篇(九)-----实现多重继承

    多重继承指的是一个类可以同时从多于一个的父类那里继承行为和特征,然而我们知道Java为了保证数据安全,它只允许单继承.有些时候我们会认为如果系统中需要使用多重继承往往都是糟糕的设计,这个时候我们往往需 ...

  6. 不可或缺 Windows Native (22) - C++: 多重继承, 虚基类

    [源码下载] 不可或缺 Windows Native (22) - C++: 多重继承, 虚基类 作者:webabcd 介绍不可或缺 Windows Native 之 C++ 多重继承 虚基类 示例1 ...

  7. scala 学习笔记(06) OOP(下)多重继承 及 AOP

    一.多继承 上篇trait中,已经看到了其用法十分灵活,可以借此实现类似"多重继承"的效果,语法格式为: class/trait A extends B with C with D ...

  8. Effective C++ -----条款40:明智而审慎地使用多重继承

    多重继承比单一继承复杂.它可能导致新的歧义性,以及对virtual继承的需要. virtual继承会增加大小.速度.初始化(及赋值)复杂度等等成本.如果virtual base classes不带任何 ...

  9. python基础——多重继承

    python基础——多重继承 继承是面向对象编程的一个重要的方式,因为通过继承,子类就可以扩展父类的功能. 回忆一下Animal类层次的设计,假设我们要实现以下4种动物: Dog - 狗狗: Bat ...

随机推荐

  1. vscode 代码跳转之PHP篇

    1.安装插件:PHP IntelliSense 2.配置:"php.executablePath": "C:\\php\\php.exe", 但是目前有问题,跨 ...

  2. Django随笔

    入门 小Demo设计介绍 本示例完成“图书-英雄”信息的维护,需要存储两种数据:图书.英雄 图书表结构设计: 表名:BookInfo 图书名称:btitle 图书发布时间:bpub_date 英雄表结 ...

  3. 卷积神经网络(CNN)在语音识别中的应用

    前言 总结目前语音识别的发展现状,dnn.rnn/lstm和cnn算是语音识别中几个比较主流的方向.2012年,微软邓力和俞栋老师将前馈神经网络FFDNN(Feed Forward Deep Neur ...

  4. Android屏幕适配工具

    这里需要用到一个jar包,下载拿到这个jar包后直接双击就可以生成市场大部分主流屏幕尺寸了.然后只要把生成好的xml尺寸文件拷贝到相应的value文件中即可.很方便,以后再也不用担心适配繁琐的问题了. ...

  5. Android 进程回收

    1.Android 进程回收策略 众所周知,Android是基于Linux系统的.在Android进程回收策略中,Android进程与Linux进程根据OOM_ADJ阈值进行区分: OOM_ADJ & ...

  6. mysql 日期时间类型 自动转型 及 运算

    日期时间类型自动转型 -- now().字符串.数字转datetime类型 create table t(dt datetime);insert into t values(now());insert ...

  7. protobuf 源代码分析 (1)准备工作

    protobuf简介 protobuf是google开源的跨平台的一种数据序列化的代码自动生成器,支持c++.java和python语言,支持跨网络的传输数据,与平台类型无关.并且其生产的序列化数据具 ...

  8. Swagger RESTful API文档规范

    *注意编写的关键词:“必须”.“不能”.“需要”.“应当”,“不得”.“应该”.“不应该”,“推荐”.“可能”和“可选的” 原文链接:http://swagger.io/specification/ ...

  9. 的确,Java存在缺陷。但是……

    [编者按]本文作者为资深码农 Tim Spann,主要讲述 Java 让人无法抗拒的众多优点以及一些些缺陷.本文系国内 ITOM 管理平台 OneAPM 编译呈现,以下为正文. 早在90年代中期,笔者 ...

  10. Kubernetes简述

    一.Kubernetes特性 1.自动装箱 建构于容器之上,基于资源依赖及其他约束自动完成容器部署且不影响其可用性,并通过调度机制混合关键型应用和非关键型应用的工作负载于一点以提高资源利用率. 2.自 ...