zoukankan      html  css  js  c++  java
  • C++中的类继承(4)继承种类之单继承&多继承&菱形继承

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

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

    菱形继承也叫钻石继承

    但是多继承存在一个问题,要想研究这个问题,我们先从单继承讲起。来看内存空间:

    复制代码
     1 class Base
     2 {
     3 public:
     4 Base() {
     5 cout << "B()" << endl;
     6 }
     7 int b1;
     8 };
     9 class Derive : public Base
    10 {
    11 public:
    12 Derive() {
    13 cout << "D()" << endl;
    14 }
    15 int d1; 
    16 };
    17 int main()
    18 {
    19 Test();
    20 getchar();
    21 return 0;
    22 }
    复制代码

    多继承的内存空间:

    复制代码
     1 class Base
     2 {
     3 public:
     4 Base() {
     5 cout << "B()" << endl;
     6 }
     7 int b1;
     8 };
     9 class C
    10 {
    11 public:
    12 C() {
    13 cout << "C()" << endl;
    14 }
    15 int c;
    16 };
    17 class Derive : public Base, public C
    18 {
    19 public:
    20 Derive() {
    21 cout << "D()" << endl;
    22 }
    23 int d1; 
    24 };
    复制代码

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

    复制代码
     1 class A
     2 {
     3 public:
     4 A() {
     5 cout << "A()" << endl;
     6 }
     7 int a;
     8 };
     9 class Base:public A
    10 {
    11 public:
    12 Base() {
    13 cout << "B()" << endl;
    14 }
    15 int b1;
    16 };
    17 class C: public A
    18 {
    19 public:
    20 C() {
    21 cout << "C()" << endl;
    22 }
    23 int c;
    24 };
    25 class Derive : public Base, public C
    26 {
    27 public:
    28 Derive() {
    29 cout << "D()" << endl;
    30 }
    31 int d1; 
    32 };
    复制代码

    在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环境下用的是偏移量,而不是图中的直接指针指向这里只是为了更直观的展示。

  • 相关阅读:
    JavaScript: RegExp + replace
    JavaScript:布局
    DOM和BOM区别
    正则表达式
    a report about the history of pragrem
    web第6次作业position
    web api
    DOM Event:事件流动(Event Flow)
    FOR衍生对象
    前端的发展
  • 原文地址:https://www.cnblogs.com/tangshiguang/p/6735317.html
Copyright © 2011-2022 走看看