2013-06-05 78 views
0

我正在學習關於對象切片的難題,我想知道是否有可能對指針進行對象切片。換句話說:指針和對象切片

  • 指針可以是對象切片的受害者,或者只要您使用指針,您總是可以安全地使用對象切片?
+1

你可能會從這裏學到最好的:http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c – chris

+3

我喜歡你如何提出矛盾的問題'指針可以是對象切片的受害者?'和'只要你使用了一個指針,你總是可以避免對象切片?'。這使得答案混淆。 – milleniumbug

回答

3

是 - 指針base需要能夠指從base派生的任何類型的對象,並仍保持正確的類型派生對象(以及它的價值,也是同樣的道理與參考)。

+3

「是的,它總是安全的。」他的問題承認不是「是」或「否」的答案。 –

7

這取決於你是否願意定義「切片」的鬆散程度。從某種意義上講,當你指向一個帶有基指針(或引用)的派生對象時,任何非虛函數都會被切分。例如:

class A { 
    void Print() { cout << "Class A\n"; } 
}; 

class B : public A { 
    void DoB() {} 
    void Print() { cout << "Class B\n"; } 
}; 

B b; 
A* a = &b; 
a->DoB(); // Won't compile! 
a->Print(); // Prints "Class A", not "Class B" 

,因爲我們使用的指針A,所以編譯器不知道它可以對指針調用DoBDoB調用不起作用。這樣,你就失去了B的一部分,所以你可以把它當作切片的一種形式。

最後一行特別是一個稱爲「名稱隱藏」現象的例子。由於Print未在基類中聲明爲virtual,而我們的指針類型爲A,編譯器不知道它應該調用B::Print而不是A::Print

這個問題的一個重要例子進場時你的析構函數:

class A { 
    ~A() {} 
}; 

class B : public A { 
    std::vector<int> v; 
}; 

A* a = new B; 
delete a; // What happens to B::v? Undefined behaviour! 

這裏,因爲析構函數沒有被標記爲virtual,它被稱爲基類的在非虛擬上下文析構函數,這意味着B的析構函數不會被調用。

+0

哇,這是一個很好的答案。非常豐富。謝謝! –