C++ 入门第 5 版虚拟继承和ctor-init

问题描述

关于 C++ 入门第 5 版。第18章多重和虚继承,我有这个问题:

练习 18.30:在 Base 中定义认构造函数、复制构造函数和具有 int 参数的构造函数。在每个派生类中定义相同的三个构造函数。每个构造函数都应该使用它的参数来初始化它的 Base 部分。

我尝试以这种方式解决它,所以这是我的继承层次结构:

struct Class {
    Class(){cout << "Class()\n";}
    ~Class(){cout << "~Class()\n";}
};

struct Base : Class {
    Base(){cout << "Base()\n";}
    Base(int){cout << "Base(int)\n";}
    Base(Base const&){cout << "Base(Base const&)\n";}

    ~Base(){cout << "~Base()\n";}
};

struct D1 : virtual public Base {
    D1(){cout << "D1()\n";}
    D1(int x) : Base(x){
        cout << "D1(int)\n";
    }
    D1(D1 const& rhs) : Base(rhs){
        cout << "D1(D1 const&)\n";
    }

    ~D1(){cout << "~D1()\n";}
};

struct D2 : virtual public Base {
    D2(){cout << "D2()\n";}
    D2(int x) : Base(x){
        cout << "D2(int)\n";
    }
    D2(D2 const& rhs) : Base(rhs){
        cout << "D2(D2 const&)\n";
    }
    ~D2(){cout << "~D2()\n";}
};

struct MI : public D1,public D2 {
    MI(){cout << "MI()\n";}
    MI(int x) : Base(x),D1(x),D2(x){
        cout << "MI(int)\n";
    }
    MI(MI const& rhs) : Base(rhs),D1(rhs),D2(rhs){
        cout << "MI(MI const&)\n";
    }

    ~MI(){cout << "~MI()\n";}
};

struct Final : public MI,public Class {
    Final(){cout << "Final()\n";}
    Final(int x) : MI(x){
        cout << "Final(int)\n";
    }
    Final(Final const& rhs) : MI(rhs),Class(rhs){
        cout << "Final(Final const&)\n";
    }

    ~Final(){cout << "~Final()\n";}
};

现在,如果我编译程序,我会收到错误

 error: ‘Class’ is an ambiguous base of ‘Final’

所以问题出在类 Final 的复制构造函数初始化列表中,所以我如何在复制构造函数中初始化 Class 的子部分。

  • Final(int) 不会抱怨,因为我让 Class()认构造函数运行:

      Final(int x) : MI(x) // Class default ctor is executed.
    

所以帮我解决这个问题。谢谢!

解决方法

inaccessible-base 类就是这种情况。 Final 类已经有一个继承链:

struct Final -> struct MI -> struct D1 -> struct Base -> struct Class

把东西写成 class Square: public Shape 表示 is-a 关系,所以 Square is-a 形状。对于您的类链,它也在 FinalClass 之间建立了相同的关系,尽管通过许多中间父系谱系。在 public Class 中写 struct Final : public MI,public Class 实际上是多余的。在现实世界的类比中,这类似于表明曾曾祖父是直系父亲,除非我们讨论幻想或反常的东西,否则这是不适用的。编译器在警告中声明了 here ,显示了它所带来的歧义,然后无法编译代码。对此 here 有一个更细致入微的答案。对于您的具体问题,只需从 Class 中删除 Final 就应该是 fine 以进行编译。

附言请考虑将 Class 重命名为其他名称,因为这是 C++ 并且...class 是一件大事。 class Class 会非常不可读。