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?
All overloaded operators except assignment (operator=) are inherited by derived classes.
Overloading allows several function definitions for the same name, distinguished primarily through different argument types; it is typically resolved at compile-time. Inheritance allows subclasses to define more special versions of the same function; it is typically resolved at run-time.
Inheritance: Overriding of functions occurs when one class is inherited from another class. Overloading can occur without inheritance. Function Signature: Overloaded functions must differ in function signature ie either number of parameters or type of parameters should differ.
Which operator is used for inheriting a class in C++? A colon ( : ) is used to inherit from another class, usually in combination with an access specifier, typically public.
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
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With