我有一个疑问,下面的函数可以接收类型为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类型的对象?
这样做安全吗?
答案 0 :(得分:7)
在代码中执行以下操作时:
A* ptr = new A(obj);
你总会得到一个A实例。 obj将被视为A,新的A将根据obj的“A部分”创建。
更好的方法是在早期的回复中指出,将虚拟MakeCopy方法添加到基类并为派生类实现它。
virtual A* MakeCopy();
通过制作被调用对象的副本来实现此方法。然后它在派生类中实现,所以如果你有一个实际上是B对象的A指针,你将得到一个真正的B副本,并避免在你的例子中出现“切片”。
答案 1 :(得分:5)
返回的对象的类型为pointer to A
,这意味着hPtr
指向的对象的类型为A
。这是不安全的,因为调用B独有的方法或成员将导致崩溃或未定义的行为。您可能正在寻找factory pattern。
答案 2 :(得分:3)
安全的方法是提供虚拟克隆方法
#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();
}
答案 3 :(得分:1)
它不安全,不正确,编译器应该给你一些诊断。如果使用GCC,您是否尝试使用g++ -Wall
进行编译?
答案 4 :(得分:1)
不编译:
B *hPtr=copyToHeap(bObj); //error: invalid conversion from ‘A*’ to ‘B*’
如果您将hPtr
的类型更改为A*
,则会进行编译,但您仍会获得A
个对象。您使用的A
的默认复制构造函数将创建一个A
对象,并复制B
对象的字段,这些字段在A
中定义,切片{{1}部分关闭。
答案 5 :(得分:0)
由于上述/本文所述的所有问题 - 如果有的话你可以避免它(我想不出你为什么不能这样做的原因) - 你不应该设计你的代码要求“ copyToHeap
”。
正如Luchian指出的那样,你可能想要一家工厂。工厂在堆上创建您的对象以开始(并返回一个智能指针来管理对象/指针/内存的生命周期)。