修改: 请注意,我的最终目的不是让课程有效,只是学习更多关于模板的内容: - )
假设您有一个实现向量的模板类:
template <typename T>
class Vector
{
public:
Vector(size_t dim) {
dimension = dim;
elements = new T[dim];
}
/* Here more stuff, like operator[] etc... */
private:
size_t dimension;
T * elements;
}
假设你想用它构建一个矩阵。矩阵只是向量的向量,因此可以按如下方式设计:
template <typename T>
class Matrix : public Vector<Vector<T> >
{
/*...*/
}
这就麻烦了:在构造函数中,我需要提供行和列作为内部向量的参数。它应该像
template <typename T>
Matrix<T>::Matrix (size_t ncols, size_t nrows)
: Vector<Vector<T> > /* Here I need to specify size for both
* internal and external vectors */
{
}
显然我不能写Vector<Vector<T>(nrows)>(ncols)
,但这就是我需要的东西!
可能的解决方案是在模板中包含大小:
template <typename T, size_t N>
class Vector
{
public:
Vector() {
elements = new T[N];
}
/* Here more stuff, like operator[] etc... */
private:
T * elements;
}
因此我不再需要构造函数参数,但这也迫使我用模板编写笨拙的代码(例如,使用Vector
的每个函数都应声明为
template <typename T, size_t N>
void foo (Vector<T,N> &vec) {...}
你有更好的解决方案吗?
修改
作为解决方案,我从Fooz先生和chubsdad的帖子中获取灵感。这就是我解决问题的方法:
/* The RowAccess class is just an array wrapper which raises an exception
* if you go out of bounds */
template <typename T>
class RowAccess
{
public:
RowAccess (T * values, unsigned cols) : values(vals), cols(c) {}
T & operator[] (unsigned i) throw (MatrixError) {
if (i < cols) return values[i];
else throw MatrixError("Column out of bound");
}
private:
T * values;
unsigned cols;
};
template <typename T>
class Matrix
{
public:
Matrix (unsigned rows, unsigned cols) {...}
virtual ~Matrix () {...}
RowAccess<T> operator[] (unsigned row) {
if (row < rows) return RowAccess<T>(values + cols * row, cols);
else throw MatrixError("Row out of boundary");
}
private:
unsigned rows;
unsigned cols;
T * values;
};
非常感谢大家!
答案 0 :(得分:3)
在OO术语中,我会投票支持“拥有”Matrix和Vector之间的关系。矩阵有向量,而不是矩阵“是一个”向量,这意味着矩阵不应该从向量派生。
编辑1:小修正。 “..这意味着Matrix不应该从”公开“派生出来”。私人继承可能仍然没有问题。
答案 1 :(得分:2)
像这样使用placement-new(隐藏在uninitialized_fill
电话后面)
template <typename T>
class Vector
{
public:
Vector(size_t dim, T const& c = T()) {
dimension = dim;
elements =
static_cast<T*>(operator new(sizeof(T) * dim));
std::uninitialized_fill(elements, elements + dim, c);
}
/* Here more stuff, like operator[] etc... */
private:
size_t dimension;
T * elements;
};
然后你可以使用Matrix::Vector(ncols, Vector<T>(nrows))
调用构造函数(你不需要重复外部Vector的参数,因为Vector
会自动引用Vector< Vector<T> >
,因为你从外部继承Vector。你需要确保在析构函数中执行operator delete(elements)
之前手动调用析构函数。
您可能还希望将矢量嵌入为成员,我可能更喜欢这个因素,因为我认为外部矢量的所有操作都不一定对矩阵有意义。然后初始化看起来像m(ncols, Vector<T>(nrows))
。
应该注意std::vector
也可以用于此
template <typename T>
class Vector
{
public:
Vector(size_t dim, T const& c = T()):elements(dim, c)
{ }
private:
std::vector<T> elements;
};
这是一种简单而安全的方法,您可以获得自动内存管理。
答案 2 :(得分:1)
这不是你提出的问题,但是矩阵很有可能更好地作为单个线性向量实现,你可以提供进行索引的高级访问方法(例如elmLoc = row * ncols + col) 。这样您就不需要创建和初始化向量向量。您也不必担心意外地拥有一些不同大小的内部向量。我曾经使用过的所有密集矩阵实现都使用单个线性向量作为底层实现。
答案 3 :(得分:0)
这取决于您对Vector(和Matrix)类的期望。
要么在运行时确定大小,在这种情况下,我建议添加一个resize()
函数,它允许您根据需要在构造函数中调整Vector的大小。
template <typename T>
class Vector
{
public:
Vector(size_t dim) {
dimension = dim;
elements = new T[dim];
}
Vector() : dimension(0), elements(0) {} // you need default constructor
void resize(size_t dim) { // note: this could be implemented a lot better
T* new_elements=new T[dim];
for(int i=0; i<dim && i<dimension; i++)
new_elements[i]=elements[i];
delete [] elements;
elements=new_elements; dimension=dim;
}
/* Here more stuff, like operator[] etc... */
private:
size_t dimension;
T * elements;
}
然后,您将在循环中调整Vectors
构造函数中的Matrix
。
如果你想在编译时确定向量或矩阵的大小,最好的办法就是按照你的建议使用模板非类型参数。