2011-11-26 65 views
7

这让我感到有点惊讶,但是我正在玩弄一些代码,发现至少在我的电脑上,当函数通过引用接受父类并传递子实例时,切片问题不会'发生。举例说明:通过引用传递总是避免切片问题?

#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

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

我只是想确认一下,这是否应该发生,或者它是那些“它适用于我的机器”类型的实例?

+0

这不是什么“切片”。此外,该代码甚至编译?什么是'使用std;'? –

+0

表示它是'使用命名空间std'。我想我能够明白这一点,但是清理了代码,以使整个网站受益。 – Anthony

回答

9

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

+0

谢谢,这就是我的想法。就像我刚才提到的,我只是想要一个完整的检查,所以我没有做出无效的假设。 – Anthony

2

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

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

3

这应该发生。通过引用传递完全像传递指针 - 它在引擎盖下做同样的事情。这没有什么魔力;每个多态对象的实例都有一个与之关联的虚函数表。只要你不复制任何东西,你就不会失去这些信息,你的虚函数调用将按照你期望的方式工作。

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

11

“切片”是指基本复制构造函数无法区分来自派生类的精确类型匹配。调用切片的唯一方法是调用基本拷贝构造函数。通常,此按值传递参数时出现,但其他情况可以做作:

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

当通过值传递时提到复制构造函数是使此答案完美的原因。 – dani