Mossid
Mossid

Reputation: 183

Polymorphic function in class which is implementing abstract class

class Eq
{
public:
    virtual bool operator==(Eq operand) = 0;
};

class Day : public Eq
{
public:
    enum DAY
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    } day;
    Day(DAY init_day) : day(init_day){}
    bool operator==(Day operand)
    {
        return day == operand.day;
    }
};

int main()
{
    Day d1(Day::Monday);
    Day d2(Day::Monday);
    d1 == d2;
    return 0;
}

This is the code which I trying to implement. Class Eq works like as interface of JAVA. It has only one member function, operator==. Operator== takes one operand which is same type with the class which is deriving Eq class. For example, class Day derives Eq, so it have to implement operator== which is taking Day type parameter.

And there is the problem. First, both operator== functions have different signatures. So the compiler thinks they are not same functions, but overrided functions. Second, if any function in this code takes Eq class parameter, then compiler makes error because instance of the abstract class is not available.

So this is the question. How can I make operator== function in T class to take T class parameter, where T is implementation of Eq class?

Upvotes: 3

Views: 113

Answers (4)

Christophe
Christophe

Reputation: 73366

Your approach has two main flaws:

  • The signature of operator== for Day does not match the one of Eq so it won't work.
  • You pass operand of operator by value. THis means that there will be slicing (i.e. the object passed might loose all members that are not in Eq, here the day)

There are already nice template solutions proposed, which is very convenient for this kind of problems. For the sake of completeness, I propose you a templateless alternative.

First chance Eq:

class Eq
{
public:
    virtual bool operator==(Eq& operand) = 0;  // References passing doesn't slice
};

Then update its overriding in Day:

bool operator==(Eq& operand)
{
    if (dynamic_cast<Day*>(&operand))  // check if types compatible 
        return day == dynamic_cast<Day*>(&operand)->day;
    else return false;  // else the objects are different anyway
}

Finally you can test in main():

 ...
if (d1 == d2)  // check that result is as expected !
    cout << "Yes it works !";  
else cout << "Hhmmm..."; 

Upvotes: 1

Mats Fredriksson
Mats Fredriksson

Reputation: 20101

You can do this by sending in references instead.

class Eq
{
public:
    virtual bool operator==(Eq& operand) = 0; // Changed to reference
};

class Day : public Eq
{
public:
    enum DAY
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    } day;
    Day(DAY init_day) : day(init_day){}
    bool operator==(Eq& operand) // Changed to reference of Eq.
    {
        const Day* other = dynamic_cast<Day*> (&operand);
        if (other == nullptr) // Checking if the operand is of Day type.
            return false; // If not, those two objects cannot be the same.
        return day == other->day; // Do the comparison. 
        // Note the '->' instead of '.' since 'day' is a pointer.
    }
};

You are missing a few key points on how C++ works compared to Java (which I guess you are more familiar with).

  1. To do virtual overriding you have to have the same method signature.
  2. To avoid slicing you need to send references or pointers, not objects on the stack.
  3. Finally, it could be potentially very memory intensive to send values (compared to references or pointers).

Here are a couple of good links I found regarding how to do operator== overloading when dealing with inheritance. (They also talk about the public-non-virtual/non-public-virtual discussion.)

Equality Test for Derived Classes in C++

What's the right way to overload operator== for a class hierarchy?

Upvotes: 2

swang
swang

Reputation: 5239

you can use CRTP:

template <typename DerivedType>
class Eq
{
public:
    virtual bool operator==(DerivedType operand) = 0;
};

class Day : public Eq<Day>
{
public:
    enum DAY
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    } day;
    Day(DAY init_day) : day(init_day){}
    bool operator==(Day operand)
    {
        return day == operand.day;
    }
};

Upvotes: 2

Codor
Codor

Reputation: 17595

You could introduce a type parameter T in Eq and derive Dayfrom Eq<Day> to enforce the desired signature of operator==.

Upvotes: 3

Related Questions