The == operator in a derived class is never called

Can someone ask to lead me out of my misery with this? I am trying to understand why the derived operator == is never called in a loop. To simplify the example, here is 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 this ...

 Derived p1("Sarah", 42); Derived p2("Sarah", 42); bool z = ( p1 == p2 ); 

... everything is fine. The == operator from Derived is called here, but when I iterate over the list, comparing the items in the 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 Base operator== , even if both are Derived objects.

I know that I am going to kick myself when I find out what is wrong, but if someone can softly let me down, it will be very grateful.

+4
source share
5 answers

There are two ways to fix this.

First decision. I would suggest adding some additional type logic to the loop, so you know when you have Base and when you have Derived . If you are really dealing with Derived objects, use

 list<Derived*> coll; 

otherwise put dynamic_cast somewhere.

The second solution. Paste the same logic into your operator== . Make it virtual first, so the type of left operand is determined at runtime. Then manually check the type of the right 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 given that objects of different types are probably not equal, it’s possible that you want

 virtual bool operator==( const Base& other ) const { Derived *other_derived = dynamic_cast< Derived * >( &other ); return other_derived && Base::operator==( other ) && age_ == other_derived->age_; } 
+4
source

This is because you did not make your == operator virtual, so the actual type is not taken into account at runtime.

Unfortunately, just making the == virtual statement will not help solve your problem. The reason is that when you change the signature of the function, changing the type of the argument from the base to the derivative, you are actually creating a new function. It looks like you want to study dual dispatch to solve your problem.

+9
source

You need to do operator== virtual , and you need to make sure that both methods have the same signature. those. they will probably need to take Base . You may have an overloaded operator== in a derived class that can handle derived objects.

+2
source

When a member function is virtual, the virtual table is used at run time to polymorphically call the function of the type that the actual pointer points to (in this case, your Derived class). When the function is not virtual, the virtual table is not searched, and the function called by this type (in this case, your class base).

Here your operator = () functions are not virtual, so the type of the pointer is used, not the type that the pointer points to.

+1
source

For derived classes that use their own implementation of the operator, the operator must be virtual in the base class, otherwise, the implementation of the base classes will be used instead.

0
source

Source: https://habr.com/ru/post/1299492/


All Articles