我有一段时间了解引用文献的魔鬼。考虑以下代码:
class Animal
{
public:
virtual void makeSound() {cout << "rawr" << endl;}
};
class Dog : public Animal
{
public:
virtual void makeSound() {cout << "bark" << endl;}
};
Animal* pFunc()
{
return new Dog();
}
Animal& rFunc()
{
return *(new Dog());
}
Animal vFunc()
{
return Dog();
}
int main()
{
Animal* p = pFunc();
p->makeSound();
Animal& r1 = rFunc();
r1.makeSound();
Animal r2 = rFunc();
r2.makeSound();
Animal v = vFunc();
v.makeSound();
}
其结果是:“树皮树皮rawr rawr”。
用Java的思维方式(显然已经破坏了我对C++的概念化),结果将是“树皮树皮树皮树皮”。我从previous question中了解到,这种差异是由于切片造成的,现在我对切片是什么有了很好的了解。
但是,让我们说我想要一个返回真正是Dog的Animal值的函数。
更新:由于到目前为止每个人似乎都同意rFunc是非法的,因此提出了另一个相关问题:
如果我传回一个指针,我该如何与程序员沟通该指针不是他们要删除的指针?或者作为替代,我如何在任何时候(从同一线程但有不同的函数)传达指针随时可能被删除的信息,以便在这种情况下调用函数不应存储该指针。通过评论传达此信息的唯一方法是吗?这似乎草率。
注意:所有这些都导致了我正在研究的模板化shared_pimpl概念的想法。希望我能在几天内学到足够的知识来发表一些有关此的东西。
最佳答案
1)如果要创建新对象,则永远不要返回引用(请参阅有关#3的注释。)您可以返回指针(可能由std::shared_ptr
或std::auto_ptr
包装)。 (您也可以按拷贝返回,但这与使用new
运算符不兼容;它也与多态性稍有不兼容。)
2)rFunc
是错误的。不要那样做如果使用new
创建对象,则通过(可选包装的)指针将其返回。
3)您不应该这样做。那就是指针的目的。
编辑(响应您的更新:)很难描述您描述的场景。说调用者调用其他(特定)方法后返回的指针可能是无效的,这会更准确吗?
我建议不要使用这样的模型,但是如果您绝对必须这样做,并且必须在API中强制执行此模型,那么您可能需要添加一个或什至两个间接级别。示例:将实际对象包装在包含真实指针的引用计数对象中。当删除真实对象时,引用计数对象的指针设置为null
。这很丑。 (也许有更好的方法可以做到,但是它们仍然很丑陋。)