继承的函数返回派生类,而不是基类
Inherited functions to return Derived class, not Base class
在C++中,是否可以在基类中公式化返回基类的函数,以便在Derived类中返回Derived类型,而不重载?
最小示例:
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;
}
动机
在实际示例中,Base
表示线性代数矩阵,Derived
表示向量。矩阵提供了许多适用于向量的函数,例如标量的加法或乘法。
在这种情况下,希望不必手动覆盖所有这些矩阵函数来返回向量。如果可能的话,我想表达一下,无论this
类型是什么,返回类型都应该与它相同
示例:
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
由于存在3维和2维向量等的派生类,增加了覆盖所有派生类的努力,例如operator*()
。
我知道解决方案是定义从Matrix
到Vector
(以及到Vector3
、Vector2
…)的强制转换,但这将涉及复制所有条目(为了提高效率,这些条目是堆栈数组)。
有没有更有效的解决方案?如果没有,它通常会被认为比更清洁/更好吗
- 复制每个派生类中的所有相关代码,或
- 定义演员阵容
在我目前的理解中,相互冲突的问题是:
- 重复的代码使解决方案容易出错,并且更难重构
- 每当"范围"在Matrix、Vector、Vector3…之间发生变化时,重用现有代码需要大量的复制操作。如果在大型计算中使用,效率会很低
如有任何建议,我们将不胜感激。谢谢
是的,但仅限自由函数(包括大多数运算符)。
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;
}
如果我做对了,
(d1+d2).timesTwo();
工作。
我还根据+=
实现了+
,因为它通常工作得很好。
花式启用if是因为当您将Base
和从Base
派生的类型传递给模板类型并继续对生成的类型使用+
时,使用非常通用的模板运算符的koenig查找会导致奇怪的事情发生。只要说"只有源自Base
的东西",正确的事情就会发生。
我们需要使用一个无模板的朋友函数,这样我们就可以在模板中获得"*this
"的类型(如它所在的位置)来更改我们的返回类型。这不能在模板成员函数中完成。
enable_if
子句在MSVC中不能很好地工作,但在其他编译器中是最佳实践。对于MSVC,使用class=enable_if
而不是enable_if=0
。=0
最好的原因在这里超出了范围。
使class Base抽象,并将其方法放在分离的函数中。还声明纯虚拟派生类中所需的方法:
#include <iostream>
class Base
{
public:
Base(double v) : value(v) {}
double value;
virtual void timesTwo() = 0;
};
class Derived : public Base
{
public:
Derived(double v) : Base(v) {}
void timesTwo()
{
value *= 2.0;
std::cout << "timesTwo " << value << std::endl;
}
};
template <class T>
T add(const T& t1, const T& t2)
{
return T(t1.value + t2.value);
}
int main()
{
Derived d1(1), d2(2);
add(d1, d2).timesTwo();
return 0;
}
- 虚拟基类函数中派生类的大小
- 无法访问基类函数 C++
- 如何使派生类函数在调用时始终调用相同的基类函数?
- C++虚拟函数:基类函数是调用的,而不是派生的
- Qt基类函数定义
- 添加字符串类型的类成员会导致调用基类函数而不是子函数
- 有没有办法调用基类函数,该函数在使用私有继承的派生类中被覆盖?
- C++ - 基类函数指针调用的替代方法
- 什么更有效率?在重载函数中或通过在基类函数中检查对象类型来实现
- 重载基类函数是不好的做法吗?
- 在 qml 中公开基类函数
- 调用基类函数时强制使用类名?
- 如何判断哪个派生的类对象称为基类函数
- 获取具有基类函数的派生类
- 有没有办法从基类函数参数中推断出模板参数
- 私有非虚拟基类函数被称为派生类中的函数
- 模板基类函数成员的别名
- 如何用相同的签名从main调用基类函数
- C++ 如何从 main 调用派生的基类函数
- memcpy派生类到基类,为什么还调用基类函数