C ++:派生的虚函数返回奇怪的结果

时间:2011-04-22 03:21:19

标签: c++

我在.HPP文件中创建了一个带有虚函数的可派生类,然后在类的.CPP文件中给它一个默认的返回值。接下来,我创建了一个继承后一个派生类的类,并重载了它的虚函数,给它一个新的返回值。但是,返回值并不总是相同(默认返回值或重载返回值)。有人可以帮我修复我的代码或找到问题。感谢。

注意:我提供示例代码,我相信这足以显示问题。

#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;
}

5 个答案:

答案 0 :(得分:6)

您遇到的问题是object slicing。由于您的Apple正按值传递到operator<<,因此只会复制对象的Fruit部分。因此,当调用getVal时,会在基类Fruit而不是Apple上调用它。

要解决此问题,请确保在处理基类时使用引用(或指针)而不是值。例如,此处的修复方法是简单地使用const Fruit&而不只是Fruit

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

正如维基百科条目所说,这个问题在C ++中出现,因为“按值分配不是多态的”。

答案 1 :(得分:2)

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

此代码使用定义为Fruit(const Fruit&);的构造函数构造Fruit类型的新对象。

AppleFruit,因此它可以用作Fruit复制构造函数的参数,但Fruit复制构造函数会定期Fruit您提供的Fruit的子类,因此您将获得常规Fruit。这有点令人困惑地称为“切片”。

相反,您可能希望定义运算符以获取const引用,因此不使用复制构造函数。像这样,ostream& operator<<(ostream& a, const Fruit& b)

我还建议在水果类的私有部分(未实现)中声明复制构造函数和赋值运算符,这样你就不会再意外地犯这个错误了

答案 2 :(得分:0)

你正在与切片问题发生冲突。您的operator<<正在获取该对象的副本,而不是对该对象的引用。由于你没有定义一个拷贝构造函数,编译器为你做了一个,它做错了。

答案 3 :(得分:0)

快速跳出的一件事是你没有通过指针调用getVal(),并且因为你的operator<<采用Fruit而不是Apple,它有效地切掉了对象的派生部分。请尝试使用Fruit&作为operator<<的参数。

答案 4 :(得分:0)

改变这个: ostream& operator<<(ostream& a, Fruit b) { return a << b.getVal(); } 对此: ostream& operator<<(ostream& a, const Fruit& b) { return a << b.getVal(); } 它应该工作。

在您的实施中,您正在构建Apple的全新Fruit实例。 所以调用Fruit :: getVal()。