学习C++:返回引用并绕过切片

JnB*_*ymn 11 c++ polymorphism reference object-slicing

我有一个时间了解参考的魔鬼.请考虑以下代码:

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();
}
Run Code Online (Sandbox Code Playgroud)

结果是:"树皮树皮rawr rawr".

用Java的思维方式(显然已经破坏了我对C++的概念化),结果将是"树皮树皮树皮".我从前一个问题中了解到,这种差异是由切片引起的,我现在对切片的理解有了很好的理解.

但是,让我们说我想要一个返回Animal值的函数,它实际上是一个Dog.

  1. 我是否正确理解我能得到的最接近的参考
  2. 此外,使用rFunc接口的人是否有责任看到返回的引用分配了一个Animal&?(或以其他方式故意将对动物的引用分配给动物,通过切片,丢弃多态性.)
  3. 我究竟应该如何返回对新生成的对象的引用而不执行我在rFunc中执行的愚蠢操作?(至少我听说这是愚蠢的.)

更新:因为到目前为止每个人似乎都同意rFunc它是非法的,这带来了另一个相关的问题:

如果我传回指针,如果是这种情况,我如何与程序员沟通指针不是他们要删除的?或者,我如何传达指针在任何时候(来自同一个线程但是不同的函数)都要删除,以便调用函数不应该存储它,如果是这种情况.是通过评论进行沟通的唯一方法吗?这似乎很草率.

注意:所有这些都导致了我正在研究的模板化shared_pimpl概念的想法.希望我能学到足够的东西,在几天内发布一些相关信息.

Dan*_*lau 5

1)如果你正在创建新对象,你永远不想返回一个引用(参见你自己对#3的评论.)你可以返回一个指针(可能用std::shared_ptr或包裹std::auto_ptr).(您也可以通过复制返回,但这与使用new运算符不兼容;它也与多态性略有不兼容.)

2)rFunc是错的.不要那样做.如果您曾经new创建过该对象,则通过(可选地包装)指针返回它.

3)你不应该这样做.这就是指针的用途.


编辑(回复您的更新:)很难描绘您所描述的场景.一旦调用者调用其他(特定)方法,返回指针可能无效会更准确吗?

我建议不要使用这样的模型,但如果你绝对必须这样做,并且你必须在你的API中强制执行,那么你可能需要添加一个间接级别,甚至两个.示例:将实际对象包装在包含实际指针的引用计数对象中.null删除实际对象时,引用计数对象的指针被设置为.这很难看.(可能有更好的方法,但它们可能仍然很难看.)