C++实验一(CMatrix类的设计与实现)

[原编辑时间: 2021-10-07 17:15:23]

实验步骤

1. 重载的定义

本次实验的知识重点是函数的重载,函数重载的定义如下:

重载是指在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。且不能仅通过返回类型的不同来重载函数。

2. 实验源码

2.1 头文件

#ifndef CMATRIX_H
#define CMATRIX_H
#include <iostream>  
using namespace std;
//类定义
class CMatrix
{
public:
	CMatrix();
	//pDate是带有数据指针的参数
	CMatrix(int nRow, int nCol, double* pData = NULL);

	//拷贝构造函数
	CMatrix(const CMatrix& m);

	//带文件路径参数的构造函数
	CMatrix(const char* strPath);

	//(析构函数)调用Release()
	~CMatrix();

	//先删除原有空间,根据传入行列创建空间,如果pDate不为空要将pDate的内容拷贝到m_pDate中
	bool Create(int nRow, int nCol, double* pData = NULL);
	void Set(int nRow, int nCol, double dVale);

	//将内存释放,并将行列设置为0
	void Release();

	//全局函数
	friend istream& operator>>(istream& is, CMatrix& m);
	friend ostream& operator<<(ostream& os, const CMatrix& m);

	CMatrix& operator=(const CMatrix& m);
	CMatrix& operator+=(const CMatrix& m);
	double& operator[](int nIndex);
	double& operator()(int nRow, int nCol);
	bool operator ==(const CMatrix& m);
	bool operator !=(const CMatrix& m);
	operator double();

private:
	int m_nRow;
	int m_nCol;
	double* m_pData;
};
CMatrix operator+(const CMatrix& m1, const CMatrix& m2);

//内联成员函数的显式声明(代码简单,被频繁调用)
inline void CMatrix::Set(int nRow, int nCol, double dVal) {
	m_pData[nRow * m_nCol + nCol] = dVal;
}
#endif

2.2 CMatrix模块文件

#include "CMatrix.h"
#include <fstream>
#include <assert.h>

//参数的初始化
CMatrix::CMatrix() :m_nRow(0), m_nCol(0), m_pData(NULL)
{

}

//pDate是传入的数组参数
CMatrix::CMatrix(int nRow, int nCol, double* pData) : m_pData(NULL)
{
	Create(nRow, nCol, pData);
}
CMatrix::CMatrix(const CMatrix& m) : m_pData(NULL)
{
	*this = m;
}
CMatrix::CMatrix(const char* strPath)
{
	m_pData = NULL;
	m_nRow = m_nCol = 0;
	ifstream cin(strPath);
	cin >> *this;
}

//析构函数
CMatrix::~CMatrix()
{
	Release();
}
bool CMatrix::Create(int nRow, int nCol, double* pData)
{
	Release();
	//m_pData = new double(nRow * nCol);
	m_pData = new double[nRow * nCol];
	m_nRow = nRow;
	m_nCol = nCol;
	if (pData != NULL)
	{
		/*库函数 void *memcpy(void *str1, const void *str2, size_t n)表示
		从存储区 str2 复制 n 个字节到存储区 str1,该函数返回一个指向目标存储区 str1 的指针
		参数:
		str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
		str2 -- 指向要复制的数据源,类型强制转换为 void* 指针。
		n -- 要被复制的字节数。*/
		memcpy(m_pData, pData, nRow * nCol * sizeof(double));
		return true;
	}
}
void CMatrix::Release()
{
	//释放数组内存
	if (m_pData != NULL)
	{
		delete[]m_pData;
		m_pData = NULL;
	}
	m_nRow = m_nCol = 0;
}

CMatrix& CMatrix::operator=(const CMatrix& m) {
	if (this != &m) {
		Create(m.m_nRow, m.m_nCol, m.m_pData);
	}
	return *this;
}

//运算符重载
CMatrix& CMatrix::operator+=(const CMatrix& m) {
	assert(m_nRow == m.m_nRow && m_nCol == m.m_nCol);
	for (int i = 0; i < m_nRow * m_nCol; i++)
	{
		m_pData[i] += m.m_pData[i];
	}
	return *this;
}
CMatrix operator+(const CMatrix& m1, const CMatrix& m2) {
	CMatrix m3(m1);
	m3 += m2;
	return m3;
}
double& CMatrix::operator[](int nIndex) {
	assert(nIndex < m_nRow* m_nCol);
	return m_pData[nIndex];
}
double& CMatrix::operator()(int nRow, int nCol) {
	assert(nRow * m_nCol + nCol < m_nRow* m_nCol);
	return m_pData[nRow * m_nCol + nCol];
}
bool CMatrix::operator == (const CMatrix& m) {
	if (!(m_nRow == m.m_nRow && m_nCol == m.m_nCol)) {
		return false;
	}
	for (int i = 0; i < m_nRow * m_nCol; i++)
	{
		if (m_pData[i] != m.m_pData[i])
		{
			return false;
		}
	}
	return true;
}
bool CMatrix::operator !=(const CMatrix& m) {
	return !((*this) == m);
}
CMatrix::operator double()
{
	double dS = 0;
	for (int i = 0; i < m_nRow * m_nCol; i++)
	{
		dS += m_pData[i];
	}
	return dS;
}
istream& operator>>(istream& is, CMatrix& m) {
	is >> m.m_nRow >> m.m_nCol;
	m.Create(m.m_nRow, m.m_nCol);
	for (int i = 0; i < m.m_nRow * m.m_nCol; i++)
	{
		is >> m.m_pData[i];
	}
	return is;
}
ostream& operator<<(ostream& os, const CMatrix& m)
{
	os << m.m_nRow << " " << m.m_nCol << endl;
	double* pData = m.m_pData; 	for (int i = 0; i < m.m_nRow; i++)
	{
		for (int j = 0; j < m.m_nCol; j++)
		{
			os << *pData++ << " ";
		}
		os << endl;
	}
	return os;
}

3. 主函数及其实现过程

3.1 简单构造函数的使用

主函数代码如下:

#include <iostream>
#include "CComplex.h"
#include <stdio.h>
#include "CMatrix.h"
using namespace std;
int main(int argc, char** argv) {
	double pData[10]={2,3,4,5,6,1,3,5,7,9};
	//定义类变量,m2是四参数的构造函数
	CMatrix m1(2,5,pData); 
	cout<< "m1的输出结果为:\n" << m1;
}

其中,m1(2,5,pData)调用构造函数CMatrix(int nRow, int nCol, double* pData = NULL);从而实现m1变量的值域的初始化,运行结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gSp0lg5Q-1679318042186)(images/2021-10-07_bece6128-3829-47e8-9cac-1a5e60b7c37b.png)]


从控制台获取输入值初始化变量的值域
代码如下(省略main(){}函数部分):

CMatrix m1; 
cin>>m1;
cout<< "m1的输出结果为:\n" << m1;

运行结果:
在这里插入图片描述

3.2 从文本文件中读取数值进行构造

使用如下函数从文本文件中读取数值:

//全局函数
friend istream& operator>>(istream& is, CMatrix& m);
friend ostream& operator<<(ostream& os, const CMatrix& m);

其中istream表示从流里读取一个类,ostream表示把一个类输出到流。
文件内容:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d2sMBEyG-1679318042188)(images/2021-10-07_254e9a8d-c349-4562-bcbd-9067c1c848a9.png)]

代码如下:

CMatrix m2("C:\\Users\\lenovo\\Desktop\\1.txt"); 
cout<< "m2的输出结果为:\n" << m1;

运行结果:

3.3 使用Set函数修改值

Set函数的定义:

inline void CMatrix::Set(int nRow, int nCol, double dVal) {
	m_pData[nRow * m_nCol + nCol] = dVal;
}

该函数是一个内联成员函数的显式声明,内联成员函数的函数体会在编译时被插入到每个调用它的地方,特点:

  • 代码结构简单
  • 被其他函数频繁调用

内联成员函数的优点:减少调用的开销,提高执行效率
代码如下:

CMatrix m1(2, 5, pData);
cout << "m1的原始输出结果为:\n" << m1;
m1.Set(1, 3, 99);
cout << "m1修改之后的输出结果为:\n" << m1;

运行结果:

3.4 运算符的重载

如果在代码中将Matrix变量m1的值赋给m3,则该操作的结果是m3和m1会使用同一个指针地址(数组地址),导致的结果是若改变m1或m3中数组的其中一个值则另一个对应的值也会同时改变,因此为了避免此结果的发生需对运算符"="进行重载,重载函数如下:

CMatrix& CMatrix::operator=(const CMatrix& m) {
	if (this != &m) {
		Create(m.m_nRow, m.m_nCol, m.m_pData);
	}
	return *this;
}

代码如下(省略main(){}函数部分):

//定义类变量,m1是四参数的构造函数
CMatrix m1(2, 5, pData),
m2("C:\\Users\\lenovo\\Desktop\\1.txt"), m3,m4(m2);
m3 = m1;
m1.Set(1, 3,88);
cout << "m1的输出结果为:\n" << m1;
cout << "m3的输出结果为:\n" << m3;

运行结果:
在这里插入图片描述


运算符"+="的重载
重载函数:

CMatrix& CMatrix::operator+=(const CMatrix& m) {
	assert(m_nRow == m.m_nRow && m_nCol == m.m_nCol);
	for (int i = 0; i < m_nRow * m_nCol; i++)
	{
		m_pData[i] += m.m_pData[i];

	}
	return *this;
}

代码如下(省略main(){}函数部分):

double pData[10]={2,3,4,5,6,1,3,5,7,9};
//定义类变量,m2是四参数的构造函数
CMatrix m1(2, 5, pData),
m2("C:\\Users\\lenovo\\Desktop\\1.txt"), m3,m4(m2);
m3 = m1;
m1.Set(1, 3,88);
m3 += m2;
cout << "m3的输出结果为:\n" << m3;
return 0;

运行结果:

其余运算符的重载在此不一一列举。

3.5 析构函数

析构函数用来完成对象被删除前的一些清理工作,析构函数在对象的生存周期即将结束会被自动调用,它的调用完成之后,对象相应的内存空间将被释放。

本实验中的析构函数如下:

void CMatrix::~Release()
{
	//释放数组内存
	if (m_pData != NULL)
	{
		delete[]m_pData;
		m_pData = NULL;
	}
	m_nRow = m_nCol = 0;
}

当该析构函数被某个变量调用时,该变量的数组内存空间将被释放,在对象变量的创建之前也可调用析构函数来清空该变量之前可能存在而没有清空的值。

4. 总结

本次实验重点学习了C++中构造函数的使用以及一些运算符的重载,了解了构造函数中初始化值域的不同方法,也让我对C++中对类的抽象封装和成员函数有了更加深入的理解,函数的重载使得对于类中成员变量的操作变得更加的细化。同时也了解了从流中读取变量、将变量输出到流的方法,但是由于对部分函数功能的不理解,导致在使用函数传参时出现错误,因此需结合函数的具体实现和用法来正确使用函数,此外,本实验也从多个方面来对重载函数和构造函数的使用进行演示,在加深印象的同时也能对代码的执行流程有更深刻的了解。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值