我有一段时间了解引用文献的魔鬼。考虑以下代码:

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接口(interface)的那个是否有责任看到返回的引用分配了Animal&? (或者有意将引用分配给动物,该动物通过切片会丢弃多态性。)
  • 我到底应该如何返回对新生成对象的引用,而不执行我在rFunc中所做的愚蠢操作? (至少我听说这很愚蠢。)


  • 更新:由于到目前为止每个人似乎都同意rFunc是非法的,因此提出了另一个相关问题:

    如果我传回一个指针,我该如何与程序员沟通该指针不是他们要删除的指针?或者作为替代,我如何在任何时候(从同一线程但有不同的函数)传达指针随时可能被删除的信息,以便在这种情况下调用函数不应存储该指针。通过评论传达此信息的唯一方法是吗?这似乎草率。

    注意:所有这些都导致了我正在研究的模板化shared_pimpl概念的想法。希望我能在几天内学到足够的知识来发表一些有关此的东西。

    最佳答案

    1)如果要创建新对象,则永远不要返回引用(请参阅有关#3的注释。)您可以返回指针(可能由std::shared_ptrstd::auto_ptr包装)。 (您也可以按拷贝返回,但这与使用new运算符不兼容;它也与多态性稍有不兼容。)

    2)rFunc是错误的。不要那样做如果使用new创建对象,则通过(可选包装的)指针将其返回。

    3)您不应该这样做。那就是指针的目的。

    编辑(响应您的更新:)很难描述您描述的场景。说调用者调用其他(特定)方法后返回的指针可能是无效的,这会更准确吗?

    我建议不要使用这样的模型,但是如果您绝对必须这样做,并且必须在API中强制执行此模型,那么您可能需要添加一个或什至两个间接级别。示例:将实际对象包装在包含真实指针的引用计数对象中。当删除真实对象时,引用计数对象的指针设置为null。这很丑。 (也许有更好的方法可以做到,但是它们仍然很丑陋。)

    09-06 10:59