【问题标题】:c++ diamond inheritance constructor? [duplicate]C++钻石继承构造函数? [复制]
【发布时间】:2014-06-15 03:35:25
【问题描述】:

我想知道我应该如何为我的第四节课调用我的构造函数。 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()
{
}

【问题讨论】:

  • 因为没有其他人(包括链接的问题)能够解决您收到的实际错误消息;我将会。您的ClassBClassC 构造函数中的任何一个 看起来是否带有no 参数?是的,都没有。那么你为什么要调用 ClassB()ClassC() 呢?使用他们声明的构造函数。也就是说,链接问题和发布的答案中的所有内容都适用,因此请仔细阅读。
  • 我只是对调用哪个构造函数以及不调用哪个构造函数感到非常困惑?我知道我应该调用 ClassA 构造函数,因为它是基类,但这是否意味着我根本不调用 B 类和 C 类构造函数?如果我这样做,我是否将论点留空,这就是我认为我得到那个错误的原因。 *所有虚拟继承语句都包含在我的 .h 文件中。

标签: c++ inheritance diamond-problem


【解决方案1】:

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

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

    但是,这很可能不是您想要实现的。除了成为打结大脑的最可靠方法之一之外,您还会遇到许多问题,其中最少的一个是几乎任何从ClassD 实例访问ClassA 成员的尝试都会产生错误,因为到模棱两可。编译器根本不知道从两个实例中的哪个实例中查找成员。

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


回复您的评论:
您可以向ClassA 添加一个默认构造函数,您可以从ClassBClassC 的构造函数中调用它。然后ClassD 可以调用ClassA 的完整构造函数,您不必通过ClassBClassC 的构造函数转发参数。只要您只构造ClassD 的对象,就永远不会调用ClassA 的默认构造函数,即使它必须存在于ClassBClassC 的默认构造函数的定义中。

考虑以下代码:

#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) 直接从类 D 调用。

【讨论】:

  • 我为我的 B 类和 C 类添加了虚拟继承。我只是在使用 ClassD 构造函数时遇到了问题。 ClassB 和 C 采用与 classA 完全相同的参数,因此他们称之为。所以现在我有一个采用相同参数的第 4 个类,我是否在 B 和 C 为空的情况下调用 classA 构造函数?还是只是 A 而省略 B 和 C?
  • 我已将我对您的评论的回复直接添加到答案中。我希望这个例子足以说明问题。
【解决方案2】:

你应该声明为:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-21
    • 1970-01-01
    • 2013-05-16
    • 2010-10-02
    • 2019-01-12
    • 1970-01-01
    • 2014-08-21
    • 1970-01-01
    相关资源
    最近更新 更多