2011-04-22 105 views
1

我在.HPP文件中創建了一個具有虛函數的派生類,然後在類的.CPP文件中給它一個默認返回值。接下來,我創建了一個繼承後一個派生類的類,並重載了它的虛函數,給它一個新的返回值。但是,返回值並不總是相同的(默認返回值或重載返回值)。有人可以幫我修復我的代碼或找到問題。謝謝。C++:派生的虛函數返回奇怪的結果

注意:我提供了示例代碼,我相信這將足以顯示問題。

#include <iostream> 
#include <sstream> 

using std::cout; 
using std::ostream; 

class Fruit; 
class Apple; 

class Fruit 
{ 
    public: 
     int Type; 

     Fruit(); 
     ~Fruit(); 

     Fruit(int = 0); 

     virtual const int getVal() const; 
}; 

class Apple : public Fruit 
{ 
    public: 
     Apple(); 
     ~Apple(); 

     const int getVal() const; 
}; 


Fruit::Fruit() : Type(0) {} 
Fruit::~Fruit() {} 

Fruit::Fruit(int type) : Type(type) {} 

//const int Fruit::getVal() const { return 0; } //Uncommenting this results in function //always returning ZERO; even in Apple::getVal(). 
const int Fruit::getVal() const { return Type; } 

Apple::Apple() : Fruit(1) {} 
Apple::~Apple() {} 

const int Apple::getVal() const { return Type; } 

ostream& operator<<(ostream& a, Fruit b) 
{ 
    return a << b.getVal(); 
} 

int main(int *argc, char **argv) 
{ 
    cout << Apple() << "\n\n"; 

    #ifdef _WIN32 
     system("pause"); 
    #endif 

    return 0; 
}
+0

您不能重載或覆蓋返回類型。 (但是在你提供的代碼中,你似乎試圖做到這一點,你的代碼與解釋不符。幸運的是,你的理論不在基地,正如答案所解釋的那樣:D) – 2011-04-22 03:33:38

回答

2
ostream& operator<<(ostream& a, Fruit b) 

此代碼使用定義爲Fruit(const Fruit&);的構造函數構造一個類型爲Fruit的新對象。

一個AppleFruit,因此它可以作爲參數傳遞給水果拷貝構造函數,然而,Fruit拷貝構造函數使得普通Fruit無論水果的你提供的子類,你因此將只得到一個定期Fruit。這有點混亂地稱爲「切片」。

相反,您可能想要定義您的運算符以接受一個const引用,所以不使用複製構造函數。像這樣,ostream& operator<<(ostream& a, const Fruit& b)

我也建議,宣佈在水果類(未使用)的私人部分的拷貝構造函數和賦值運算符,這樣就可以永遠不小心犯了這個錯誤再次

+1

術語「切片」如何混淆?您可以刪除派生數據。 – 2011-04-22 03:37:09

+0

我沒有看到一個原因,語義上,以防止複製的對象。它會顯示出這個錯誤,但這不一定是一個很好的理由。 +1爲您的答案的其餘部分。 – 2011-04-22 03:38:07

+0

謝謝Slavik81和其他人的解決方案。該解決方案已得到很好的解釋,並解決了問題。我將在未來意識到「對象切片」的可能性。 – Michael 2011-04-22 03:38:34

6

你遇到了一個叫做object slicing的問題。由於您的Apple正在按值傳遞到您的operator<<,因此只有該對象的Fruit部分正在被複制。因此,當調用getVal時,它將在基類Fruit上被調用,而不是在Apple上調用。

要解決這個問題,請確保在處理基類時使用引用(或指針)而不是值。例如,這裏的解決方法是簡單地採取const Fruit&而不僅僅是Fruit

ostream& operator<<(ostream& a, const Fruit& b) 
{ 
    return a << b.getVal(); 
} 

正如維基百科條目所說,這個問題在C++中出現,因爲「按值賦值不是多態」。

0

你遇到了切片問題。您的operator<<正在拍攝該對象的副本,而不是對該對象的引用。既然你沒有定義一個拷貝構造函數,編譯器爲你做了一個拷貝構造函數,並且它做了錯誤的事情。

+0

好吧,它正在做正確的事。這與OP_meant_要求它做的不一樣。 – 2011-04-22 03:35:46

0

有一件事很快就會跳出來,就是你沒有通過指針調用getVal(),並且因爲你的operator<<需要一個Fruit而不是Apple,所以它有效地切掉了對象的派生部分。改爲使用Fruit&作爲operator<<的參數。

0

更改此: ostream& operator<<(ostream& a, Fruit b) { return a << b.getVal(); } 對此: ostream& operator<<(ostream& a, const Fruit& b) { return a << b.getVal(); } 它應該工作。

在您的實施中,您正在構建Apple的全新水果實例。 然後調用Fruit :: getVal()。