2011-04-22 52 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()。