2011-04-14 63 views
2

Bar和Box是Foo的派生類,Foo具有虛函數F()和Bar和Box都具有函數F()。據我所知,多態性正確地允許Bar.F()而不是Box.F()或Box.F()而不是Bar.F()使用某些運行時例程覆蓋Foo.F()而不知道對象是否一個酒吧或一個盒子。這件事情是這樣的:C++我能正確理解多態嗎?

Foo * boxxy = new Box;
boxxy->F();

最後一行將調用正確的F()(在這種情況下,Box.F())獨立的boxxy是否是盒或酒吧或美孚(以這種情況下調用虛擬Foo.F()的實現)。

我理解這個權利嗎?如果boxxy是Box指針,會發生什麼變化?如果派生類不具有F()的覆蓋會發生什麼?最後,爲了避免爲一個基類實現一個函數,但仍然允許多態,你只需寫一個空函數體並聲明它是虛擬的?謝謝。

回答

2

接近直角的 - 考慮這個繼承樹:

 Foo 
    / \ 
    Bar Box 

如果你現在做這樣一個指針:

Bar* barry = new Box(); 

你會得到一個nice compiler error,因爲Box不能被轉換爲Bar。 :)
所以它只有Foo<->BarFoo<->Box,從來沒有Bar<->Box。 接下來,當boxxyBox指針時,它將只會調用Box::F函數(如果提供)。
而在去年,強迫子類實現特定的功能,您聲明它pure virtual,像這樣:

virtual void Func() = 0; 
// note this --- ^^^^ 

現在子類(在這種情況下BarBox),必須實現Func,否則他們將失敗編譯。

+0

非常感謝。出於好奇,你可以使用NULL代替0對嗎? – 2011-04-14 15:55:43

+0

@Brandon:不,不是在聲明純虛函數時。所需的exakt標記是'= 0',沒有別的。另外,我鼓勵你使用'0'而不是'NULL',並且當C++ 0x出現時,使用'nullptr'作爲指針。 :) – Xeo 2011-04-14 15:56:57

0
  • 我理解這個權利嗎?是的,如果該函數被聲明爲虛函數。
  • 如果boxxy是一個Box 指針,會發生什麼變化?取決於 函數是否是虛擬的。一個虛擬的 函數將總是最終調用 正確的派生函數;一個非虛函數 將根據 指針的類型調用 版本。
  • 如果派生類 沒有覆蓋F()會發生什麼?它 將使用基類定義。
  • 最後,爲了避免爲一個基類實現一個 函數,但仍然允許多態性,您是否只寫 一個空函數體並聲明它爲 虛擬?您還可以聲明純 虛擬:virtual void F() = 0。任何想要實例化 類的 類都會覆蓋此 函數,並給它一個合適的 實現。
1

是的,根據您通過Foo指針創建的對象的類型調用正確的F()。

如果boxxy是一個Box指針,你只能稱它爲F()或它的派生類的F()之一,除非你對它的父類做了dynamic_cast,然後調用F()。

爲了避免在基類來實現它定義爲純虛像這樣:

class Foo 
{ 
public: 
    virtual void F() = 0; //notice the = 0, makes this function pure virtual. 

}; 
1

如果boxxy爲Box 指針什麼樣的變化?

它將允許訪問Box不從Foo繼承的方法。因爲Bar不是從Box派生的,所以Box指針不能指向Bar對象。

而且如果派生類 沒有適用於F的覆蓋(會發生什麼)?

它將從基類繼承F()的實現。

最後,以避免實施 函數的基類,但仍然 允許多態,你只是寫 一個空的函數體,並宣佈它 虛擬?

它會工作,但它不是做多態的正確方法。如果你不能爲基類的虛擬函數提供一個具體的實現來使該函數成爲純虛函數,那麼不要將其實現爲空函數。

1

如果聲明美孚這樣

class Foo 
{ 
private: 
    Foo() {}; 
public: 
    void func() const { std::cout << "Calling Foo::func()" << std::endl; } 
}; 

和酒吧這樣

class Bar : public Foo 
{ 
private: 
    Bar() {}; 
public: 
    void func() const { std::cout << "Calling Bar::func()" << std::endl; } 
}; 

然後

Foo* bar = new Bar(); 
bar->func(); 

將調用foo :: FUNC()。

如果聲明美孚這樣

class Foo 
{ 
private: 
    Foo() {}; 
public: 
    virtual void func() const { std::cout << "Calling Foo::func()" << std::endl; } // NOTICE THE virtual KEYWORD 
}; 

然後

Foo* bar = new Bar(); 
bar->func(); 

會打電話吧:: FUNC()。