1

I got an abstract base class "Parent" with a pure virtual method and a child class "Child" implementing this method and a member "value". I instantiate objects of the child class as shared_ptr as a means of dynamic binding. I use shared_ptr's here instead of references because I store these objects in a std::vector.

Now I want to compare the two objects "someObject" and "anotherObject" as defined on the bottom of my source code. Therefore, I've overwritten the ==operator in the corresponding Child class. Nevertheless, only the == operator of the shared_ptr gets called. Can I do a comparison of the dynamically binded objects behind at all?

/*
* Parent.h
*/
class Parent{
public:
    virtual ~Parent(){};
    virtual void someFunction() = 0;
};


/*
* Child.h
*/
class Child : public Base{
private:
    short value;

public:
    Child(short value);
    virtual ~Child();
    bool operator==(const Child &other) const;
    void someFunction();
};


/*
* Child.cpp
*/
#include "Child.h"

Child::Child(short value):value(value){}
Child::~Child() {}
void Child::someFunction(){...}

bool Child::operator==(const Child &other) const {
  if(this->value==other.value){
      return true;
  }
  return false;
}


/*
* Some Method
*/
std::shared_ptr<Parent> someObject(new Child(3));
std::shared_ptr<Parent> anotherObject(new Child(4));
//!!!calls == operator for shared_ptr, but not for Child
if(someObject==anotherObject){
//do sth
}

I appreciate any input here! Thank you.

Best,

Chris
  • 721
  • 1
  • 10
  • 23
  • 1
    In general, don't compare polymorphic classes, it's not pretty. Actually, don't do anything with more than one polymorphic object at a time. – Mooing Duck Dec 17 '12 at 18:47

2 Answers2

5

When the statically known type is Parent (and it is), you need to have an operator== defined for Parent.

There are problems with having a virtual operator==, but assuming that you have some operator==, virtual or not, in class Parent, then do

std::shared_ptr<Parent> someObject(new Child(3));
std::shared_ptr<Parent> anotherObject(new Child(4));

//calls == operator for Parent
if( *someObject == *anotherObject){
//do sth
}

Without the dereferencing *s (or some equivalent) you would just be comparing the shared_ptr instances, as you discovered.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • Thanks for pointing at the dereferencing problem. Unfortunately, implementing the ==operator for the derived class was my main problem. – Chris Dec 18 '12 at 08:08
2

As Alf suggested you need to change the if statement to compare the objects themselves and not the pointers.

Additionally if there are subtypes that need special processing to determine if they are equal, your operator== needs to defer to a virtual function to do the actual comparison.

bool Parent::operator==(const Parent& other) const
{
    return equals(other);
}

bool Child::equals(const Parent& other) const
{
    Child * otherChild = dynamic_cast<Child*>(&other);
    if (otherChild != NULL)
        // compare child to child
    else
        // compare child to other type
}
Community
  • 1
  • 1
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • I'd imagine instead of comparing the child to another type, one could simply return false for that case. (maybe keeping the comment for clarity) – Mooing Duck Dec 17 '12 at 18:51
  • @MooingDuck, most of the time you'd be right, but it depends on how you define "equal". You might just use a key field for example to determine equivalence. – Mark Ransom Dec 17 '12 at 18:56
  • @MarkRansom: Thanks a lot, that worked for me. Since other is a const, I had to make the dynamic_cast const as well, as shown here: http://stackoverflow.com/questions/3605679/cast-const-class-using-dynamic-cast. One question remains: why can I defer to a virtual function at all? Just to avoid the abstract class to be pure virtual? – Chris Dec 18 '12 at 08:07
  • @Chris, generally only a child class will know how to compare itself properly. If the parent can fully implement the equals operator without needing any help from the child, there's no need to use the virtual call at all. – Mark Ransom Dec 18 '12 at 13:32