Essential c++ 第六章練習及類模板template class 知識點
知識點:
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");
}