c – 您是否需要从所有派生类调用虚拟基类构造函数?即使他们不是最衍生的?
作者:互联网
我在多重继承和钻石问题上遇到了麻烦.
出现此问题是因为我的基类构造函数需要一个参数.编译器尝试为我的两个抽象类生成默认构造函数,但这会失败,因为默认构造函数无法确定基类的参数.
我不明白为什么我的抽象类调用基础构造函数.我认为最派生的类是调用虚基类构造函数的类.
这是重现我正在谈论的代码:
class VirtualBase
{
public:
VirtualBase(int initial) :
count(initial)
{}
int getCount() const
{
return count;
}
void increment()
{
count++;
}
private:
int count;
};
class ContractA : public virtual VirtualBase
{
public:
virtual void doSomething() = 0;
};
class ContractB : public virtual VirtualBase
{
public:
virtual void doSomethingElse() = 0;
};
class Concrete : public ContractA, public ContractB
{
public:
Concrete() :
VirtualBase(0)
{}
virtual void doSomething()
{
increment();
}
virtual void doSomethingElse()
{
// etc...
}
};
int main()
{
Concrete concrete;
concrete.doSomething();
concrete.doSomethingElse();
return 0;
}
我收到以下错误(对于每个合同):
main.cpp: In constructor ‘ContractA::ContractA()’:
main.cpp:29:7: error: no matching function for call to ‘VirtualBase::VirtualBase()’
class ContractA : public virtual VirtualBase
^
main.cpp:29:7: note: candidates are:
main.cpp:9:3: note: VirtualBase::VirtualBase(int)
VirtualBase(int initial) :
^
main.cpp:9:3: note: candidate expects 1 argument, 0 provided
main.cpp:4:7: note: VirtualBase::VirtualBase(const VirtualBase&)
class VirtualBase
^
main.cpp:4:7: note: candidate expects 1 argument, 0 provided
main.cpp: In constructor ‘Concrete::Concrete()’:
main.cpp:53:17: note: synthesized method ‘ContractA::ContractA()’ first required here
VirtualBase(0)
^
解决方法:
你的例子用EDG和clang编译,但它不用gcc编译.我不确定代码是否应该按原样编译,因为似乎抽象基类的构造函数被声明为已删除:根据12.1 [class.ctor]第4段,第6个子弹,如果任何子对象没有默认构造函数,则默认的默认构造函数被声明为已删除:
… A defaulted default constructor for class X is defined as deleted if:
…
- …
- any potentially constructed subobject, except for a non-static data member with a brace-or-equalinitializer, has class type
M
(or array thereof) and eitherM
has no default constructor or overload resolution (13.3) as applied toM
’s default constructor results in an ambiguity or in a function that is deleted or inaccessible from the defaulted default constructor, or- …
对于具有虚拟基础的类而言,对于虚拟基础的创建没有特殊豁免,即,将删除默认的默认构造函数.
对于抽象类,显然不必从构造函数成员初始化列表中调用虚拟基础.至少,这就是12.6.2 [class.base.init]第8段根据其说明所说的:
In a non-delegating constructor, if a given potentially constructed subobject is not designated by a meminitializer-id (including the case where there is no mem-initializer-list because the constructor has no ctorinitializer), then
- if the entity is a non-static data member that has a brace-or-equal-initializer and either
- the constructor’s class is a union (9.5), and no other variant member of that union is designated by a mem-initializer-id or
- the constructor’s class is not a union, and, if the entity is a member of an anonymous union, no other member of that union is designated by a mem-initializer-id, the entity is initialized as specified in 8.5;
- otherwise, if the entity is an anonymous union or a variant member (9.5), no initialization is performed;
- otherwise, the entity is default-initialized (8.5).
[ Note: An abstract class (10.4) is never a most derived class, thus its constructors never initialize virtual base classes, therefore the corresponding mem-initializers may be omitted. — end note ] …
最衍生基础的相关部分在12.6.2第7段,最后一句:
… A mem-initializer where the mem-initializer-id denotes a virtual base class is ignored during execution of a constructor of any class that is not the most derived class.
标签:diamond-problem,c,inheritance,abstract-class,multiple-inheritance 来源: https://codeday.me/bug/20190724/1524784.html