目录
一、代码理解
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 属性的
- #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)https://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;
}
运行结果
二、总结
构造函数&析构函数
- 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
- 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。
构造函数语法:类名(){}
- 构造函数,没有返回值也不写void
- 函数名称与类名相同
- 构造函数可以有参数,因此可以发生重载
- 程序在调用对象时候会自动调用构造函数,无须手动调用,而且只会调用一次
析构函数语法: ~类名(){}
- 析构函数,没有返回值也不写void
- 函数名称与类名相同,在名称前加上符号
~
- 析构函数不可以有参数,因此不可以发生重载
- 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
构造函数的分类
两种分类方式:
按参数分为: 有参构造和无参构造
按类型分为: 普通构造和拷贝构造
通过本次实验了解了构造函数,析构函数,运算符重载和友元函数的部分知识,并通过代码实践
推荐阅读: