Vissarion Moutafis
Vissarion Moutafis

Reputation: 78

How to override a pure virtual function using a subclass reference in the overriden function

So I have a problem to override a pure virtual function in my derived class. The implementation and declaration of the classes looks like this:

class Base{
private:
   size_t id;
public:
   virtual bool isEqual(const Base& src) const =0;
};

class Derived: public Base{
private:
    string str;
public:
    virtual bool isEqual(const Derived& src) const override
    {
        return (this->str == src.str);
    }
};

so when I implement it like this it hits me with compiler error like

member function declared with 'override' does not override a base class member function

Could you plz tell me how I could get that right and maybe explain me why my version doesn't work. Thanks in advance!

Upvotes: 4

Views: 2456

Answers (2)

Fareanor
Fareanor

Reputation: 6805

The principle of polymorphism is that a Derived is a Base. If you want to override a function, the signature must be the same.

The proper way to solve your issue is to define your override as something equivalent to:

bool Derived::isEqual(const Base & src) const
{
    try
    {
        Derived & d = dynamic_cast<Derived &>(src);
        return (this->str == d.str);
    }
    catch(const std::bad_cast & e)
    {
        // src is not a Derived
        return false;
    }
}

If you want to work with pointers, you can do the same as follows:

bool Derived::isEqual(const Base * src) const
{
    const Derived * d = dynamic_cast<const Derived*>(src);

    if(d == nullptr) // src is not a Derived*
        return false;
    else
        return (this->str == d->str);
}

Of course it assumes that you have a matching definition in Base to override.


The solution provided by @Aconcagua uses the same idea in a more elegant way. I would advise to use his solution instead.

Upvotes: 3

Aconcagua
Aconcagua

Reputation: 25516

You cannot change the function signature that way – read about co- and contravariance for details and why C++ disallows both for function parameters (covariant return types are allowed).

On the other hand, if the other object is referred to via reference to base, the overriding (actually: overloading!) function would not be called at all:

Derived d1;
Derived d2;
Base& b2 = d2;

d1.isEqual(b2); // how do you imagine the derived version to get called now???

Key to a solution is a dynamic_cast:

struct Base
{
    virtual ~Base() { }
    virtual bool operator==(Base const& other) = 0;
};

struct Derived : Base
{
    bool operator==(Base const& other) override
    {
        auto o = dynamic_cast<Derived const*>(&other);
        return o && o->str == this->str;
    }
};

Note that I renamed the function to operator==; this is far more natural in C++. With that, you can compare in the example above with:

bool isEqual = d1 == b2;

Edit:

The teacher told us that we must not overload operator

Well, then just revert the renaming... Actually, operators are just as ordinary functions as any other one else, solely that calling syntax differs (actually: an alternative variant exists, you could always call as d1.operator ==(d2), too).

Upvotes: 8

Related Questions