C++多重继承与虚基类

原创 2012年03月28日 15:21:04
1. C++允许一个派生类从多个基类继承,这种继承方式称为多重继承,当从多个基类继承时每个基类之间用逗号隔开,比如class A:public B, public C{}就表示派生类A从基类B和C继承而来。
2. 多重继承的构造函数和析构函数:多重继承中初始化的次序是按继承的次序来调用构造函数的而不是按初始化列表的次序, 比如有class A:public B, public C{}那么在定义类A的对象A m时将首先由类A的构造函数调用类B的构造函数初始化B,然后调用类C的构造函数初始化C,最后再初始化对象A,这与在类A中的初始化列表次序无关。
3. 多重继承中的二义性问题:
3.1. 成员名重复:比如类A从类B和C继承而来,而类B和C中都包含有一个名字为f的成员函数,这时派生类
A创建一个对象,比如A m; 语句m.f()将调用类B中的f函数呢还是类C中的f函数呢?
3.2. 多个基类副本:比如类C和B都从类D继承而来,这时class A:public B, public C{}类A从类C和类B同时继
承而来,这时类A中就有两个类D的副本,一个是由类B继承而来的,一个是由类C继承而来的,当类A的
对象比如A m;要访问类D中的成员函数f时,语句m.f()就会出现二义性,这个f函数是调用的类B继承来的
f还是访问类C继承来的函数f呢。
3.3.在第2种情况下还有种情况,语句classA:public B,public C{},因为类A首先使用类B的构造函数调用共同基类D的构造函数构造第一个类D的副本,然后再使用类C的构造函数调用共同基类D的构造函数构造第二个类D的副本。类A的对象m总共有两个共享基类D的副本,这时如果类D中有一个公共成员变量d,则语句
m.B::d和 m.D::d都是访问的同一变量,类B和类D都共享同一个副本,既如果有语句m.D::d=3 则 m.B::d也
将是3。这时m.C::d的值不受影响而是原来的值。为什么会这样呢?因为类A的对象m总共只有两个类D的副本,所以类A的对象m就会从A继承来的两个直接基类B和C中,把从共同基类D 中最先构造的第一个副本作为类A的副本, 即类B构造的D的副本。 因为class A:public B,public C{}最先使用B的构造函数调用共
同基类类D创造D的第一个副本,所以类B和类D共享同一个副本。
3.4. 解决方法:对于第1 和第 2 种情况都可以使用作用域运算符::来限定要访问的类名来解决二义性。但对于第二种情况一般不允许出现两个基类的副本,这时可以使用虚基类来解决这个问题 ,一旦定义了虚基类,就只会有一个基类的副本 。

例:多重继承及其二义性
class A {
public:
    int a;
    A(int i){
        a=i;cout<<"A"<<endl;
    }
}; //共同的基类A
class B:public A {
public:
    int b;
    B():A(4){
        cout<<"B"<<endl;
    }
};
class C:public A{
public:
    int c;
    C():A(5){
        cout<<"C"<<endl;
    }
};
class D:public B,public C
{
public:
    int d;
    D():C(),B(){
        cout<<"D"<<endl;
    }
}; //先调用类B的构造函数而不会先调用类C的构造函数,初始化的顺序与初始化列表顺序无关
int main()
{
    D m;  //输出ABACD,调用构造函数的顺序为类ABACD,注意这里构造了两个类A的副本,调用了两次类A的构造函数
    // m.a=1; //错误,出现二义性语句,因为类D的对象m有两个公共基类A的副本,这里不知道是调用由类B继承来的A的副本还是由类C继承来的A的副本
    m.B::a=1;cout<<m.B::a; //输出1。
    m.A::a=3; cout<<m.B::a<<m.A::a;//输出33,类B和类A共享相同的副本,调用类A中的a和类B继承来的a是一样的,因此最后a的值为3。
    m.C::a=2;  cout<<m.C::a;//输出2,类C和类A类B的副本是彼此独立的两个副本,因此,这里不会改变类B和类A的副本中的a的值。
}
虚基类:方法是使用virtual关见字,比如class B:public virtual D{},class C:virtual public D{}注意关见字virtual的次
序不关紧要。类B和类C以虚基类的方式从类D继承,这样的话从类B和类C同时继承的类时就会只创见一个类D的副本,比如class A:public B, public C{}这时类A的对象就只会有一个类D的副本,类A类B类C类D四个类都共享一个类D的副本,比如类D 有一个公有成员变量d,则m.d和 m.A::d,m.B::d,m.C::d,m.D::d 都将访问的
是同一个变量。这样类A的对象调用类D中的成员时就不会出 现二义性了 。
虚基类的构造函数:比如class B:public virtual D{};class C:virtual public D{}; class A:public B,public C{};这时当创
建类A的对象A  m时初始化虚基类D将会使用类A的构造函数直接调用虚基类的构造函数初始化虚基类部分,而
不会使用类B或者类C的构造函数调用虚基类的构造函数初始化虚基类部分, 这样就保证了只有一个虚基类的副本。
但是当创建一个类B和类C的对象时仍然会使用类B和类C中的构造函数调用虚基类的构造函数初始化虚基类。
例:虚基类及其构造函数
class A {
public:
    int a;
    A(){
        cout<<"moA"<<endl;
    }
    A(int i){
        a=i;cout<<"A"<<endl;
    }
};
class B:public virtual A {
public:
    int b;
    B(int i):A(4){
        cout<<"B"<<endl;
    }  
}; //以虚基类的方式继承
class C:public virtual A {
public:
    int c;  
    C():A(5){
        cout<<"C"<<endl;
    }
};
class D:public B, public C {
public:
    int d;
    D():A(4),C(),B(2){
        cout<<"D"<<endl;
    }   
};
//因为类D是虚基类,所以类D会直接调用虚基类的构告函数构造虚基类部分,而不会使用类B或者类C的构造函数来调用虚基类的构造函数初
始化虚基类部分。要调用虚基类中的带参数的构造函数必须在这里显示调用,如果不显示调用就将调用虚基类的默认构造函数。
int main()
{
    D m;  //输出ABCD,注意这里没有重复的基类副本A。
    C m1;  //输出AC,虽然D是虚基类,但当创建类C的对象时仍然会使用类C的构造函数调用虚基类的构造函数初始化虚基类部分。
    cout<<m.a<<endl;  //输出4,因为使用了虚基类所以这里就不存在二义性问题。
    m.B::a=1;
    cout<<m.a<<m.A::a<<m.B::a<<m.C::a<<endl; //输出1111,类A,类B,类C,类D共享的是同一个虚基类的副本,所以这里输出四个1。

}

C++ 多重继承 虚继承 虚函数表 多态

C++中的多重继承和虚继承是一个非常重要的概念,也是看你是不是懂C++的一个重要的标志之一。这中间包括了运行时多态,虚函数表等等相关概念。 多重继承,顾名思义,是一个类继承了多个父类。例如class...
  • Troy_Wu
  • Troy_Wu
  • 2016年03月25日 15:05
  • 1939

<C++略识>之多重继承、多继承、虚继承

问题:什么是多重继承? 定义三个类:人、士兵、步兵,则有:步兵士兵人,这样的关系称之为多重继承,写法如下:class Person { }; classSoldier:publicPerson ...
  • u013003827
  • u013003827
  • 2016年07月22日 22:29
  • 3248

C++学习之继承篇(多继承与多重继承)

1.多继承 多继承是指一个子类继承多个父类。多继承对父类的个数没有限制,继承方式可以是公共继承、保护继承和私有继承, 不写继承方式,默认是private继承 多继承举例: #inclu...
  • hudfang
  • hudfang
  • 2016年01月21日 18:55
  • 13955

c++ 多重继承 + 虚基类

teacher_cadre(老师兼干部)  /|\     /|\    |       | teacher  cadre  /|\     /|\    |       |    per...
  • billbliss
  • billbliss
  • 2015年02月25日 22:27
  • 250

读书笔记--C++程序设计(第2版)--11.6多重继承(与虚基类)

多重继承(与虚基类) 1. 多重继承说明 也就是,一个派生类有两个或多个基类(派生类继承了两个或者多个基类的属性)。 2. 多重继承的书写形式为 举例形式说明: 如果已经声明了类A,类B,和类C,可以...
  • sillyboy1104
  • sillyboy1104
  • 2013年06月09日 20:34
  • 606

关于多重继承中覆盖虚基类的函数问题--《C++程序设计语言》

裘宗燕翻译的《c++程序设计语言(特别版)》第356页和357页分别有以下两段描述, 1.如果不同的派生类覆盖了同一个函数,那又会怎么样呢?当且仅当某个覆盖类是从覆盖此函数的每个类派生出时,才允...
  • ljg888
  • ljg888
  • 2012年06月09日 16:00
  • 1001

C++语言--多态性-8.1----多重继承、虚基类、虚函数和纯虚函数

1.多重继承
  • wu371894545
  • wu371894545
  • 2017年02月07日 11:32
  • 163

从零开始学C++之继承(三):多重继承、虚继承与虚基类

一、多重继承 单重继承——一个派生类最多只能有一个基类 多重继承——一个派生类可以有多个基类 class 类名: 继承方式 基类1,继承方式 基类2,…. {….}; 派生类同时继承多个基类的成...
  • Simba888888
  • Simba888888
  • 2013年07月12日 20:43
  • 2515

从多重继承中的二义性 到 虚基类(摘抄自谭浩强c++)

一个多重继承的程序 #include using namespace std; class Teacher { public: Teacher(string nam,int a,string...
  • wsyxhwj
  • wsyxhwj
  • 2016年05月11日 16:15
  • 408

多重继承与虚基类

  • 2012年06月13日 16:14
  • 918KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++多重继承与虚基类
举报原因:
原因补充:

(最多只允许输入30个字)