2013-12-18 86 views
2

比方說,我們有:虛擬函數重載

Class A 
{ 
public: 
    virtual void print(){ std::cout<<" A "<<endl; } 
} 

Class B : public A 
{ 
public: 
    virtual void print(int x){ std::cout<<" B "<<endl;} 

} 

我認爲,在打印功能將隱藏A類功能打印的B級定義,但下面的代碼工作,並打印「A」

int main() 
{ 

A * a = new B; 

a->print(); 

return 0; 
} 

如果我寫這樣它不工作的主要功能:

int main() 
{ 

B b; 

b.print(); 

return 0; 
} 

我想要什麼到k現在是...在我的第一個main()示例中,我有一個調用print()的B對象...應該然後print()被隱藏,並且在第二個main()示例中有一個錯誤

+1

你有一個指向'A'的指針,所以你得到'A'的接口。 – juanchopanza

+0

但我有一個B對象,並且該函數是虛擬的... – dragosb

+3

重載發生在這裏,因爲方法簽名是不同的。您*不*重寫相同的虛擬功能。 – greatwolf

回答

2

這裏的問題是名稱查找。在類似於A *a = new B; a->print()的調用中,編譯器查看a的類型,即A*,並在A類中查找名爲print的成員函數。它找到它並稱之爲它。類似地,對於B *b = new B; b->print();,編譯器在類B中查找名爲print的成員函數;它發現print(int),它不能被調用沒有參數。並且因爲它在B中找到了一個名爲print的函數,它停止查找;它不會進入A找到A::print()。這是名稱隱藏。

這裏的關鍵是名稱查找以對象的聲明類型開始;在這兩個例子中,類型分別是A*B*。查找確實是而不是注意指針或引用指向或引用的事物的實際類型。

+0

最後有人誰理解這個問題,並給出了一個很好的答案...非常感謝你:) – dragosb

+0

@dragosb - 不客氣。 –

6

成員函數print()B不會覆蓋print()A,因爲它具有不同的簽名。因此,在您的第一個未編輯的main()版本中調用print()時,只有一個匹配函數可以調用,正如用戶juanchopanza指出的那樣:A::print()

編輯:總結:

  • 多態行爲:如果A::print()B::print()有相同的簽名,相應print()將在運行時,只要你引用通過指針或引用的對象選擇。

  • 函數重載:由於一個類是一個範圍和功能不跨範圍過載,從基類的功能由在派生類的同名函數隱藏。爲此,類型的變量用於指示您的對象是重要的,不是對象本身的類型。因此,在第二個示例中,您會看到一個錯誤,指出沒有匹配的函數可以調用,但在第一個示例中,只有一個函數在範圍內。

+0

沒有「最佳匹配」,只能通過'A'的接口調用'print()',並且只能通過'B'的接口調用'print(int)'。 – juanchopanza

+0

@ juanchopanza:你說得對,謝謝你,我糾正了我的答案。 – blackbird

1

這是因爲兩個print()函數具有不同的簽名。兩個功能 - print()print(int)被認爲是不同的,並且不能被超載相互覆蓋。

+2

他們不**重載**,因爲它們被定義在不同的範圍。簽名的不同在於'B :: print'不能覆蓋**'A :: print'。 –

+0

@PeteBecker當然可以。這兩個詞對於非本地人來說太相似了:) –

+0

他們看起來很像,不是嗎? '' –

1

在派生類中命名的重載函數是將這些從基類中隱藏起來。但是,您需要使用派生類接口來查看:

B b; 
b.print(); // won't work 
+0

我知道這個......但是如果我使用調用虛函數的B對象......在這種情況下發生了什麼? – dragosb

+0

爲什麼'b.print()'不起作用? 'B'繼承''''print()'函數就好了。它仍然會打印「A」。 – arne

+1

@arne因爲'B :: print'隱藏'A :: print'。 – juanchopanza

0

檢查您的類定義; AB中的打印功能具有不同的簽名。當你調用

a->print(); 

這裏只有一個適合該簽名,這是A::print()功能。如果您從B的定義中刪除int參數,則應該觀察您期望的行爲。