按引用传递总是避免切片问题吗?

Does passing by reference always avoid the slicing issue?

本文关键字:问题 切片 按引用传递      更新时间:2023-10-16

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

#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

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

我只是想确定,这应该发生还是它是那些"它在我的机器上工作"类型的实例之一?

"切片"是指基复制构造函数无法从派生类中区分精确的类型匹配。调用切片的唯一方法是调用基复制构造函数。这种情况通常发生在按值传递参数时,不过也可以设计其他情况:

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
}

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

您所看到的行为是正确的。这就是它的工作原理。引用的作用就像指针。

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

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

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

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