【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的继承方式,即加一个关键字
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;
}

重要结论:

基类构造函数如果有多个基类则构造函数的调用顺序是某类在类派生表中出现的

顺序而不是它们在成员初始化表中的顺序。

时间: 2024-10-27 02:34:35

【ThinkingInC++】75、多重继承的相关文章

虚基类练习:动物(利用虚基类建立一个类的多重继承,包括动物(animal,属性有体长,体重和性别),陆生动物(ter_animal,属性增加了奔跑速度),水生动物(aqu_animal,属性增加了游泳速度)和两栖动物(amp_animal)。)

Description 长期的物种进化使两栖动物既能活跃在陆地上,又能游动于水中.利用虚基类建立一个类的多重继承,包括动物(animal,属性有体长,体重和性别),陆生动物(ter_animal,属性增加了奔跑速度),水生动物(aqu_animal,属性增加了游泳速度)和两栖动物(amp_animal).其中两栖动物保留了陆生动物和水生动物的属性. Input 两栖动物的体长,体重,性别,游泳速度,奔跑速度(running_speed) Output 初始化的两栖动物的体长,体重,性别,游泳速度

Java实现多重继承:

Java没有多重继承,C++有,不过Java提供了Interface.extends和implement,多重继承的效果还是可以的: 1 /** 2 * Created by Franklin Yang on 2015.10.23. 3 */ 4 5 // 6 interface Base { 7 public void method1(); 8 } 9 10 interface aI extends Base{ 11 public void method2(); 12 public void

说说C++多重继承

尽管大多数应用程序都使用单个基类的公用继承,但有些时候单继承是不够用的,因为可能无法为问题域建模或对模型带来不必要的复杂性.在这种情况下,多重继承可以更直接地为应用程序建模. 一.基本概念 多重继承是从多于一个直接基类派生类的能力,多重继承的派生类继承其父类的属性. class ZooAnimal{ }; class Bear : public ZooAnimal{ }; class Endangered{ }; class Panda : public Bear, public Endange

C++中的多重继承(二)

1,本文分析另一个多重继承问题及其工程中的解决方案,单继承加多接口实现的开发方式: 2,多重继承的问题三: 1,多重继承可能产生多个虚函数表: 1,实际工程中可能造成不可思议的问题,并且这些问题很难以查找和排除: 3,多重继承问题三编程实验: 1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class BaseA 7 { 8 public: 9 virtual void funcA() 1

016: class and objects &gt; 多重继承与多态的例子

房屋代理模型: 1. Property class Property(object): def __init__(self, square_feet='', num_bedrooms='', num_baths='', **kwargs): super().__init__(**kwargs) self.square_feet = square_feet self.num_bedrooms = num_bedrooms self.num_baths = num_baths def display

C++多重继承中构造函数和析构函数调用顺序举例

//多重继承 #include <iostream> using namespace std; class A { public:     A()     {         cout<<"A基类构造A::A()"<<endl;     }     ~A()     {         cout<<"A基类析构A::~A()"<<endl;     } }; class B:public A { publi

C++多重继承关系举例

//多重继承 #include <iostream> using namespace std; class A { public:     int a;     A(int a=0):a(a)     {         cout<<"A基类A::A()"<<endl;     }     ~A()     {         cout<<"A基类A::~A()"<<endl;     }     void

C++多重继承中的虚继承和虚函数举例

上一篇虚继承举例:http://10638473.blog.51cto.com/10628473/1964414 本文将A类中的show()函数前加上virtual关键字. //多重继承 #include <iostream> using namespace std; class A { public:     int a;     A(int a=0):a(a)     {         cout<<"A基类A::A()"<<endl;     

Java提高篇——Java实现多重继承

阅读目录 一. 接口二.内部类 多重继承指的是一个类可以同时从多于一个的父类那里继承行为和特征,然而我们知道Java为了保证数据安全,它只允许单继承.有些时候我们会认为如果系统中需要使用多重继承往往都是糟糕的设计,这个时候我们往往需要思考的不是怎么使用多重继承,而是您的设计是否存在问题.但有时候我们确实是需要实现多重继承,而且现实生活中也真正地存在这样的情况,比如遗传:我们即继承了父亲的行为和特征也继承了母亲的行为和特征.可幸的是Java是非常和善和理解我们的,它提供了两种方式让我们曲折来实现多