C++ 虚拟基础 类:父的复制构造函数未被调用
C++ virtual base classes: parent's copy constructor doesn't get called
我有三个 类,您可以在下面的代码中看到。请注意我是如何编写复制构造函数的。
#include <iostream>
class Abstract
{
public:
Abstract(){};
Abstract( const Abstract& other ): mA(other.mA){};
virtual ~Abstract(){};
void setA(double inA){mA = inA;};
double getA(){return mA;};
virtual void isAbstract() = 0;
protected:
double mA;
};
class Parent : public virtual Abstract
{
public:
Parent(){};
Parent( const Parent& other ): Abstract(other){};
virtual ~Parent(){};
};
class Child : public virtual Parent
{
public:
Child(){};
Child( const Child& other ): Parent(other){};
virtual ~Child(){};
void isAbstract(){};
};
int main()
{
Child child1;
child1.setA(5);
Child childCopy(child1);
std::cout << childCopy.getA() << std::endl;
return 0;
}
现在为什么在构造 childCopy
时调用 Abstract()
而不是复制构造函数 Abstract( const Abstract& other )
?
Child(other)
不应该调用 Parent(other)
吗? Parent(other)
不应该反过来调用 Abstract(other)
吗?
虚基classes只能由最派生的class初始化。从非最派生的 class 调用虚拟基础的构造函数将被忽略并替换为默认构造函数调用。这是为了确保虚拟基础子对象只被初始化一次:
正确的代码应该将构造函数调用放在最派生的 class' ctor-initializer:
Child(Child const& other)
: Abstract(other) // indirect virtual bases are
// initialized first
, Parent(other) // followed by direct bases
{ }
为了正确调用Abstract
的复制构造函数,您需要在Child
的复制构造函数的初始化列表中指定。
Child( const Child& other ): Abstract(other), Parent(other) {};
这里是标准中的相关引用,其中指出虚拟基 class 的构造函数仅在最派生的 class 中调用。如果缺少,则调用默认构造函数(--如果存在)。
§12.6.2, (13.1):
In a non-delegating constructor, initialization proceeds in the following order:
- First, and only for the constructor of the most derived class (1.8),
virtual base classes are initialized in the order they appear on a
depth-first left-to-right traversal of the directed acyclic graph of
base classes, where “left-to-right” is the order of appearance of the
base classes in the derived class base-specifier-list.
特别是,这就是您注意到 Abstract
的默认构造函数被调用的原因。
然而,为了避免这个陷阱,您可以放弃所有用户定义的复制构造函数并依赖隐式定义的复制构造函数(这总是一个好主意)。 DEMO 2
我有三个 类,您可以在下面的代码中看到。请注意我是如何编写复制构造函数的。
#include <iostream>
class Abstract
{
public:
Abstract(){};
Abstract( const Abstract& other ): mA(other.mA){};
virtual ~Abstract(){};
void setA(double inA){mA = inA;};
double getA(){return mA;};
virtual void isAbstract() = 0;
protected:
double mA;
};
class Parent : public virtual Abstract
{
public:
Parent(){};
Parent( const Parent& other ): Abstract(other){};
virtual ~Parent(){};
};
class Child : public virtual Parent
{
public:
Child(){};
Child( const Child& other ): Parent(other){};
virtual ~Child(){};
void isAbstract(){};
};
int main()
{
Child child1;
child1.setA(5);
Child childCopy(child1);
std::cout << childCopy.getA() << std::endl;
return 0;
}
现在为什么在构造 childCopy
时调用 Abstract()
而不是复制构造函数 Abstract( const Abstract& other )
?
Child(other)
不应该调用 Parent(other)
吗? Parent(other)
不应该反过来调用 Abstract(other)
吗?
虚基classes只能由最派生的class初始化。从非最派生的 class 调用虚拟基础的构造函数将被忽略并替换为默认构造函数调用。这是为了确保虚拟基础子对象只被初始化一次:
正确的代码应该将构造函数调用放在最派生的 class' ctor-initializer:
Child(Child const& other)
: Abstract(other) // indirect virtual bases are
// initialized first
, Parent(other) // followed by direct bases
{ }
为了正确调用Abstract
的复制构造函数,您需要在Child
的复制构造函数的初始化列表中指定。
Child( const Child& other ): Abstract(other), Parent(other) {};
这里是标准中的相关引用,其中指出虚拟基 class 的构造函数仅在最派生的 class 中调用。如果缺少,则调用默认构造函数(--如果存在)。
§12.6.2, (13.1):
In a non-delegating constructor, initialization proceeds in the following order:
- First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
特别是,这就是您注意到 Abstract
的默认构造函数被调用的原因。
然而,为了避免这个陷阱,您可以放弃所有用户定义的复制构造函数并依赖隐式定义的复制构造函数(这总是一个好主意)。 DEMO 2