1. 程式人生 > >矩陣類——實現矩陣相乘

矩陣類——實現矩陣相乘

矩陣類——實現矩陣相乘

​ 剛開始學習C++,有什麼地方寫的不對的,懇請大家批評指正!

​ 要求:定義矩陣類,實現矩陣相乘,並將結果輸出在螢幕上、儲存到 .txt檔案中

​ 分析問題:定義一個矩陣類Class my_matrix,使用指標成員變數elem實現大小可變的矩陣(此處用一維陣列存放矩陣的元素),定義私有成員row、col。必備的是建構函式、複製建構函式、解構函式;為了實現深拷貝,需要過載運算子=;由於原有的乘號*並不知道如何對你的矩陣類進行操作,所以要過載運算子*;在螢幕上輸出陣列,需要過載流運算子<< ;矩陣元素輸入時需要函式void getelem()

獲取元素,結果儲存到.txt檔案中需要一個成員函式void save_matrix()

文章目錄

1.建構函式

​ 功能:物件初始化(此時物件已經分配了儲存空間)。

​ 必要性:1. 預設的建構函式實際上不做任何操作 2. 物件沒有初始化就使用,會導致程式出錯。

	my_matrix(int r =0, int c =0) :row(r), col(c)	//建構函式!!
	{
		elem = new long double[row*col]();
        //加一個括號就全部初始化成0了
//		elem = new long double[row*col];
/*		for (int i = 0; i < row*col; i++) {
			elem[i] = 0.0;
		}
		cout << "建構函式被呼叫" << endl;*/
	}

2.複製建構函式

​ 什麼情況下起作用:

1. 用一個物件初始化同類的另一個物件——`my_matrix M1(M2)`
2. 某函式的形參是類的物件(也就是按值傳遞,如果是物件的引用傳遞則不會呼叫)
3. 函式的返回值是類的物件或引用(因為進入函式內部的是一個臨時值,離開函式就全部消失了)
	my_matrix(const my_matrix &M)	//複製建構函式
	{
		row = M.row;
		col = M.col;
		elem = new long double[M.row*M.col];		
		for (int i = 0; i < row*col; i++)		//所有的數都複製一遍
		{
			elem[i] = M.elem[i];
		}
		cout << "複製建構函式被呼叫" << endl;
	}

​ 在這裡學到一個新的函式void *memcpy(void *dest, void *src, unsigned int count),可以實現一個位元組一個位元組的拷貝。但是要注意幾個問題:1.首先要判斷指標變數elem是不是空的,直接return。 2.在編寫中發現,如果沒有elem = new long double[M.row*M.col];,則會提示 0xC0000005: 讀取位置 0xFFFFFFFFFFFFFFFF 時發生訪問衝突。我的想法是如果不加上這句話,memcpy函式不知道該複製到哪裡吧。

​ 所以改過之後可以這樣寫。

	my_matrix(const my_matrix &M)	//複製建構函式
	{
		if (!M.elem) {
			elem = NULL;
			col = 0; row = 0;
			return *this;}     
		col = M.col;
		row = M.row;
		elem = new long double[M.row*M.col];		
		memcpy(elem, M.elem, sizeof(long double)*col*row);
    }

3.解構函式

​ 作用:釋放分配的空間。

​ 建構函式可以有多個,但是解構函式只能有一個。

	~my_matrix(void)		//解構函式
	{
		delete[] elem;		
		cout << "解構函式被呼叫" << endl;
    }

4.運算子過載

​ 作用:擴充套件運算子的運算範圍,可以應用於類所表示的資料型別。

4.1過載運算子“=”

​ 淺拷貝:將原來的指標複製一遍(並沒有給新的變數提供新的儲存空間)。新的和舊的指標指向同一個記憶體。如果原來變數的記憶體釋放(析構),那麼複製的那個變數的指標就會變成野指標。並且最後析構的時候,將一塊記憶體析構兩次,也會報錯。

​ 深拷貝:申請新的記憶體空間,使得兩個變數指向不同的記憶體空間。

​ 在這裡也可以用到memcpy(elem, M.elem, sizeof(long double)*col*row);

	my_matrix& operator=(const my_matrix& M)		//深拷貝
	{
		col = M.col;
		row = M.row;
		elem = new long double[row*col];
		for (int i = 0; i < row*col; i++)
			elem[i] = M.elem[i];
		return *this;
	}

4.2過載運算子“*”

​ 將乘號*過載為類的友元函式或者成員函式都可以,過載為成員函式需要使用this指標。

​ 注意由於最後是return temp,所以在不能直接把temp的維度初始化為temp(matrix1.row,matrix2.col),不然在最後檢驗的行列數目不匹配的時候,會輸出一個全是0的矩陣,而不是一個空的矩陣。

	friend my_matrix operator*(const my_matrix& matrix1, const my_matrix& matrix2) {
		my_matrix temp;
		cout << "*運算子過載" << endl;
		if (matrix1.col == matrix2.row) {
			temp.row = matrix1.row;
			temp.col = matrix2.col;
			temp.elem = new long double [temp.row*temp.col]();
			for (int i = 0; i < matrix1.row; i++) {
				for (int j = 0; j < matrix2.col; j++) {
					for (int k = 0; k < matrix1.col; k++) {
						temp.elem[i*matrix2.col + j] += matrix1.elem[i*matrix1.col + k] * matrix2.elem[k*matrix2.col + j];
					}
				}
			}
		}
		else {
			cout << "行數和列數不等" << endl;
		}
		return temp;
	}

4.3過載運算子“<<”

​ 流運算子必須是全域性函式的形式,不能是成員函式。cout是iostream中定義的,是ostream類的物件。

​ 返回值是ostream的引用,這樣的話就可以連續輸出。第一個引數要是cout,因為使用的時候呼叫函式為cout.operator<<(),第二個引數是類的物件。

​ 這個函式的寫法很奇妙啊,第一次把另一個類的物件寫到函式裡面。

	friend ostream&operator<<(ostream &out, const my_matrix& matrix)
	{
		for (int i = 0; i < matrix.row; i++) {
			for (int j = 0; j < matrix.col; j++) {
				out << matrix.elem[i*matrix.col + j] << " ";
			}
			out << endl;
		}
		return out;
	}

5.輸入和輸出函式

5.1輸入函式

	void getelem()		//獲取元素
	{
		cout << "輸入元素" << endl;
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				cin >> elem[i*col + j];
			}
		}
	}

5.2輸出函式

	void save_matrix()
	{
		ofstream outfile("matrix_nn.txt");
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				outfile << elem[i] << " ";
			}
			outfile << endl;
		}
	}