C++: Derived virtual function is returning strange results
I created a derivable class with a virtual function in a .HPP file, and then gave it a default return value in the class's .CPP file. Next, I created a class which inherited the latter derivable class and overloaded it's virtual function, giving it a new return value. However, the return value is not always the same (either the default return value or the overloaded return value). Can someone help me fix my code or find the issue. Thanks.
Note: I am providing example code, which I believe will suffice in displaying the problem.
#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(ty开发者_开发技巧pe) {}
//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;
}
You are hitting a problem known as object slicing. Because your Apple
is being passed by value into your operator<<
, only the Fruit
portion of the object is being copied. Thus, when getVal
is called, it is being called on the base class Fruit
instead of on your Apple
.
To fix this, ensure that you use references (or pointers) instead of values when dealing with base classes. For example, the fix here is to simply take a const Fruit&
instead of just a Fruit
.
ostream& operator<<(ostream& a, const Fruit& b)
{
return a << b.getVal();
}
As the Wikipedia entry says, this issue crops up in C++ because "assignment by value is not polymorphic".
ostream& operator<<(ostream& a, Fruit b)
This code constructs a new object of type Fruit using the constructor defined as Fruit(const Fruit&);
.
An Apple
is a Fruit
, so it can be used as the argument to the Fruit copy constructor, however, the Fruit
copy constructor makes a regular Fruit
regardless of the subclass of Fruit you supply, and you therefore will just get a regular Fruit
. This is somewhat confusingly referred to as 'slicing'.
Instead, you probably want to define your operator to take a const reference, so the copy constructor is not used. Like so, ostream& operator<<(ostream& a, const Fruit& b)
I'd also recommend declaring the copy constructor and assignment operator in the private section of the fruit class (unimplemented) so that you can never accidentally make this mistake again
You're running afoul of the slicing problem. Your operator<<
is taking a copy of the object, not a reference to it. Since you didn't define a copy constructor, the compiler did one for you, and it's doing the wrong thing.
One thing that jumps out pretty quickly is that you're not calling getVal() by pointer, and since your operator<<
takes a Fruit rather than an Apple, it effectively slices off the derived part of the object. Try Fruit&
as the parameter for the operator<<
instead.
Change this:
ostream& operator<<(ostream& a, Fruit b)
{
return a << b.getVal();
}
to this:
ostream& operator<<(ostream& a, const Fruit& b)
{
return a << b.getVal();
}
and it should work.
In your implementation you are constructing brand new instance of Fruit from Apple. And so calling Fruit::getVal().
精彩评论