C++ operator overloading with inheritance

25,662

Solution 1

Change

virtual Car operator++(int x){Car v(*this); operator++(); return v;}

to

virtual Vehicle operator++(int x){Car v(*this); Vehicle::operator++(); return v;}
  1. While overriding operator++, return type should not be changed.
  2. Explicitly mention that you want to call parent class's operator++ Vehicle::operator++()

With that change, your program produces this output

Ctor Vehicle 10
Ctor Car 10

Solution 2

Another way to do that is through CRTP and operator overloading helpers (Like boost operators header)

Suposse you have the following helper:

template<typename T>
struct AddHelper
{
    T& operator++()
    {
        T& reference = static_cast<T&>(*this);
        reference.add();
        return reference;
    }

    T operator++(int)
    {
        AddHelper<T> copy( *this );
        operator++();
        return static_cast<T>(copy);
    }
};

The add() implementation is provided by the base class:

class Vehicle
{
private:
    int _n;
public:
    void add(int n) { _n += n; }

    ...
};

Because Vehicle::add() is public, we can use it in every Vehicle subclasses, thats means you can have specific operator++ for every Vehicle subclasses thanks to AddHelper:

class Car : public Vehicle , public AddHelper<Car>
{
    Car(int n) : Vehicle(n) {}
    ...
};

class Motorcicle : public Vehicle , public AddHelper<Motorcicle>
{
    Motorcicle(int n) : Vehicle(n) {}
    ...
};

class Bus : public Vehicle , public AddHelper<Bus>
{
    Bus(int n) : Vehicle(n) {}
    ...
};

... //Ad infinitum

Another advantage of this way is that it doesnt use virtual functions to provide the polymorphism, so its more efficient (Static polymorphism instead of dynamic polymorphism).

Share:
25,662
prongs
Author by

prongs

Updated on June 16, 2020

Comments

  • prongs
    prongs over 3 years

    Let's say I have a class called Vehicle and another called Car that extends Vehicle class. I want to implement ++ operators for both classes.

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <vector>
    #include <sstream>
    #include <typeinfo>
    
    #define debug(args...) // Just strip off all debug tokens
    using namespace std;
    // CUT begin
    #define debug(args...) {dbg,args;cout<<endl;}
    struct debugger{template<typename T> debugger& operator ,(const T& v){cout<<v<<" ";return *this;}}dbg;
    template <typename T1,typename T2> inline ostream& operator<<(ostream& os,const pair<T1,T2>& p){return os<<"("<<p.first<<", "<<p.second<<")";}
    template<typename T>inline ostream&operator<<(ostream& os,const vector<T>& v){string delim="[";for(unsigned int i=0;i < v.size();i++){os<<delim<<v[i];delim=", ";}return os<<"]";}
    template<typename T>inline ostream&operator<<(ostream& os,const set<T>& v){string delim="[";for (typename set<T>::const_iterator ii=v.begin();ii!=v.end();++ii){os<<delim<<*ii;delim=", ";}return os<<"]";}
    template<typename T1,typename T2>inline ostream&operator<<(ostream& os,const map<T1,T2>& v){string delim="[";for (typename map<T1,T2>::const_iterator ii=v.begin();ii!=v.end();++ii){os<<delim<<*ii;delim=", ";}return os<<"]";}
    // CUT end
    
    
    class Vehicle
    {
    public:
        int n;
        Vehicle(int n):n(n){cout<<"Ctor Vehicle "<<n<<endl;}
        Vehicle(Vehicle& v):n(v.n){cout<<"Copy Ctor Vehicle "<<n<<endl;}
        virtual ~Vehicle(){cout<<"Dtor Vehicle "<<n<<endl;}
        virtual ostream& dump(ostream& os){return os<<"Vehicle("<<n<<")";}
        string to_str(){stringstream s; dump(s); return s.str();}
        virtual Vehicle& operator++(){n++;return *this;}
        virtual Vehicle operator++(int x){Vehicle v(*this); operator++(); return v;}
    };
    
    class Car: public Vehicle
    {
    public:
        Car(int n): Vehicle(n){cout<<"Ctor Car "<<n<<endl;}
        virtual ~Car(){cout<<"Dtor Car "<<n<<endl;}
        virtual ostream& dump(ostream& os){return os<<"Car("<<n<<")";}
        virtual Car operator++(int x){Car v(*this); operator++(); return v;}
        /* data */
    };
    ostream& operator<<(ostream& os,  Vehicle& v)
    {
        return v.dump(os);
    }
    
    int main(int argc, char const *argv[])
    {
        Vehicle * v = new Car(10);
        // cout<<c++<<endl;
        // cout<<c<<endl;
        return 0;
    }
    

    I get the following error with gcc:

    C:\Users\Rajat\Documents\GitHub\interview-preparation\cpp_test.cpp:16:0: warning: "debug" redefined [enabled by default]
    C:\Users\Rajat\Documents\GitHub\interview-preparation\cpp_test.cpp:13:0: note: this is the location of the previous definition
    C:\Users\Rajat\Documents\GitHub\interview-preparation\cpp_test.cpp:44:14: error: invalid covariant return type for 'virtual Car Car::operator++(int)'
    C:\Users\Rajat\Documents\GitHub\interview-preparation\cpp_test.cpp:35:18: error:   overriding 'virtual Vehicle Vehicle::operator++(int)'
    C:\Users\Rajat\Documents\GitHub\interview-preparation\cpp_test.cpp: In member function 'virtual Car Car::operator++(int)':
    C:\Users\Rajat\Documents\GitHub\interview-preparation\cpp_test.cpp:44:57: error: no matching function for call to 'Car::operator++()'
    C:\Users\Rajat\Documents\GitHub\interview-preparation\cpp_test.cpp:44:57: note: candidate is:
    C:\Users\Rajat\Documents\GitHub\interview-preparation\cpp_test.cpp:44:14: note: virtual Car Car::operator++(int)
    C:\Users\Rajat\Documents\GitHub\interview-preparation\cpp_test.cpp:44:14: note:   candidate expects 1 argument, 0 provided
    

    How do I get ++ operators for both Car and Vehicle with minimum number of virtual overrides?