虚拟继承:接口和构造函数
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”的实例时,将调用这些构造函数:
- A(参数 1,参数 2)
- B()
- C()
B 和 C 构造函数依次尝试调用定义不正确的 A() 构造函数(我收到“调用隐式删除默认构造函数”错误)。罪魁祸首是 A 的 const 字段,它禁用了默认构造函数。
我找不到解决这个问题的优雅方法。我是否遗漏了什么,是我的设计有缺陷还是这只是 cpp 的限制?
解决办法是:
- 将
B
和 C
抽象化 类。
- 或者为
A
定义一个默认构造函数。
- 或者在
B
和C
的构造函数中调用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{}
};
我正在使用 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”的实例时,将调用这些构造函数:
- A(参数 1,参数 2)
- B()
- C()
B 和 C 构造函数依次尝试调用定义不正确的 A() 构造函数(我收到“调用隐式删除默认构造函数”错误)。罪魁祸首是 A 的 const 字段,它禁用了默认构造函数。
我找不到解决这个问题的优雅方法。我是否遗漏了什么,是我的设计有缺陷还是这只是 cpp 的限制?
解决办法是:
- 将
B
和C
抽象化 类。 - 或者为
A
定义一个默认构造函数。 - 或者在
B
和C
的构造函数中调用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{}
};