虚拟继承:接口和构造函数

Virtual Inheritance: Interfaces and constructors

我正在使用 C++11。我正在尝试声明 2 个接口:B 和 C,每个接口都声明了一些要由子 classes 实现的函数。这两个接口都依赖于在公共 A class 中声明的变量和函数。即使是这种相对简单的结构也会导致钻石遗传问题。(https://www.makeuseof.com/what-is-diamond-problem-in-cpp/) 我对 link A 和 B/C 使用虚拟继承,试图实现这样的东西:

#edit 1 将原始代码片段修改为最小的可重现示例。

class T1{};
class A{
public:
    A(const T1& param1);

    void myfuna();
    const T1 member1;
};
class B : public virtual A{
    virtual void myfunb()=0;
};
class C: public virtual A{
    virtual void myfunc()=0;
};
class Di: public B, public C{
    Di(const T1& param1): A(param1){}
    void myfunb() override;
    void myfunc() override;
};

但是,这段代码无法编译。原因是 cpp 接口并不完全是“接口”(我有 Java 背景),因为即使使用虚拟继承,它们仍然有一个被调用的默认构造函数。这意味着在初始化“D”的实例时,将调用这些构造函数:

B 和 C 构造函数依次尝试调用定义不正确的 A() 构造函数(我收到“调用隐式删除默认构造函数”错误)。罪魁祸首是 A 的 const 字段,它禁用了默认构造函数

我找不到解决这个问题的优雅方法。我是否遗漏了什么,是我的设计有缺陷还是这只是 cpp 的限制?

解决办法是:

  • BC 抽象化 类。
  • 或者为A定义一个默认构造函数。
  • 或者在BC的构造函数中调用A的non-default构造函数。

如@eerorika 所述,有 2 个选项可以解决此问题:

为 A() 定义默认构造函数

使用虚拟参数实例化父对象 class 相对容易,因此定义了默认构造函数。它有点难看,但是因为默认构造函数创建的对象通常永远不会被使用,所以它应该可以工作。

我还有一点要说:假设class B 实现了他的一个功能(参见“implementeB”)并且需要访问member1。将访问什么对象?虚拟变量还是给 Di (param1) 的构造函数的变量? 如果使用虚拟变量,这是一个问题。

class T1{};
static const T1 dummy;

class A{
public:
    A(): member1(dummy){}
    A(const T1& param1);
    void myfuna();
    const T1 member1;
};

class B : public virtual A{
public:
    virtual void myfunb()=0;
    T1 implementedB(){
        return member1;
    }
};

class C: public virtual A{
public:
    virtual void myfunc()=0;
};

class Di: public B,
        public C
{
public:
    Di(const T1& param1):
    A(param1){}
    void myfunb() override{}
    void myfunc() override{}
};

在B和C的构造函数中调用A的non-default构造函数 我相信这是正确的解决方案。但是,这也意味着需要将 A 的参数列表传播到所有 subclasses。对于更大的 classes,这会很快变得很大,这有点违背了“接口”的目的。这也意味着子 classes ("Di") 需要显式调用所有基础 class 构造函数(A(..)、B(..) 和 C(..))我猜没有理想的方法...

class T1{};
static const T1 dummy;

class A{
public:
    A(const T1& param1);

    void myfuna();
    const T1 member1;
};

class B : public virtual A{
public:
    B(T1 param1) : A(param1){}
    virtual void myfunb()=0;
};

class C: public virtual A{
public:
    C(T1 param1) : A(param1){}
    virtual void myfunc()=0;
};

class Di: public B,
        public C
{
public:
    Di(const T1& param1):
    A(param1), B(param1), C(param1){

    }
    void myfunb() override{}
    void myfunc() override{}
};