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

目录

一、代码理解

        CMatrix.h

        CMatrix.cpp

        Main.cpp

        运行结果

二、总结


一、代码理解

        CMatrix.h

#ifndef CMATRIX_H  //防止被重复引用
#define CMATRIX_H 

#include<iostream>
using namespace std;

class CMatrix
{
public:
    //构造器
	CMatrix();//不带参数的构造函数
	CMatrix(int nRow,int nCol, double* pData = NULL);//带行、列及数据指针等参数的构造函数,并且参数带默认值
	CMatrix(const CMatrix& m);//拷贝构造函数
	CMatrix(const char * strpath);//带文件路径参数的构造函数
	~CMatrix();//析构函数

	bool Create(int nRow, int nCol, double* pData = NULL);

	void Set(int nRow, int nCol, double dVale);
	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);
	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=NULL;
};

CMatrix operator+(const CMatrix& m1, const CMatrix& m2);
CMatrix operator-(const CMatrix& m1, const CMatrix& m2);

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

#endif // !CMATRIX_H

  • 友元函数:友元函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数。友元函数可以访问当前类中的所有成员,包括 public、protected、private 属性的  

        详细可以看这篇文章:(30条消息) C++ friend 用法总结_eskimoer的专栏-CSDN博客_c++ friendicon-default.png?t=L892https://blog.csdn.net/ddupd/article/details/38053159

  • #ifndef/#define/#endif  :防止头文件被重复引用,Eg:存在a.h文件#include "c.h"而此时b.cpp文件导入了#include "a.h" 和#include "c.h"此时就会造成c.h重复引用。
  • C++重载运算符  :重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。Box operator+(const Box&);

C++ 重载运算符和重载函数 | 菜鸟教程 (runoob.com)icon-default.png?t=L892https://www.runoob.com/cplusplus/cpp-overloading.html

  • inline内联函数:在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。

    栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。

        CMatrix.cpp

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

//对类成员进行初始化  无参构造器
// 无参构造器:
CMatrix::CMatrix() :m_nRow(0), m_nCol(0), m_pData(0)
{

}
//带行、列及数据指针等参数的构造函数,并且参数带默认值
CMatrix::CMatrix(int nRow, int nCol, double* pData) : m_pData(0)
{
	Create(nRow, nCol, pData); // 调用新建类对象方法
}

//拷贝构造函数 
CMatrix::CMatrix(const CMatrix& m) : m_pData(0)
{
	*this = m;
}
//带文件路径参数的构造函数
CMatrix::CMatrix(const char* strPath)
{
	m_pData = 0;
	m_nRow = m_nCol = 0;
	ifstream cin(strPath);//通过ifstream定义输入流对象
	cin >> *this;
}
//析构函数
CMatrix::~CMatrix() {
	//Release()基本就是用来释放资源的
	Release();
}

bool CMatrix::Create(int nRow, int nCol, double* pData)
{
	//将数据赋值为空
	Release();
	m_pData = new double[nRow * nCol];
	m_nCol = nCol;
	m_nRow = nRow;
	if (pData != NULL)
	{
		//void* memcpy(void* str1, const void* str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1。
		//https://www.runoob.com/cprogramming/c-function-memcpy.html
		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;
}

//运算符重载

//C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。
//重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
//https://www.runoob.com/cplusplus/cpp-overloading.html


//一、关系运算符重载
//1.赋值运算符重载
CMatrix& CMatrix::operator=(const CMatrix& m)
{
	if (this != &m) {
		Create(m.m_nRow, m.m_nCol, m.m_pData);
	}
	return *this;
}
//2.恒等号运算符重载
bool CMatrix::operator == (const CMatrix& m)
{
	if (!m_nRow == m.m_nRow && m_nCol == m.m_nRow) {

		return false;
	}
	//比较元素是否相等
	for (int i = 0; i < m_nCol * m_nRow; i++) {
		if (m_pData[i] != m.m_pData[i])
			return false;
	}

	return true;
}
bool CMatrix::operator != (const CMatrix& m)
{
	return !((*this) == m);
}

//二、算术运算符重载
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;
}
CMatrix operator-(const CMatrix& m1, const CMatrix& m2)
{
	CMatrix m3(m1);
	m3 -= m2;
	return 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;
}
//三、操作符重载
double& CMatrix::operator[](int nIndex)
{
	assert(nIndex < m_nCol* m_nRow);
	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];
}

//强制类型转换
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_nCol >> m.m_nRow;
	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;

}

//C++中的ostream这个类型,通常作为某个类的友元函数出现,用于<<操作重载中

// 重载操作符”<<“
// 使得“<<”操作符能够打印 CMatrix 数据类型
ostream& operator<<(ostream& os, const CMatrix& m)
{
	os << "size:[" << 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;
}

        Main.cpp

#include <iostream>
#include <stdio.h>
#include "cmatrix.h"
#include<fstream>
using namespace std;


int main(int argc, char** argv) {
    double pData[10] = { 2,3,4,5 };

    ifstream file;
    file.open("1.txt");
    if (!file.is_open())
    {
        std::cerr << "cannot open the file" << endl;
    }
    else
        std:cout << "文件读取成功" << endl;
    CMatrix m1, m2(2, 5, pData), m3("1.txt"), m4(m2);
    cout << "输入数据" << endl;
    cin >> m1;

    cout <<"输出"<< m1 << m2 << m3 << m4;

    m2.Set(0, 2, 10);
    cout << "修改后的m2" << m2 << endl;
    if (m4 == m3)
    {
        cout << "Error !" << endl;
    }
    m3 += m1;
    cout << "m3 += m1:\n" << m3;
    return 0;
}

        运行结果

二、总结

构造函数&析构函数

  • 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
  • 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

构造函数语法:类名(){}

  1. 构造函数,没有返回值也不写void
  2. 函数名称与类名相同
  3. 构造函数可以有参数,因此可以发生重载
  4. 程序在调用对象时候会自动调用构造函数,无须手动调用,而且只会调用一次

析构函数语法: ~类名(){}

  1. 析构函数,没有返回值也不写void
  2. 函数名称与类名相同,在名称前加上符号~
  3. 析构函数不可以有参数,因此不可以发生重载
  4. 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次

构造函数的分类

两种分类方式:

​ 按参数分为: 有参构造和无参构造

​ 按类型分为: 普通构造和拷贝构造

通过本次实验了解了构造函数,析构函数,运算符重载和友元函数的部分知识,并通过代码实践

推荐阅读:

(30条消息) C++核心编程(二)_Augenstern_QXL的博客-CSDN博客_c++icon-default.png?t=L892https://blog.csdn.net/Augenstern_QXL/article/details/117253730?spm=1001.2014.3001.5501

猜你喜欢

转载自blog.csdn.net/m0_50945459/article/details/120688611