Reputation: 9606
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?
Upvotes: 6
Views: 32385
Reputation: 14174
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).
Upvotes: 2
Reputation: 239443
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;}
Vehicle::operator++()
With that change, your program produces this output
Ctor Vehicle 10
Ctor Car 10
Upvotes: 4