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

C++: Derived virtual function is returning strange results

本文关键字:结果 返回 函数 派生      更新时间:2023-10-16

我在. 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() << "nn";
    #ifdef _WIN32
        system("pause");
    #endif
    return 0;
}

你遇到了一个被称为对象切片的问题。因为你的Apple是按值传递给你的operator<<,只有对象的Fruit部分被复制。因此,当getVal被调用时,它是在基类Fruit上调用的,而不是在您的Apple上。

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

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

正如维基百科条目所说,这个问题在c++中突然出现,因为"按值赋值不是多态的"。

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

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

AppleFruit,所以它可以用作Fruit复制构造函数的参数,然而,Fruit复制构造函数生成一个常规的Fruit,而不管你提供的Fruit的子类是什么,因此你只会得到一个常规的Fruit。这被称为"切片",有些令人困惑。

相反,您可能希望将操作符定义为接受const引用,因此不使用复制构造函数。像这样,ostream& operator<<(ostream& a, const Fruit& b)

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

您遇到了切片问题。您的operator<<正在获取对象的副本,而不是对它的引用。由于您没有定义复制构造函数,编译器为您定义了一个,并且它正在做错误的事情。

很快跳出来的一件事是,您没有通过指针调用getVal(),并且由于您的operator<<接受的是Fruit而不是Apple,因此它有效地切掉了对象的派生部分。请尝试将Fruit&作为operator<<的参数。

修改如下: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()

相关文章: