我有一个Vector类,它代表给定模板类的数学向量。我希望能够以两种不同的方式保存向量:
template <class T>
class Vector
{
private:
T* elements;
};
和
template <class T, unsigned int D>
class Vector
{
private:
T elements[D];
};
在第一个例子中,我在构造函数和析构函数中使用new和delete分配并释放数组。 现在因为我不想为这两个类写两次所有方法,因为它甚至不会以这种方式编译,因为我有两个具有相同名称但不同模板参数的类,我想将两个类合并为一个像这样的课:
template <class T, int D = -1>
class Vector
{
public:
Vector<T, D> add(const Vector<T, D>& add) const;
private:
T elements[D];
};
template <class T>
class Vector<T, -1>
{
public:
Vector<T, D> add(const Vector<T, D>& add) const;
private:
T* elements;
};
所以第二部分只是第一部分的部分模板专业化。如果没有给出维度,则应使用动态分配的选项(D的默认参数)。作为一个例子,我添加了一个函数来计算两个向量的总和。 现在我的问题是我必须为逻辑上只有一个函数提供两个实现。每当我访问元素数组时,它在动态和静态Vector类中的语法完全相同。我可以以某种方式将两种实现组合成一个add函数的实现(以及所有类似函数的实现)吗? 如果我不能用这种方式解决问题,你对如何使用动态和静态内存分配创建Vector类有其他想法吗?
答案 0 :(得分:3)
我会选择基于策略的设计,类似于std::vector
处理分配的方式。
在你的情况下,它意味着:
示例(这里使用聚合而不是继承):
// The policy default implementation:
template <class T, int D>
class VectorStorage
{
T elements[D];
public:
T& operator[](int x) {
return elements[x];
}
const T& operator[](int x) const {
return elements[x];
}
};
class VectorStorage<T, -1>
{
T* elements; // (for allocation, see below)
public:
T& operator[](int x) {
return elements[x];
}
const T& operator[](int x) const {
return elements[x];
}
};
// The vector implementation, independent of the storage,
// but defaulting to the one above:
template <class T, int D = -1, class Storage = VectorStorage<T,D>>
class Vector
{
Storage storage;
public:
Vector<T, D> add(const Vector<T, D>& add) const {
// Access your elements using "storage[x]"
}
};
请注意,您需要一个适合您的策略类的构造函数(就动态存储类型而言,您需要在构造期间使用大小)。为所有专业提供独特的构造函数接口,而不仅仅是需要它的人;并适当地调用vector的构造函数中的构造函数:
// within class VectorStorage<T,-1>:
VectorStorage(int size) : elements(new T[size]) {}
~VectorStorage() { delete[] elements; }
// within class VectorStorage<T,D>:
VectorStorage(int /* ignored */) {}
// within class Vector:
Vector(int size) : storage(size) {}
或者,要支持像Vector<int,5> myVector;
这样的客户端代码(即静态大小版本的默认构造函数),请提供一个默认构造函数,只允许为静态大小版本调用:
Vector() : storage(D) {
static_assert(D != -1, "The default constructor is only allowed for the static-sized version of Vector.");
}
现在,用户甚至可以使用Vector
std::vector
作为存储后端:Vector<int, -1, std::vector<int>>
或Vector<int, 5, std::vector<int>>
。甚至是Vector<int, 5, std::array<int,5>>
。
答案 1 :(得分:1)
我会做类似以下的事情,即只专注于数据部分:
template <class T, int D = -1>
class VectorData
{
public:
int size() const { return D; }
protected:
T elements[D];
};
template <class T>
class VectorData<T, -1>
{
public:
explicit VectorData(int size) : elements(size) {}
int size() const { return elements.size(); }
protected:
std::vector<T> elements;
};
template <class T, int D = -1>
class Vector : protected VectorData<T, D>
{
public:
using VectorData<T, D>::VectorData;
Vector add(const Vector& add) const
{
Vector res(*this);
for (int i = 0; i != this->size(); ++i) {
res.elements[i] += add.elements[i];
}
return res;
}
};