矩阵类——实现矩阵相乘

矩阵类——实现矩阵相乘

​ 刚开始学习C++,有什么地方写的不对的,恳请大家批评指正!

​ 要求:定义矩阵类,实现矩阵相乘,并将结果输出在屏幕上、保存到 .txt文件中

​ 分析问题:定义一个矩阵类Class my_matrix,使用指针成员变量elem实现大小可变的矩阵(此处用一维数组存放矩阵的元素),定义私有成员row、col。必备的是构造函数、复制构造函数、析构函数;为了实现深拷贝,需要重载运算符=;由于原有的乘号*并不知道如何对你的矩阵类进行操作,所以要重载运算符*;在屏幕上输出数组,需要重载流运算符<< ;矩阵元素输入时需要函数void getelem()获取元素,结果保存到.txt文件中需要一个成员函数void save_matrix()

文章目录

  • 矩阵类——实现矩阵相乘
    • 1.构造函数
    • 2.复制构造函数
    • 3.析构函数
    • 4.运算符重载
      • 4.1重载运算符“=”
      • 4.2重载运算符“*”
      • 4.3重载运算符“<<”
    • 5.输入和输出函数
      • 5.1输入函数
      • 5.2输出函数

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

你可能感兴趣的:(C++)