问题
Can someone please put me out of my misery with this? I'm trying to figure out why a derived operator== never gets called in a loop. To simplify the example, here's my Base and Derived class:
class Base { // ... snipped
bool operator==( const Base& other ) const { return name_ == other.name_; }
};
class Derived : public Base { // ... snipped
bool operator==( const Derived& other ) const {
return ( static_cast<const Base&>( *this ) ==
static_cast<const Base&>( other ) ? age_ == other.age_ :
false );
};
Now when I instantiate and compare like this ...
Derived p1("Sarah", 42);
Derived p2("Sarah", 42);
bool z = ( p1 == p2 );
... all is fine. Here the operator== from Derived gets called, but when I loop over a list, comparing items in a list of pointers to Base objects ...
list<Base*> coll;
coll.push_back( new Base("fred") );
coll.push_back( new Derived("sarah", 42) );
// ... snipped
// Get two items from the list.
Base& obj1 = **itr;
Base& obj2 = **itr2;
cout << obj1.asString() << " " << ( ( obj1 == obj2 ) ? "==" : "!=" ) << " "
<< obj2.asString() << endl;
Here asString()
(which is virtual and not shown here for brevity) works fine, but obj1 == obj2
always calls the Base
operator==
even if the two objects are Derived
.
I know I'm going to kick myself when I find out what's wrong, but if someone could let me down gently it would be much appreciated.
回答1:
There are two ways to fix this.
First solution. I would suggest adding some extra type logic to the loop, so you know when you have a Base
and when you have a Derived
. If you're really only dealing with Derived
objects, use
list<Derived*> coll;
otherwise put a dynamic_cast
somewhere.
Second solution. Put the same kind of logic into your operator==
. First make it virtual, so the type of the left-hand operand is determined at runtime. Then manually check the type of the right-hand operand.
virtual bool operator==( const Base& other ) const {
if ( ! Base::operator==( other ) ) return false;
Derived *other_derived = dynamic_cast< Derived * >( &other );
if ( ! other_derived ) return false;
return age_ == other_derived->age_;
}
but considering that objects of different types probably won't be equal, probably what you want is
virtual bool operator==( const Base& other ) const {
Derived *other_derived = dynamic_cast< Derived * >( &other );
return other_derived
&& Base::operator==( other )
&& age_ == other_derived->age_;
}
回答2:
That's because you haven't made your operator== virtual so the actual type is not taken into account at runtime.
Unfortunately, just making the operator== virtual is not going to solve your problem. The reason why is that when you change the function signature by changing the type of the argument from base to derived, you are actually creating a new function. It sounds like you want to look into double-dispatch to solve your problem.
回答3:
You need to make operator==
virtual
and you need to make sure that they both methods have the same signature. i.e. they will likely need to both take Base
. You could have an overloaded operator==
in your derived class that would be able to handle Derived objects.
回答4:
When a member function is virtual, the virtual table is used at runtime to polymorphically call the function on the type that the pointer actually points to (in this case, your class Derived). When a function is not virtual, no virtual table lookup is done and the function the given type is called (in this case, your class Base).
Here, your operator=() functions are not virtual, so the type of the pointer is used rather than the type that the pointer points to.
回答5:
For derived classes to use their own implementation of an operator the operator must be virtual in the base class, otherwise the base classes implementation will be used instead.
来源:https://stackoverflow.com/questions/2143394/operator-in-derived-class-never-gets-called