知识点:
1、类模板形式 template< typename elemType> class T ,其中typename可以替换为class,写成template< class elemType> class T。 调用形式:T< string>t1
2、typename:用在模板定义里,标明其后的模板参数是类型参数。
3、常量表达式与默认参数值:Template的参数并不是非得某种类型不可,也可以用常量表达式(constant expression)作为参数。例如,template<int a,int b=1>class T,调用时为 T<32,1> t2.
4、Member Template Function(成员模板函数),即将类的成员函数定义成Template形式,其中类可以是普通类,也可以模板类。
5、new表达式和delete表达式:用以管理内存分配和释放。primer 12.1.2节详解。new返回一个指针,delete接收一个指针。
练习6.1
试改写以下类,使之成为一个class template:
class example{
public:
example(double min, double max);
example(const double *array, int size);
double& operator[](int index);
bool operator==(const example&) const;
bool insert(const double*, int);
bool insert(double);
double min() const { return _min; }
double max() const { return _max; }
void min(double);
void max(double);
int count(double value) const;
private:
int size;
double *parray;
double _max;
double _min;
};
解:要将某个class转换为一个class template,我们必须找出所有和类型相关的部分,并且剥离出来。本例中,_size 的类型是int,用户会不会指定为其他类型呢?不会,因为 size用来记录 _parray所指数组的元素个数,其类型不会变动。至于_parray,就有可能指向不同类型的元素,如int ,double,float,string等,因此必须将_parray,_min,_max这些数据类型予以参数化。
由于elemType 现在可能被用来表现内置类型或class类型,因此以传址(by reference)方式而非传值(by value)方式比较好
template <typename elemType>
class example{
public:
example(const elemType &min, const elemType &max);
example(const elemType *array, int size);
elemType& operator[](int index);
bool operator==(const example&) const;
bool insert(const elemType*, int);
bool insert(const elemType&);
elemType min() const { return _min; }
elemType max() const { return _max; }
void min(const elemType&);
void max(const elemType&);
int count(const elemType &value) const;
private:
int size;
elemType *parray;
elemType _max;
elemType _min;
};
tip:可以看到,模板类型下,凡是自定义数据类型的形参全部改成const T &a和const T *a,这是因为将内部数据类型(int ,double等)改成用户自定义数据类型后,对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const 引用传递”,目的是提高效率。
练习6.2
将4.5的矩阵Matrix用template重写,使他能够通过堆内存来支持任意行列大小。分配/释放内存的操作请在constructor/destructor中进行。
知识点:new表达式分配动态数组~
#include<iostream>
using namespace std;
template<typename elemType>
class Matrix{
//类模板中友函数声明前要再加上template<typename elemType>!!!不然会出现“无法解析的外部符号”错误
template<typename elemType>
friend Matrix<elemType> operator+(const Matrix<elemType>&, const Matrix<elemType>&);
template<typename elemType>
friend Matrix<elemType> operator*(const Matrix<elemType>&, const Matrix<elemType>&);
public:
Matrix(int rows, int columns);
//析构函数释放动态数组内存,要加[]
~Matrix(){ delete[] _matrix; }
//复制构造函数和复制赋值运算符
Matrix(const Matrix&);
Matrix& operator=(const Matrix&);
void operator+=(const Matrix&);
ostream& print(ostream &os)const;
//函数调用运算符重载
elemType& operator()(int row, int column){
return _matrix[row*cols() + column];
}
elemType operator()(int row, int column)const{
return _matrix[row*cols() + column];
}
int rows()const{ return _rows; }
int cols()const{ return _cols; }
private:
int _rows;
int _cols;
elemType *_matrix;
};
template<typename elemType>
inline ostream& operator<<(ostream &os, const Matrix<elemType> &m)
{
return m.print(os);
}
template<typename elemType>
ostream& Matrix<elemType>::print(ostream &os)const
{
int col = cols();
int matrix_size = col*rows();
for (int ix = 0; ix < matrix_size; ++ix)
{
if (ix%col == 0) os << endl;
os << (*(_matrix + ix)) << ' ';
}
os << endl;
return os;
}
template<typename elemType>
Matrix<elemType>::Matrix(int rows, int columns)
:_rows(rows), _cols(columns)
{
int size = _rows*_cols;
_matrix = new elemType[size]();// new表达式定义动态数组,加个()就可以实现初始化。
}
template<typename elemType>
Matrix<elemType>::Matrix(const Matrix &rhs)
{
_rows = rhs._rows; _cols = rhs._cols;
int matrix_size = _rows*_cols;
_matrix = new elemType[matrix_size];
for (int ix = 0; ix < matrix_size; ++ix)
_matrix[ix] = rhs._matrix[ix];
}
template<typename elemType>
Matrix<elemType>& Matrix<elemType>::operator=(const Matrix &rhs)
{
if (this != &rhs)
{
_rows = rhs._rows; _cols = rhs._cols;
int matrix_size = _rows*_cols;
delete[] _matrix;
_matrix = new elemType[matrix_size];
for (int ix = 0; ix < matrix_size; ++ix)
_matrix[ix] = rhs._matrix[ix];
}
return *this;
}
template<typename elemType>
Matrix<elemType> operator+(const Matrix<elemType> &m1, const Matrix<elemType> &m2)
{
Matrix<elemType> result(m1.rows(), m1.cols());
for (int ix = 0; ix < m1.rows(); ++ix)
{
for (int jx = 0; jx < m1.cols(); ++jx)
{
result(ix, jx) = 0;
result(ix, jx) = m1(ix, jx)+m2(ix,jx);
}
}
return result;
}
template<typename elemType>
Matrix<elemType> operator*(const Matrix<elemType> &m1, const Matrix<elemType> &m2)
{
Matrix<elemType> result(m1.rows(), m2.cols());
for (int ix = 0; ix < m1.rows(); ++ix)
{
for (int jx = 0; jx < m1.cols(); ++jx)
{
result(ix, jx) = 0;
for (int kx = 0; kx < m1.cols();++kx)
result(ix, jx) += m1(ix, kx) * m2(kx, jx);
}
}
return result;
}
template<typename elemType>
void Matrix<elemType>::operator+=(const Matrix &m)
{
int matrix_size = cols()*rows();
for (int ix = 0; ix < matrix_size; ++ix)
(*(_matrix + ix)) += (*(m._matrix + ix));
}
int main()
{
Matrix<float>identity(4, 4);
cout << "identity: " << identity << endl;
float ar[16] = { 1., 0., 0., 0., 0., 1., 0., 0.,
0., 0., 1., 0., 0., 0., 0., 1. };
for (int i = 0, k = 0; i < 4;++i)
for (int j = 0; j < 4; ++j)
identity(i, j) = ar[k++];
cout << "identity after set: " << identity << endl;
Matrix<float> m(identity);
cout << "m " << m << endl;
Matrix<float> m2(8, 12);
cout << "m2 " << m2 << endl;
m2 = m;
cout << "m2=m " << m2 << endl;
float ar2[16] = { 1.3, 0.4, 2.6, 8.2, 6.2, 1.7, 1.3, 8.3,
4.2, 7.4, 2.7, 1.9, 6.3, 8.1, 5.6, 6.6 };
Matrix<float> m3(4, 4);
for (int ix = 0, kx = 0; ix < 4; ++ix)
for (int j = 0; j < 4; ++j)
m3(ix, j) = ar2[kx++];
cout << "m3 " << m3 << endl;
Matrix<float>m4 = m3*identity; cout << "m4 "<<m4 << endl;
Matrix<float>m5 = m3 + m4; cout << "m5 " << m5 << endl;
m3 += m4; cout << m3 << endl;
system("pause");
}