我们可以在C++中将类复制构造函数设为虚拟吗

问题描述 投票:0回答:7

我们可以在 C++ 中将类复制构造函数设为虚拟吗?如何使用?

c++ constructor virtual
7个回答
34
投票

不,你不能,构造函数不能是虚拟的。

C++03 - 12.1 构造函数

4) 构造函数不得为

virtual
(10.3) 或
static
(9.4)。 [...]

如果您需要这样的东西,您可以在here查找虚拟构造函数习惯用法。


6
投票

不,你不能。

此外,整个概念没有意义。虚函数是根据对象的值(对象的动态类型)分派的函数。当构造函数被调用时,对象还没有值(因为它还没有被构造)。因此,不可能发生虚拟调度。

想一想。这样的构造函数有什么语义?


2
投票

不。 C++ 是静态类型语言,对于 C++ 编译器来说,多态地创建对象是没有意义的。编译器必须知道类类型才能创建对象。换句话说,从 C++ 编译器的角度来看,要创建什么类型的对象是编译时决定的。如果我们将构造函数设为虚拟,编译器会标记一个错误。


2
投票

不能,因为在调用构造函数之前,内存是根据新类型的大小而不是复制操作数分配的。如果它确实有效,那将是一种特殊情况,可以反转许多语言结构的多态性。

但这并不意味着它不能通过一点 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);
    }
};

0
投票

永远不会,这在 C++ 中是不可能的。


0
投票

与标准委员会关系密切的人员正在研究的解决方案是

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);

}

-2
投票

是的,您可以创建虚拟复制构造函数,但不能创建虚拟构造函数。

原因:

虚拟构造函数:- 不可能,因为 c++ 是静态类型语言,并将构造函数创建为虚拟,因此编译器将无法决定它的对象类型,并由于 virtual 关键字而将整个过程留给运行时。 编译器必须知道类类型才能创建对象。换句话说,从 C++ 编译器的角度来看,要创建什么类型的对象是编译时决定的。如果我们将构造函数设为虚拟,编译器会标记错误。

虚拟复制构造函数:- 是的可能,考虑剪贴板应用程序。剪贴板可以保存不同类型的对象,并从现有对象中复制对象,将它们粘贴到应用程序画布上。同样,要复制什么类型的对象是运行时决定的。虚拟复制构造函数填补了这里的空白。

© www.soinside.com 2019 - 2024. All rights reserved.