【问题标题】:Diamond Problem C++: Derived class of diamond calls default constructor钻石问题 C++:钻石的派生类调用默认构造函数
【发布时间】:2021-11-13 03:33:32
【问题描述】:

因此,作为我程序的公共 API 的一部分,我公开了 D 类,以便用户从 D 类继承来创建自己的类。

然而,D 类是致命钻石的尖端,我遇到了一个问题,即用户的类正在调用 A 类的默认构造函数,而不是根据需要调用参数化构造函数。

  A
 / \
B   C
 \ /
  D
  |
E or F

在下面的代码中,类 E 是一个干净的 API,但是调用了错误的 A 构造函数。 F 类按预期工作,但是用户必须添加 A 的参数化构造函数,这很难看,因为该类是一个内部类。

有没有办法让 E 类按预期工作?为什么会这样?

#include<iostream>
using namespace std;
class A {
public:
    A(int x)  { cout << "A::A(int ) called" << endl;   }
    A()     { cout << "A::A() called" << endl;   }
};
  
class B : virtual public A {
public:
    B(int x): A(x)   {
       cout<<"B::B(int ) called"<< endl;
    }
};
  
class C : virtual public A {
public:
    C(int x): A(x) {
        cout<<"C::C(int ) called"<< endl;
    }
};
  
class D : public B, public C  {
public:
    D(int x): A(x), B(x), C(x)   {
        cout<<"D::D(int ) called"<< endl;
    }
};

class E : public D {
public:
    E(int x): D(x) {
        cout<<"E::E(int ) called"<<endl;
    }
};

class F : public D {
public:
    F(int x): D(x), A(x) {
        cout<<"F::F(int ) called"<<endl;
    }
};
  
int main()  {
    D d(0);
    cout<<endl;
    E e(1);
    cout<<endl;
    F f(2);
}

输出:

A::A(int ) called
B::B(int ) called
C::C(int ) called
D::D(int ) called

A::A() called
B::B(int ) called
C::C(int ) called
D::D(int ) called
E::E(int ) called

A::A(int ) called
B::B(int ) called
C::C(int ) called
D::D(int ) called
F::F(int ) called

【问题讨论】:

标签: c++ diamond-problem


【解决方案1】:

当构造一个具有任何虚拟基类的类时,命名虚拟基类的初始化器只会为派生最多的类调用。如果您的类有任何个虚拟基类,并且您想使用该虚拟基的非默认构造函数,那么您必须在派生类中指定该构造函数。

1 "所有虚拟基子对象都在任何非虚拟基子对象之前初始化,因此只有最派生的类在其成员初始化列表中调用虚拟基的构造函数:... "

2 "在构造不是正在构造的对象的最派生类的任何类期间,将忽略类或标识符命名虚拟基类的初始化程序。"

这个话题对我来说比较新,所以我希望有更多经验的人能指出我遗漏的任何细微差别。

【讨论】:

  • 啊,看来我的问题没有解决方案
  • @Will 我觉得那里 应该 是一个解决方案。我自己没有遇到过这个。也许你真的希望 E 和 F 有一个 D 类型的成员变量?
  • @Will “通常,当派生自虚拟基的类,尤其是虚拟基本身是纯抽象类时,虚拟基类最合适。” isocpp.org/wiki/faq/… 在这种情况下,基类构造函数将不带参数(这是一件好事,可以解决您的问题)
  • 感谢@JohnFilleau 的建议。组合需要相当多的重构,但总体上可能是一个更清洁的解决方案。 A 类目前几乎是一个纯抽象接口,除了 1 属性,一种标识符,如果 B 和 C 直接继承自(它们可以是)或 D/E,则它们是有意义的/F 有一个。标识符用作 A 设置的一部分,因此从构造函数中提取并不容易。我想我会试一试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-22
  • 2014-06-15
  • 1970-01-01
  • 2020-10-03
  • 1970-01-01
相关资源
最近更新 更多