c++ - 学习 C++ : returning references AND getting around slicing

标签 c++ reference polymorphism 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();
}

结果是:“bark bark rawr rawr”。

以 Java 的思维方式(这显然破坏了我对 C++ 的概念化),结果将是“bark bark bark bark”。我从我的 previous question 了解到这种差异是由于切片造成的,我现在对切片是什么有了很好的理解。

但是假设我想要一个返回真正是狗的 Animal 值的函数。

  1. 我是否正确理解我能得到的最接近的是引用
  2. 此外,使用 rFunc 接口(interface)的人是否有义务查看返回的引用是否分配了一个 Animal&? (或以其他方式故意将引用分配给 Animal,它通过切片丢弃多态性。)
  3. 我到底应该如何返回对新生成的对象的引用而不做我上面在 rFunc 中做的愚蠢的事情? (至少我听说这是愚蠢的。)

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

如果我传回一个指针,如果是这种情况,我如何与程序员沟通该指针不是他们要删除的指针?或者我如何传达指针随时可能被删除(从同一个线程但不同的函数),以便调用函数不应该存储它,如果是这种情况。是通过评论传达这一点的唯一方法吗?这看起来很草率。

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

最佳答案

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

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

3) 你不应该这样做。这就是指针的作用。


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

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

关于c++ - 学习 C++ : returning references AND getting around slicing,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4405634/

相关文章:

c++ - 构造函数依赖注入(inject) : unique_ptr + move vs shared_ptr

c++仿函数和函数模板

c++ - 如果容器不是调用函数中的引用,则使用 std::thread 传递对迭代器的引用失败

java - Jackson 将对象字段误认为是 JsonTypeInfo.Id.NAME

c++ - std::accumulate 的迭代器

c++ - 为什么我的程序会因大值而不是小值而导致程序崩溃?

c++ - 返回指向引用的指针

python - 如何使用 Boost Python 将 Python 派生类升级到它的 c++ 基类?

ruby-on-rails - Rails 多态命名边缘情况

c# - C# EmguCV Image.setValue(...) 方法的 C++ OpenCV 等价物