矩陣類——實現矩陣相乘
矩陣類——實現矩陣相乘
剛開始學習C++,有什麼地方寫的不對的,懇請大家批評指正!
要求:定義矩陣類,實現矩陣相乘,並將結果輸出在螢幕上、儲存到 .txt檔案中
分析問題:定義一個矩陣類Class my_matrix
,使用指標成員變數elem
實現大小可變的矩陣(此處用一維陣列存放矩陣的元素),定義私有成員row、col
。必備的是建構函式、複製建構函式、解構函式;為了實現深拷貝,需要過載運算子=
;由於原有的乘號*並不知道如何對你的矩陣類進行操作,所以要過載運算子*
;在螢幕上輸出陣列,需要過載流運算子<<
;矩陣元素輸入時需要函式void getelem()
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;
}
}