【问题标题】:Inheriting from multiple/diamond Inheritance从多重/钻石继承继承
【发布时间】:2013-01-29 13:09:03
【问题描述】:

我有以下情况:

class A
{
  public:
    A(std::string id);
};

class B : public virtual A
{
  public:
    B();
};

class C : public virtual A
{
  public:
    C();
};

class D : public B, public C
{
  public:
    D(std::string id);
};


D::D(std::string id) : A(id), B(), C()
{
}


class X : public D
{
  public:
    X(std::string id);
}

X::X(std::string id) : D(id)
{
}

现在,如果我创建 D 的实例,一切正常。但是,如果我创建 X 的一个实例,我会收到一个编译器错误,它告诉我某些东西试图调用 A 的默认构造函数——它不存在。如果我创建它,它会编译,但只调用默认构造函数,因此,id 没有正确设置/初始化。

这可以通过像这样实现 X 的构造函数来解决:

X::X(std::string id) : A(id), D(id)
{
}

但我的理解是,这应该是不必要的。那么我的错误在哪里?

【问题讨论】:

  • X::X 必须初始化 A,因为 D::D 在用作基类时不会初始化 A(A(id) 初始化程序被忽略)。

标签: c++ inheritance multiple-inheritance virtual-inheritance diamond-problem


【解决方案1】:

您需要将所有构造函数设为public 并为A 定义一个默认构造函数,因为字符串构造函数会将默认构造函数标记为=delete。此外,the most derived class will initialize any virtual base class,引用自draft Standard:

12.6.2 初始化基和成员 [class.base.init]

10 在非委托构造函数中,初始化在 下面的顺序:——首先,并且只针对最上面的构造函数 派生类(1.8),虚拟基类按顺序初始化 它们出现在有向的从左到右的深度优先遍历中 基类的无环图,其中“从左到右”是 派生类中基类的外观 基本说明符列表。

在这种情况下,这意味着X 必须确实初始化A。

#include <iostream>
#include <string>

class A
{
public:
  A() { std::cout << "A\n"; }
  A(std::string id) { std::cout << id << " A(id)\n"; }
};

class B : public virtual A
{
public:
   B() { std::cout << "B\n"; }
};

class C : public virtual A
{
public:
   C() { std::cout << "C\n"; }
};

class D : public B, public C
{
public:  
   D(std::string id): A(id) { std::cout << id << " D(id)\n"; }
};


class X : public D
{
public:
  X(std::string id): A(id), D(id) { std::cout << id << " X(id)\n"; }
};

int main()
{
   X x("bla");
   x;       
}

【讨论】:

  • 我的所有构造函数都是公共的,但是在 A 中添加默认构造函数会导致在创建 X 的实例时调用 A() 而不是 A(id)。
  • 在这种情况下,我的问题是:有没有办法解决这个问题?由于 A、B、C 和 D 组成了一个图书馆,我不希望图书馆的用户知道关于 A 的任何事情。他们只应该知道和使用 D。
  • @joekr AFAIK,除了重构你的类层次结构之外,没有其他办法。请注意,这是为什么组合几乎总是优于继承的原因之一,尤其是优于维护状态的类的继承。
  • 一种选择是将 id 存储在 D 中并添加一个用于检索它的虚函数。
猜你喜欢
  • 2019-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-09
  • 2016-09-21
  • 1970-01-01
相关资源
最近更新 更多