2011-11-26 46 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