使用运算符对模板类进行子类化

时间:2014-02-06 10:45:53

标签: c++ templates subclassing

我正在尝试为各种维度的数学向量创建类,并且由于它们有很多共同之处,我创建了一个模板化的基类,其中矢量大小作为模板参数。我是子类,因为我想要不同的构造函数(例如Vec2f(float x, float y)Vec3f(float x, float y, float z))和其他函数,例如3维向量的叉积。

我的问题:基类中的operator+应该返回什么?如果它返回基类的实例,则Vec3f + Vec3f返回Vecnf,但它应返回Vec3f。这可以通过某种方式实现吗?

这是一个代码示例:

template <size_t n>
class Vecnf {
public:
   Vecnf operator+(Vecnf const & vec) const {
      return Vecnf(*this) += vec;
   }
   Vecnf & operator+=(Vecnf const & vec) {
      for (int i = 0; i < n; ++i) {
         elements[i] += vec.elements[i];
      }
      return *this;
   }
protected:
   std::array<float, n> elements;
};

class Vec3f : public Vecnf<3> {
public:
   Vec3f(float x = 0.0f, float y = 0.0f, float z = 0.0f);
   Vec3f crossProd(Vec3f const & vec);
};

通过此实现,以下内容:

Vec3f a, b;
Vec3f c = a + b;

给出编译时错误

error: conversion from 'Vecnf<3u>' to non-scalar type 'Vec3f' requested

我在Windows 8 Pro上使用TDM GCC版本4.8.1。我正在使用c ++ 11,所以你的解决方案也可以使用它,但由于我认为这不重要,所以我没有用它来标记问题。提前谢谢你:)

2 个答案:

答案 0 :(得分:1)

您可以使构造函数成为可变参数模板,从而解决您的第一个问题,并且无需使用继承:

template <size_t n>
class Vecnf
{
    std::array<float, n> elements;

public:
    template <typename ... Args>
    Vecnf(Args ... args): 
        elements {{static_cast<float>(args)...}}
    {}

    // other methods, operators etc...
};

现在,如果您愿意,可以为常用尺码制作typedef

typedef Vecnf<3> Vec3f;

在我看来,您甚至可以通过为要存储在数组中的类型添加另一个模板参数来改进这一点。当然,它可以默认为float

此外,以通用方式实现跨产品应该不会太难......

答案 1 :(得分:0)

你可以在vec3f上定义一个符合你想要的操作符+。它可以具有与vecnf不同的返回类型,只要它是它的子类型并且它仍将覆盖它。

更好的解决方案是@JorenHeit推出的;这实际上就是你想要的,还有两个typedef。这个解决方案虽然兼容c ++ 03,但他不是。