使用虚拟继承时强制调用基本构造函数,尽管它永远不会被调用?
Forced to call the base constructor when using virtual inheritance although it will never be called?
我有一个 class Base
它有一个参数化的构造函数和两个 classes Middle1
和 Middle2
实际上继承自 Base
(为了解决菱形问题)。另外,classFoo
继承自Middle1
和Middle2
。
Foo 现在显式调用 Base 构造函数并传递参数。
class Base
{
private:
int value;
protected:
Base(int& value) { this->value = value; }
};
class Middle1 : virtual public Base
{
protected:
Middle1() { }
};
class Middle2 : virtual public Base
{
protected:
Middle2() { }
};
class Foo : public Middle1, public Middle2
{
public:
Foo(int& value) : Base(value) { }
};
然而,代码无法编译,因为 Base 缺少默认构造函数,因此 Middle1 和 Middle2 没有可调用的默认构造函数,但需要一个可以被 Foo 调用的构造函数。
当然,我现在也可以更改 Middle1 和 Middle2 的构造函数来调用 Base 的构造函数:
Middle1(int& value) : Base(value) { }
//...
Middle2(int& value) : Base(value) { }
// and then change my constructor of Foo:
Foo(int& value) : Base(value), Middle1(value), Middle2(value) { }
然而,它看起来相当笨拙 - 特别是考虑到由于虚拟继承, Base 构造函数将永远不会被 Middle1 或 Middle2 调用(它们不打算被初始化,即基本上是抽象的 class es)。因此,必须将参数引入到 Middle1 和 Middle2 的构造函数中似乎毫无用处。
有没有其他方法可以编译上述代码而不必在 Middle1 和 Middle2 中引入参数化构造函数?
在虚拟继承中,最派生的 class 必须 直接 调用其所有祖先构造函数。由于 Base
没有默认构造函数,如果 Middle1()
和 Middle2()
不能将 int&
传递给 Base()
,则它们无法编译。
但是,在您显示的代码中,Base()
没有理由引用 int
。改为按值传递,然后 Middle1()
和 Middle2()
可以将 0 传递给 Base()
:
class Base
{
private:
int value;
protected:
Base(int value = 0) { this->value = value; }
};
class Middle1 : virtual public Base
{
protected:
Middle1() { }
};
class Middle2 : virtual public Base
{
protected:
Middle2() { }
};
class Foo : public Middle1, public Middle2
{
public:
Foo(int value) : Base(value) { }
};
不过,我建议改为传递指针(或 std::optional
):
class Base
{
private:
int value;
protected:
Base(int* avalue = nullptr) { if (avalue) this->value = *avalue; }
};
class Middle1 : virtual public Base
{
protected:
Middle1() { }
};
class Middle2 : virtual public Base
{
protected:
Middle2() { }
};
class Foo : public Middle1, public Middle2
{
public:
Foo(int& value) : Base(&value) { }
};
我有一个 class Base
它有一个参数化的构造函数和两个 classes Middle1
和 Middle2
实际上继承自 Base
(为了解决菱形问题)。另外,classFoo
继承自Middle1
和Middle2
。
Foo 现在显式调用 Base 构造函数并传递参数。
class Base
{
private:
int value;
protected:
Base(int& value) { this->value = value; }
};
class Middle1 : virtual public Base
{
protected:
Middle1() { }
};
class Middle2 : virtual public Base
{
protected:
Middle2() { }
};
class Foo : public Middle1, public Middle2
{
public:
Foo(int& value) : Base(value) { }
};
然而,代码无法编译,因为 Base 缺少默认构造函数,因此 Middle1 和 Middle2 没有可调用的默认构造函数,但需要一个可以被 Foo 调用的构造函数。
当然,我现在也可以更改 Middle1 和 Middle2 的构造函数来调用 Base 的构造函数:
Middle1(int& value) : Base(value) { }
//...
Middle2(int& value) : Base(value) { }
// and then change my constructor of Foo:
Foo(int& value) : Base(value), Middle1(value), Middle2(value) { }
然而,它看起来相当笨拙 - 特别是考虑到由于虚拟继承, Base 构造函数将永远不会被 Middle1 或 Middle2 调用(它们不打算被初始化,即基本上是抽象的 class es)。因此,必须将参数引入到 Middle1 和 Middle2 的构造函数中似乎毫无用处。
有没有其他方法可以编译上述代码而不必在 Middle1 和 Middle2 中引入参数化构造函数?
在虚拟继承中,最派生的 class 必须 直接 调用其所有祖先构造函数。由于 Base
没有默认构造函数,如果 Middle1()
和 Middle2()
不能将 int&
传递给 Base()
,则它们无法编译。
但是,在您显示的代码中,Base()
没有理由引用 int
。改为按值传递,然后 Middle1()
和 Middle2()
可以将 0 传递给 Base()
:
class Base
{
private:
int value;
protected:
Base(int value = 0) { this->value = value; }
};
class Middle1 : virtual public Base
{
protected:
Middle1() { }
};
class Middle2 : virtual public Base
{
protected:
Middle2() { }
};
class Foo : public Middle1, public Middle2
{
public:
Foo(int value) : Base(value) { }
};
不过,我建议改为传递指针(或 std::optional
):
class Base
{
private:
int value;
protected:
Base(int* avalue = nullptr) { if (avalue) this->value = *avalue; }
};
class Middle1 : virtual public Base
{
protected:
Middle1() { }
};
class Middle2 : virtual public Base
{
protected:
Middle2() { }
};
class Foo : public Middle1, public Middle2
{
public:
Foo(int& value) : Base(&value) { }
};