c ++钻石继承构造函数?

时间:2014-04-29 09:21:25

标签: c++ inheritance diamond-problem

我想知道我应该如何为我的第四课打电话给我的构造函数。 A类是基类,B类和C类继承它。

ClassA::ClassA( const string &nam, const string &ide, double bal)
        :name(nam), id(ide), balance(bal)
{
}

ClassB::ClassB(const string &nam, const string &ide, double bal)
        :ClassA(nam, ide, bal)
{
}
 ClassC::ClassC(const string &nam, const string &ide, double bal)
                :ClassA(nam, ide, bal)
{
}

现在我的第四个类继承了B类和C类 我该如何为我的班级D调用构造函数?

我试过这种方式,但我得到“没有匹配函数来调用ClassB :: ClassB()â”

ClassD::ClassD(const string &nam, const string& ide, double bal)
        :ClassA(nam, ide, bal), ClassB(), ClassC()
{
}

2 个答案:

答案 0 :(得分:2)

这里不可见的是你是使用普通还是虚拟继承。这对你调用构造函数有很大的影响:

  1. 如果您使用普通继承,则ClassA的每个实例中都有两个 ClassD个实例。一个作为ClassB实例的一部分,另一个作为ClassC实例的一部分。因此,每个中间类都使用自己的构造函数调用构造自己的基本实例。

    然而,这很可能不是您想要达到的目标。除了作为结合大脑的最可靠方法之一之外,你会遇到许多问题,其中最少的是几乎任何从ClassA的实例访问ClassD成员的尝试都将由于歧义而产生错误。编译器根本不知道要从哪两个实例中查找成员。

  2. 如果使用虚拟继承,则对象中只有一个ClassA实例。因此,ClassB的构造函数和ClassC的构造函数都不会构造共享库,ClassA如果构造它们将构造两次。相反,ClassA在调用其他两个基本构造函数之前直接从ClassD的构造函数构造,因此您需要将ClassA()的调用添加到ClassD的初始化列表中如果默认构造函数不能做。


  3. 回应你的评论:
    您可以将ClassA的默认构造函数添加到ClassBClassC的构造函数中。然后,ClassD可以调用ClassA的完整构造函数,而您不必通过ClassBClassC的构造函数转发参数。只要您只构造ClassD的对象,就永远不会调用ClassA的默认构造函数,即使它必须存在于ClassB和{{1的默认构造函数的定义中}}

    请考虑以下代码:

    ClassC

    该程序的输出是

    #include <iostream>
    
    class A {
        public:
            A() { std::cout << "A::A()\n"; }    //Not used, but required.
            A(int) { std::cout << "A::A(int)\n"; }
    };
    
    class B : public virtual A {
        public:
            B() { std::cout << "B::B()\n"; }
            B(int) : A(1) { std::cout << "B::B(int)\n"; }    //Not required.
    };
    
    class C : public virtual A {
        public:
            C() { std::cout << "C::C()\n"; }
            C(int) : A(1) { std::cout << "C::C(int)\n"; }    //Not required.
    };
    
    class D : public B, public C {
        public:
            D(int) : A(1) { std::cout << "D::D(int)\n"; }
    };
    
    int main() {
        D foo(1);
    }
    

    正如您所看到的,即使A::A(int) B::B() C::C() D::D(int) A::A()是默认构造且不需要传递参数,也永远不会调用BC直接从班级A::A(int)调用。

答案 1 :(得分:1)

你应该声明为:

class ClassB: public virtual Class A
{
  ...
};
class ClassC: public virtual Class A
{
  ...
};
class ClassD: public ClassB, ClassC
{
...
};