我们可以在 C++ 中将类复制构造函数设为虚拟吗?如何使用?
不,你不能,构造函数不能是虚拟的。
C++03 - 12.1 构造函数
4) 构造函数不得为
(10.3) 或virtual
(9.4)。 [...]static
如果您需要这样的东西,您可以在here查找虚拟构造函数习惯用法。
不,你不能。
此外,整个概念没有意义。虚函数是根据对象的值(对象的动态类型)分派的函数。当构造函数被调用时,对象还没有值(因为它还没有被构造)。因此,不可能发生虚拟调度。
想一想。这样的构造函数有什么语义?
不。 C++ 是静态类型语言,对于 C++ 编译器来说,多态地创建对象是没有意义的。编译器必须知道类类型才能创建对象。换句话说,从 C++ 编译器的角度来看,要创建什么类型的对象是编译时决定的。如果我们将构造函数设为虚拟,编译器会标记一个错误。
不能,因为在调用构造函数之前,内存是根据新类型的大小而不是复制操作数分配的。如果它确实有效,那将是一种特殊情况,可以反转许多语言结构的多态性。
但这并不意味着它不能通过一点 C++ 魔法来完成。 :)
在某些情况下它非常有用,例如序列化非 POD 类。此示例创建一个使用placement new 工作的虚拟复制构造函数。
警告:这是一个示例,可以帮助某些用户解决特定问题。不要在通用代码中执行此操作。如果为新类分配的内存小于派生类,它将崩溃。使用此功能的最佳(也是唯一)安全方法是,如果您正在管理自己的班级内存并使用新的放置。
class VirtualBase
{
public:
VirtualBase() {}
virtual ~VirtualBase() {}
VirtualBase(const VirtualBase& copy)
{
copy.VirtualPlacementCopyConstructor(this);
}
virtual void VirtualPlacementCopyConstructor(void*) const {}
};
class Derived :: public VirtualBase
{
public:
...
Derived(const Derived& copy) : ... don't call baseclass and make an infinite loop
{
}
protected:
void VirtualPlacementCopyConstructor(void* place) const
{
new (place) Derived(*this);
}
};
永远不会,这在 C++ 中是不可能的。
与标准委员会关系密切的人员正在研究的解决方案是
value_types
提案。
https://github.com/jbcoe/value_types
例如,下面的代码显示了复制多态类型,而无需编写任何额外的
clone
或 deepcopy
虚拟成员。要求只是将对象构造成一个 polymorphic
包装器,它捕获真实类型的构造函数。
https://godbolt.org/z/1fbxE7Pxc
#include <https://raw.githubusercontent.com/jbcoe/value_types/main/indirect.h>
#include <https://raw.githubusercontent.com/jbcoe/value_types/main/polymorphic.h>
#include <vector>
#include <utility>
class Base {
public:
Base(){}
virtual int foo() = 0;
virtual ~Base() = default;
};
class Child : public Base {
public:
Child(int _x):x(_x){}
int foo() override { return x;}
int x;
};
class Child2 : public Base {
public:
Child2(int _y):y(_y){}
int foo() override { return y;}
int y;
};
int main()
{
std::vector<xyz::polymorphic<Base>> vec;
vec.push_back(xyz::polymorphic<Base>(Child(189)));
vec.push_back(xyz::polymorphic<Base>(Child(97)));
vec.push_back(xyz::polymorphic<Base>(std::in_place_type_t<Child2>{},66));
assert(vec[0]->foo() == 189);
assert(vec[1]->foo() == 97);
assert(vec[2]->foo() == 66);
auto b = vec;
assert(b[0]->foo() == 189);
assert(b[1]->foo() == 97);
assert(b[2]->foo() == 66);
}
是的,您可以创建虚拟复制构造函数,但不能创建虚拟构造函数。
原因:
虚拟构造函数:- 不可能,因为 c++ 是静态类型语言,并将构造函数创建为虚拟,因此编译器将无法决定它的对象类型,并由于 virtual 关键字而将整个过程留给运行时。 编译器必须知道类类型才能创建对象。换句话说,从 C++ 编译器的角度来看,要创建什么类型的对象是编译时决定的。如果我们将构造函数设为虚拟,编译器会标记错误。
虚拟复制构造函数:- 是的可能,考虑剪贴板应用程序。剪贴板可以保存不同类型的对象,并从现有对象中复制对象,将它们粘贴到应用程序画布上。同样,要复制什么类型的对象是运行时决定的。虚拟复制构造函数填补了这里的空白。