【问题标题】:Does passing by reference always avoid the slicing issue?通过引用传递是否总是避免切片问题?
【发布时间】:2012-01-06 21:37:29
【问题描述】:

这让我有点吃惊,但我正在玩一些代码并发现,至少在我的计算机上,当一个函数通过引用接受父类并且您传递一个子实例时,切片问题不会不会发生。举例说明:

#include <iostream>

class Parent
{
public:
    virtual void doSomething()
    {
        using namespace std;
        cout << "Parent::DoSomething" << endl;
    }
};

class Child : public Parent
{
public:
    virtual void doSomething()
    {
        using namespace std;
        cout << "Child::DoSomething" << endl;
    }
};

void performSomething(Parent& parent)
{
    parent.doSomething();
}

int main(int argc, char** argv)
{
    Child myChild;

    performSomething(myChild);

    return 0;
}

这会打印出Child::DoSomething

就像我说的,我有点惊讶。我的意思是,我知道通过引用传递就像传递指针(但在我的理解中更安全),但我不知道这样做时我仍然必须保持多态性。

我只是想确定一下,这是应该发生的,还是属于“它在我的机器上工作”类型的实例之一?

【问题讨论】:

  • 这不是“切片”的意思。此外,该代码甚至可以编译吗? using std; 是什么?
  • 意思是using namespace std。我认为我能够理解这一点,但为了网站的整体利益,我清理了代码。

标签: c++ polymorphism pass-by-reference


【解决方案1】:

“切片”是指基本复制构造函数无法区分精确类型匹配与派生类。调用切片的唯一方法是调用基本副本构造函数。这通常发生在按值传递参数时,但可以设计其他情况:

class Base { };
class Derived : public Base { };

void foo(Base);

int main()
{
  Derived x;

  Base y = x;   // flagrant slicing
  foo(x);       // slicing by passing by value
}

你从来没有做任何这样的事情,所以你不会遇到任何切片情况。

【讨论】:

  • 按值传递时提及复制构造函数是使这个答案完美的原因。
【解决方案2】:

您看到的行为是正确的。这就是它应该如何工作的方式。引用就像指针一样工作。

【讨论】:

  • 谢谢,我就是这么想的。就像我提到的那样,我只是想要一个健全性检查,所以我没有做出无效的假设。
【解决方案3】:

这是应该发生的。通过引用传递就像传递指针一样——它在底层做同样的事情。这没有什么神奇之处。多态对象的每个实例都有一个与之关联的虚函数表。只要您不复制任何内容,您就不会丢失该信息,并且您的虚函数调用将按照您预期的方式工作。

您在按值传递时遇到问题的原因是它会使用您在函数签名中指定的类型的复制构造函数,因此您最终会得到一个全新的超类实例。

【讨论】:

    【解决方案4】:

    是的,绑定到引用会启用动态绑定。这是由于对象的动态类型和静态类型不同造成的。

    如果您按值获取参数,它将成为Parent 类。虽然如果您通过引用或指针传递某些内容并调用虚函数,运行时将查找被引用的实际对象的 dynamic typemost-derived type

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-11
      • 2018-01-02
      • 2021-05-20
      相关资源
      最近更新 更多