第九章 多重继承

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. DNS必知必会

    什么是DNS? DNS服务器(Domain Name Server,域名服务器)是进行域名和与之相对应的IP地址进行转换的服务器. 基本概念 DNS服务器中保存了一张域名和与之相对应的IP地址 的表, ...

  2. mysql 导入时报错:Got a packet bigger than‘max_allowed_packet’bytes

    原因是max_allowed_packet 值设置过小. 网上粘贴一段定义: max_allowed_packet:指代mysql服务器端和客户端在一次传送数据包的过程当中数据包的大小这个是定义mys ...

  3. 日期选择器(DatePicker)

    日期选择器(DataPicker) 显示一个可供日期选择的界面 监听器方法init(year,month,day,OnDateChangedListener) 监听器 DataPicker.OnDat ...

  4. python学习笔记之——python函数

    1.定义一个函数 你可以定义一个自己想要功能的函数,以下是简单的规则: 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号(). 任何传入参数和自变量必须放在圆括号中间.圆括号之间可以用于定 ...

  5. 强网杯2018 pwn复现

    前言 本文对强网杯 中除了 2 个内核题以外的 6 个 pwn 题的利用方式进行记录.题目真心不错 程序和 exp: https://gitee.com/hac425/blog_data/blob/m ...

  6. phpAdmin修改密码后拒绝访问

    [phpMyadmin没配置正确] 解决方法: 1.打开 phpMyadmin 目录找到config.inc.php文件2.查找到$cfg['Servers'][$i]['password']=''3 ...

  7. DBFlow(4.2)新版使用

    DBFlow新版使用 一.DBFlow4.2.4介绍 DBFlow是一个基于AnnotationProcessing(注解处理器)的ORM框架.此框架设计为了速度.性能和可用性.消除了大量死板的数据库 ...

  8. Navicat Premium 连接MySQL数据库出现Authentication plugin 'caching_sha2_password' cannot be loaded的解决方案

    1. 管理员权限运行命令提示符,登陆MySQL mysql -u root -p root 2. 修改账户密码加密规则并更新用户密码  ALTER USER 'root'@'localhost' ID ...

  9. CSS 颜色 字体 背景 文本 边框 列表 display属性

    1  颜色属性 <div style="color:blueviolet">ppppp</div> <div style="color:#f ...

  10. html的button疑问

    button是可以自动垂直居中的,随便给个高度,它都会自动垂直居中.用控制台查看computed属性里也没有发现和垂直相关的,贴出来希望以后能够了解或有高手看到来解惑小弟:)