Operator== in derived class never gets called

强颜欢笑 提交于 2019-12-23 12:23:50

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!