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

发布于 2025-01-09 18:49:16 字数 1069 浏览 2 评论 0原文

我正在使用 C++11。我试图声明 2 个接口:B 和 C,每个接口声明一些由子类实现的函数。这两个接口都依赖于公共 A 类中声明的变量和函数。即使这种相对简单的结构也会导致钻石继承问题。(https: //www.makeuseof.com/what-is-diamond-problem-in-cpp/) 我使用虚拟继承来链接 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”实例时,将调用这些构造函数:

  • A(param1,param2)
  • B()
  • C()

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

我找不到一种优雅的方法来解决这个问题。我是否遗漏了一些东西,我的设计是否有缺陷,或者这只是 cpp 的限制?

I am using C++11. I am trying to declare 2 interfaces: B and C, which each declare some functions to be implemented by the child classes. Both interfaces rely on variables and functions which are declared in the common A class. Even this relatively simple structure leads to the diamond heritance problem.(https://www.makeuseof.com/what-is-diamond-problem-in-cpp/)
I use virtual inheritance to link A and B/C, trying to implement something like this:

#edit 1
Modified the original code snippet to be a minimal reproducable example.

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;
};

However, this code won't compile. The reason is that cpp interfaces aren't exactly speaking "interfaces" (I have a Java background), as they still have a default constructor which is called, even when virtual inheritance is used. This means that upon initialization of an instance of "D", these constructors are called:

  • A(param1,param2)
  • B()
  • C()

The B and C constructors in turn try to call the A() constructor, which is ill-defined (I get the "call to implicitly-delete default constructor" error). The culprit is the const field of A, which disables the default constructor.

I can't find an elegant way to remedy this problem. Am I missing something, is my design flawed or is this just a limitation of cpp?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

暮倦 2025-01-16 18:49:16

解决方案是:

  • 创建BC抽象类。
  • 或者为 A 定义一个默认构造函数。
  • 或者在BC的构造函数中调用A的非默认构造函数。

The solutions are:

  • Make B and C abstract classes.
  • Or define a default constructor for A.
  • Or call the non-default constructor of A in the constructors of B and C.
玩套路吗 2025-01-16 18:49:16

正如 @eerorika 所说,有 2 个选项可以解决这个问题:

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

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

我还有一句话:想象一下类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的非默认构造函数。
我相信这是正确的解决方案。然而,这也意味着 A 的参数列表需要传播到所有子类。对于更大的类,这可能会很快变得很大,并且它有点违背了“接口”的目的。这也意味着子类(“Di”)需要显式调用所有基类构造函数(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{}
};

As stated by @eerorika, there are 2 options to solve this issue:

Define a default constructor for A()

It is relatively easy to instantiate the parent class with a dummy parameters, so that a default constructor is defined. It is a bit ugly, but because the object created by the default constructor will normally never be used, it should work.

I still have one remark: Imagine class B implements one of his functions (see "implementeB") and needs to access member1. What object will be accessed? The dummy variable or the variable given to the constructor of Di (param1)? If the dummy variable is used, this is a problem.

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{}
};

Call the non-default constructor of A in the constructors of B and C.
I believe this is the correct solution. However, it also means that the argument list of A needs to be propagated to all the subclasses. For bigger classes, this can quickly grow quite big, and it kind of defeats the purpose of an "interface". It also means that the child classes ("Di") need to explicitly call all base class constructors (A(..), B(..) and C(..))I guess there isn't an ideal way...

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{}
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文