Is it possible in C++ to formulate functions in the Base class that return Base type such that in the Derived class, they return Derived type, without overloading?
Minimal example:
class Base
{
public:
Base(double v)
{
value = v;
}
Base add(Base b)
{
return Base(b.value + this->value);
}
void print()
{
std::cout << value << std::endl;
}
double value;
};
class Derived : public Base
{
public:
Derived(double v) : Base(v)
{
}
void timesTwo()
{
value *= 2.0;
}
};
int main()
{
Derived d1(1), d2(2);
// This doesn't work because the result is of type Base
(d1.add(d2)).timesTwo();
return 0;
}
In the actual example, Base
represents a linear algebra matrix, and Derived
represents a vector. The matrix offers many functions that are all applicable to vectors, such as addition or multiplication by a scalar.
In this case, it would be desirable not having to override all these matrix functions manually to return vectors. I would like to, if possible, express that whatever this
type is, the return type should be identical to it.
Example:
class Matrix
{
...
Matrix operator*(double x);
};
class Vector : Matrix
{
...
};
Matrix M;
M = M * 2.0; // works
Vector v;
v = v * 2.0; // does not work, because v * 2.0 returns a Matrix
The effort for overriding e.g. operator*()
for all derived classes is increased by the fact that there are derived classes for 3- and 2-dimensional vectors, etc.
I understand that a solution is to define a cast from Matrix
to Vector
(and to Vector3
, Vector2
, ...) but this would involve copying all entries (which are, for efficiency, stack arrays).
Is there a more efficient solution? And, if not, would it generally be considered cleaner/better to
In my current understanding, the conflicting problems are:
Any suggestion would be most appreciated. Thanks!
Following are the properties which a derived class doesn't inherit from its parent class : 1) The base class's constructors and destructor. 2) The base class's friend functions. 3) Overloaded operators of the base class.
The derived class inherits all members and member functions of a base class. The derived class can have more functionality with respect to the Base class and can easily access the Base class. A Derived class is also called a child class or subclass.
Which among the following is inherited by a derived class from base class? Explanation: The class inheriting another class, inherits all the data members and member functions that are not private. This is done to ensure the security features with maximum flexibility.
You can derive a class from any number of base classes. Deriving a class from more than one direct base class is called multiple inheritance.
Yes, but only with free functions (including most operators).
template<class X, class Y,
std::enable_if_t<std::is_base_of<Base, std::decay_t<X>>{},int> =0,
std::enable_if_t<std::is_base_of<Base, std::decay_t<Y>>{},int> =0
>
friend X& operator+=(X&x, Y&& rhs)
{
x.value += rhs.value;
return x.
}
template<class X, class Y,
std::enable_if_t<std::is_base_of<Base, std::decay_t<X>>{},int> =0,
std::enable_if_t<std::is_base_of<Base, std::decay_t<Y>>{},int> =0
>
friend std::decay_t<X> operator+(X&&x, Y&& rhs) {
auto r=std::forward<X>(x);
r+=std::forward<Y>(rhs);
return r;
}
Now if I did that right,
(d1+d2).timesTwo();
works.
I also implemented +
in terms of +=
because that usually works well.
The fancy enable if exists because koenig lookup with very generic template operators causes strange things to happen when you pass Base
and types derived from Base
to template types and proceed to use +
on the resulting type. By saying "only things derived from Base
", the right thing happens.
We need to use a template free friend function so we can get the type of "*this
" (as it where) within the template to change our return type. This cannot be done in a template member function.
The enable_if
clause does not work well in MSVC, but is best practice in other compilers. For MSVC use class=enable_if
instead of enable_if=0
. The reason why the =0
is best is out of scope here.
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