使用new操作符在不知道对象类型的情况下将其复制到堆中

Using new operator for copy an object to heap without knowing its type

本文关键字:复制 情况下 操作符 new 不知道 类型 对象 使用      更新时间:2023-10-16

我有一个疑问,下面的函数是否可以接收a类型的对象或派生类型的对象

A *copyToHeap(A &obj) {
    A *ptr=new A(obj);
    return ptr;
}

如果我们这样称呼它:

//B inherits from A
B bObj;
B *hPtr=copyToHeap(bObj);

hPtr指向的对象实际上是A型还是B型?这样做安全吗?

当您在代码中执行以下操作时:

A* ptr = new A(obj);

总是得到一个A实例。obj将被视为A,并基于obj的"A部分"创建一个新的A。

更好的方法是如前面的回复所指出的,向基类添加一个虚拟MakeCopy方法,并为派生类实现它。

virtual A* MakeCopy();

这个方法是通过复制调用它的对象来实现的。然后在派生类中实现它,所以如果你有一个A指针实际上是一个B对象,你将得到一个真正的B副本,并避免在你的例子中发生的"切片"。

返回的对象类型为pointer to A,即hPtr所指向的对象类型为A。这是不安全的,因为调用B独占的方法或成员将导致崩溃或未定义行为。您可能正在寻找工厂模式。

一种安全的方法是提供虚拟克隆方法

#include <memory>
class Base
{
public:
    virtual std::unique_ptr<Base> Clone() = 0;
};
class Derived : public Base
{
public:
    Derived(int i) : i_(i)
    {
    }
    std::unique_ptr<Base> Clone()
    {
        return std::unique_ptr<Derived>(new Derived(i_));
    }
private:
    int i_;
};

std::unique_ptr<Base> copyToHeap(std::unique_ptr<Base> obj) 
{
    return obj->Clone();
}

这是不安全的,它是不正确的,编译器应该给你一些诊断。如果使用GCC,您是否尝试使用g++ -Wall进行编译?

无法编译:

B *hPtr=copyToHeap(bObj); //error: invalid conversion from ‘A*’ to ‘B*’

如果您将hPtr的类型更改为A*,它会编译,但您仍然得到A对象。您使用的A的默认复制构造函数将创建A对象并复制A中定义的B对象的字段,将B部分切掉。

因为这篇文章中描述的所有问题——如果你能避免它(我想不出为什么你不能)——你不应该设计你的代码来要求"copyToHeap"。

正如Luchian指出的,你可能想要一个工厂。工厂首先在堆上创建对象(并返回一个智能指针来管理对象/指针/内存的生命周期)。

相关文章: