使用new操作符在不知道对象类型的情况下将其复制到堆中
Using new operator for copy an object to heap without knowing its type
我有一个疑问,下面的函数是否可以接收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指出的,你可能想要一个工厂。工厂首先在堆上创建对象(并返回一个智能指针来管理对象/指针/内存的生命周期)。
相关文章:
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 在不复制临时对象的情况下延长其生存期
- 在这种情况下,我真的复制了字节还是复制了字符?
- QT QOpenGLWidget:如何在不使用数据块复制的情况下修改VBO中的单个顶点值?
- 如何在不复制的情况下将一个向量移动到另一个向量中
- 如何在没有复制构造函数的情况下为地图设置值?
- 在这种情况下,使用 string_view 是否会导致不必要的字符串复制?
- 我有两棵二叉树.我想在不更改输入树的情况下深度复制两个二叉树的结果
- 如何在不复制的情况下操作 QByteArray 对象?
- 在不复制数据的情况下,将double数组转换为只有double成员的structs数组
- 有没有一种方法可以在不复制数据的情况下从string_view创建字符串流
- 是否可以在不复制的情况下访问undered_map中的元素
- 如何在不复制数据的情况下将 cv::Mat 转换为 2d 标准::矢量
- 如何在不复制列表的情况下将列表传递给线程,同时销毁原始列表
- 是否有可能在没有复制的情况下传递 std::vector<int> 作为参数来获得 std::vector<std::array<int, 3>>?
- 是否可以在不显式迭代每个元素的情况下深度复制指针容器?
- 如何在不复制此代码的情况下将多个函数放入多个命名空间?
- 父类有 26 个构造函数重载.如何在不复制+粘贴 26 个重载的情况下将一个小任务附加到所有构造器?
- 如何在自定义删除器的情况下复制unique_ptr
- 如何在不复制的情况下比较字符串的一部分?