• C++中的类继承之单继承&多继承&菱形继承


     C++中的类继承之单继承&多继承&菱形继承

    单继承是一般的单一继承,一个子类只 有一个直接父类时称这个继承关系为单继承。这种关系比较简单是一对一的关系:

    多继承是指 一个子类有两个或以上直接父类时称这个继承关系为多继承。这种继承方式使一个子类可以继承多个父类的特性。多继承可以看作是单继承的扩展。派生类具有多个基类,派生类与每个基类之间的关系仍可看作是一个单继承。多继承下派生类的构造函数与单继承下派生类构造函数相似,它必须同时负责该派生类所有基类构造函数的调用。同时,派生类的参数个数必须包含完成所有基类初始化所需的参数个数。在子类的内存中它们是按照声明定义的顺序存放的,下面的截图将清晰看到。
    但是多继承存在一个问题,要想研究这个问题,我们先从单继承讲起。来看内存空间:

    class Base
    {
    public:
    Base() {
    cout << "B()" << endl;
    }
    int b1;
    };
    class Derive : public Base
    {
    public:
    Derive() {
    cout << "D()" << endl;
    }
    int d1; 
    };
    int main()
    {
    Test();
    getchar();
    return 0;
    }

    多继承的内存空间:

    class Base
    {
    public:
    Base() {
    cout << "B()" << endl;
    }
    int b1;
    };
    class C
    {
    public:
    C() {
    cout << "C()" << endl;
    }
    int c;
    };
    class Derive : public Base, public C
    {
    public:
    Derive() {
    cout << "D()" << endl;
    }
    int d1; 
    };

    菱形继承内存中数据分布:

    class A
    {
    public:
    A() {
    cout << "A()" << endl;
    }
    int a;
    };
    class Base:public A
    {
    public:
    Base() {
    cout << "B()" << endl;
    }
    int b1;
    };
    class C: public A
    {
    public:
    C() {
    cout << "C()" << endl;
    }
    int c;
    };
    class Derive : public Base, public C
    {
    public:
    Derive() {
    cout << "D()" << endl;
    }
    int d1; 
    };
    在A类中初始化int a=4则可清楚的看到菱形继承中内存分布所以子类Derive中有两份A类中的数据成员,这造成了访问二义性和数据冗余的问题这就是我前面说的多继承存在的问题。可以这样访问

    1 tmp.C::a=4;
    2 tmp.Base::a=5;

    什么是对象模型

    有两个概念可以解释C++对象模型:

    1、语言中直接支持面向对象程序设计的部分。
    2、对于各种支持的底层实现机制。

    还有另外一个方法解决这个问题,我们要用到一种新的继承方法:虚继承--解决菱形继承的二义性和数据冗余的问题。看下面这段代码:

    复制代码
     1 class Base
     2 {
     3 public:
     4     Base() {
     5         cout << "B()" << endl;
     6     }
     7     int b1;
     8 };
     9 class Derive : virtual public Base
    10 {
    11 public:
    12     Derive() {
    13         cout << "D()" << endl;
    14     }
    15     int d1; 
    16 };
    17 void Test()
    18 {
    19     Derive tmp;
    20     tmp.d1 = 1;
    21     tmp.b1 = 2;
    23 }
    24 int main()
    25 {
    26     Test();
    27     getchar();
    28     return 0;
    29 }
    复制代码

    虚拟继承的关键字---virtual

    复制代码
     1 class A
     2 {
     3 public:
     4     A() {
     5         cout << "A()" << endl;
     6     }
     7     int a ;
     8 };
     9 class Base : virtual public A
    10 {
    11 public:
    12     Base() {
    13         cout << "B()" << endl;
    14     }
    15     int b1;
    16 };
    17 class C:virtual public A
    18 { 
    19 public:
    20     C() {
    21         cout << "C()" << endl;
    22     }
    23     int c;
    24 };
    25 class Derive : virtual public Base, virtual public C
    26 {
    27 public:
    28     Derive() {
    29         cout << "D()" << endl;
    30     }
    31     int d1; 
    32 };
    33 void Test()
    34 {
    35     Derive tmp;
    36     tmp.d1 = 1;
    37     tmp.b1 = 2;
    38     tmp.c = 3;
    39     tmp.a = 4;
    40 }
    41 int main()
    42 {
    43     Test();
    44     getchar();
    45     return 0;
    46 }
    复制代码

    菱形虚拟继承的对象模型解决二义性问题在vs环境下用的是偏移量,而不是图中的直接指针指向这里只是为了更直观的展示。

  • 相关阅读:
    [补]2019HDU杭电多校第一场A
    [补]2019nowcoder牛客第三场F(暂且)
    [补]2019nowcoder牛客第一场E、I
    [学]从零(多项式基础与FFT)开始BM学习笔记
    [补]2019nowcoder牛客第二场E、H(upd0730)
    从一个简单的例子对win 服务程序进行讲解
    HTTP协议学习记录及总结
    Windows身份验证与forms身份验证的结合
    关于Sql server 的 几道面试题
    PlaceHolder控件的使用
  • 原文地址:https://www.cnblogs.com/yjd_hycf_space/p/6721179.html
Copyright © 2020-2023  润新知