假设我有一个基类
class Vector
{
public:
Vector(const std::vector<float> &elements);
static Vector add(const Vector &v1, const Vector &v2);
Vector Vector::operator+(const Vector &v) const
{
return add(*this, v);
}
Vector &Vector::operator+=(const Vector &v)
{
*this = add(*this, v);
return *this;
}
float operator[](size_t index) const;
private:
std::vector<float> _elements;
}
以及 3 元素向量的派生类
class Vector3 : public Vector
{
public:
Vector3(float x, float y, float z);
};
我必须做什么才能将运算符与派生类一起使用?
我的解决方案是重新定义派生类中的运算符,如下所示:
Vector3 Vector3::operator+(const Vector3 &v) const
{
Vector res = Vector::operator+(v);
return Vector3(res[0], res[1], res[2]);
}
Vector3 &Vector3::operator+=(const Vector3 &v)
{
Vector res = Vector::operator+=(v);
*this = Vector3(res[0], res[1], res[2]);
return *this;
}
到目前为止,这是可行的,但我想知道这是否是正确的方法。对我来说,这看起来很像双重工作。此外,我不完全理解为什么我必须首先重新定义运算符。是因为我无法从 Vector 转换为 Vector3 吗?我的简单假设是“Vector3”与大小为 3 的“Vector”相同,因此在我看来,不存在与给定操作员任务不同相关的差异。如果有人能启发我是否有更好的方法,那就太好了。
框架挑战:您想要在这里做的事情增加了复杂性、继承性和您必须跳过的障碍(实践和概念),并降低了性能。由于您通常只想承受增加的复杂性以获得更高的性能,因此请做其他事情。
我的建议是,记住你的大部分想法是
Vector
转换为模板,其大小是模板参数(并且可能存储数据类型,以便您可以轻松地在 float
、double
和 int
之间切换)Vector3
转换为 typedef。例如using Vector3 = Vector<3>;
。现在 Vector3
字面上是 Vector
,因此无需在继承中纠结,同时提供您想要的行为。这是一个快速演示:
#include <array>
#include <cstddef>
#include <functional>
#include <algorithm>
#include <iostream>
template<size_t SIZE> // A more general <class TYPE, int SIZE> will be more useful
class Vector
{
public:
// initializer_list may make this easier to work with
Vector(const std::array<float,SIZE> &elements): _elements(elements)
{
}
Vector & operator+=(const Vector &v)
{
//just crapping out a simple summation here for demo purposes
std::transform(_elements.begin(), _elements.end(),
v._elements.begin(),
_elements.begin(),
std::plus());
return *this;
}
float operator[](size_t index) const;
// consider adding the usual iterator -granting functions so
// you can use one of these in Standard algorithms
// added for demo purposes to print out the result
friend std::ostream & operator<<(std::ostream & out,
const Vector & vec)
{
for (const auto & val:vec._elements)
{
out << val << ' ';
}
return out;
}
private:
std::array<float, SIZE> _elements; // Look ma! No pointers!
// The Vector data is IN the Vector!
// no extra look-ups and no extra
// cache misses
};
// now a free function to aid in decoupling
template <size_t SIZE>
Vector<SIZE> operator+(Vector<SIZE> lhs,
const Vector<SIZE> &rhs)
{
lhs += rhs;
return lhs;
}
using Vector3 = Vector<3>;
int main()
{
Vector3 a({1,2,3});
Vector3 b({3,2,1});
Vector3 c = a+b;
std::cout << c << '\n';
Vector<4> d({});
//Vector3 e = c+d; // addition fails at compile time because the types
// don't match. Much debug savings
}