I am currently trying to understand inheritance in C++, but I am quite confused as to why I can't make a descendant class of my main class return an object of the same type as said descendant class from some operator methods I overloaded.
The classes are defined like this (this is an abridged version):
template <class elem>
class Vect
{
public:
Vect() = default;
virtual Vect operator+(const elem&);
virtual Vect operator-(const elem&);
}
template <class elem, std::size_t taille=10>
class Vect_fixe: public Vect<elem>
{
public:
Vect_fixe() = default;
virtual Vect_fixe operator+(const elem&);
virtual Vect_fixe operator-(const elem&);
private:
elem vecteur[taille] = {0};
}
And this is how the methods are defined:
template <class elem, std::size_t taille>
Vect_fixe<elem,taille> Vect_fixe<elem, taille>::operator+(const elem& operand)
{
Vect_fixe<elem, taille> temp_v;
for (int i=0; i<taille; i++)
{
temp_v[i] = vecteur[i];
temp_v[i] += operand;
}
return temp_v;
}
template <class elem, std::size_t taille>
Vect_fixe<elem,taille> Vect_fixe<elem, taille>::operator-(const elem& operand)
{
Vect_fixe<elem, taille> temp_v;
for (int i=0; i<taille; i++)
{
temp_v[i] = vecteur[i];
temp_v[i] -= operand;
}
return temp_v;
So in this case, both methods should return a copy of the vector + operand, but it doesn't work when I use inheritance. If I remove the first class' virtual methods (Vect) from the file, everything works fine. Otherwise the compiler complains about an invalid covariant return type.
main.cpp:88:24: required from here
main.cpp:50:24: error: invalid covariant return type for 'Vect_fixe<elem, taille> Vect_fixe<elem, taille>::operator+(const elem&) [with elem = int; long unsigned int taille = 35ul]'
Vect_fixe<elem,taille> Vect_fixe<elem, taille>::operator+(const elem& operand)
^
In file included from main.cpp:9:0:
Vect.hpp:25:22: error: overriding 'Vect<elem> Vect<elem>::operator+(const elem&) [with elem = int]'
virtual Vect operator+(const elem&);
^
main.cpp:62:24: error: invalid covariant return type for 'Vect_fixe<elem, taille> Vect_fixe<elem, taille>::operator-(const elem&) [with elem = int; long unsigned int taille = 35ul]'
Vect_fixe<elem,taille> Vect_fixe<elem, taille>::operator-(const elem& operand)
^
In file included from main.cpp:9:0:
Vect.hpp:26:22: error: overriding 'Vect<elem> Vect<elem>::operator-(const elem&) [with elem = int]'
virtual Vect operator-(const elem&);
I tried doing it with a reference, but returning a reference to a temporary object is undefined behaviour as far as I know, and I wish for the methods to return a copy of my object and not directly modify it.
Is there any way to do that?
One thing I could point out is that you are not doing inheritance as you wanted to use. I can guess that you intention was to use Vect
as an interface and override it with Vect_fixe
.
But, because the return types are different, they become covariant return types. This mechanism requires return by pointer or reference (so the covariant types can be cast from/to each other).
If you intend to use Vect
as a general reference handler for all its subtypes, then you should really be returning references/pointers.
I tried doing it with a reference, but returning a reference to a temporary object is undefined behaviour as far as I know, and I wish for the methods to return a copy of my object and not directly modify it.
If you return a reference you can extend its lifetime by using static
local.
int& returnByReference()
{
static int x = 5; // static ensures x doesn't go out of scope when we return it by reference
return x;
}
int value = returnByReference(); // case A -- ok, treated as return by value
const int &cref = returnByValue(); // case C -- ok, the lifetime of return value is extended to the lifetime of cref
Not good idea to follow for life, though. As @n.m. said in the commends, inheritance and copy don't mix well because overloading will eventually introduce ambiguities or unavoidable but undesired casts.