1. 程式人生 > >Essential c++ 第六章練習及類模板template class 知識點

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");
}