- 一、CMatrix类的代码实现
- 1. main.cpp
- 2. CMatrix.h
- 3. CMatrix.cpp
- 二、运行结果
- 三、函数
- 1. 构造函数
- (1)分类
- (2)特点
- 2. 析构函数
- 3. 运算符重载
- 4. 友元函数
- 5. 内联函数
- (1)显示
- (2)隐式
#include2. CMatrix.h#include "CComplex.h" #include #include "CMatrix.h" using namespace std; int main(int argc, char** argv) { //初始化,调用CMatrix() CMatrix m; cin >> m; cout << "m = " << m << endl; double pData[10] = { 1,2,3,4,5 }; CMatrix m1(2, 5, pData); CMatrix m2("1.txt"); cout << "m2 = n" << m2 << endl; CMatrix m3(m1); CMatrix m4; //指向等一个地方 m4 = m1; //第0行第1列改为20 m1.Set(0, 1, 20); //此处m1,m4相同 cout << "m3 = n" << m3 << endl; cout << "m1 = n" << m1 << endl; cout << "m4 = n" << m4 << endl; m4 = m4; cout << "new m4 = n" << m4 << endl; //[]重载,[0,1]不允许带多个参数 cout << "m4[8] = " << m4[8] << endl; //()重载,()允许带多个参数 m4(1, 1) = 10; cout << "m4(1,1) = " << m4(1, 1) << endl; if (m4 == m1) { cout << "Error!" << endl; } //+重载 CMatrix m5; m5 = m1 + m4; cout << "m5 = n" << m5 << endl; //double重载 double d = m5; cout << "sum of m5 = " << d << endl; return 0; }
#pragma once #ifndef CMATRIX_H #define CMATRIX_H #include3. CMatrix.cppusing namespace std; class CMatrix { public: //不带参数的构造函数 CMatrix(); //如果nRow=0有默认值则之后的都得有默认值 //若都默认值为0,相当于无参数,则会与上一个构造函数CMatrix();产生歧义,不知道调用哪一个 //带行、列及数据指针等参数的构造函数, 并且参数带默认值 CMatrix(int nRow, int nCol, double* pData = NULL); //拷贝构造函数 CMatrix(const CMatrix& m); //带文件路径参数的构造函数 CMatrix(const char* strPath); //析构函数名应与类名相同,只是在函数名前面加一个位取反符,以区别于构造函数。 //它不能带任何参数,也没有返回值(包括void类型)。由于没有函数参数,因此它不能被重载,只能有一个析构函数。 //如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数(即使自定义了析构函数,编译器也总是会为我们合成一个析构函数,并且如果自定义了析构函数,编译器在执行时会先调用自定义的析构函数再调用合成的析构函数),它也不进行任何操作。所以许多简单的类中没有用显示的析构函数。 //当对象的生命周期结束时,撤销类对象时候会自动调用析构函数。 //1.对象在生命期结束,撤销类对象时会自动调用析构函数。 //2.如果用new运算动态地建立一个对象,那用delete运算符释放该对象时,才会调用析构函数。 ~CMatrix(); bool Create(int nRow, int nCol, double* pData = NULL); void Set(int nRow, int nCol, double dVal); //隐式内联函数,不声明 //void CMatrix::Set(int nRow, int nCol, double dVal) { // m_pData[nRow * m_nCol + nCol] = dVal; //} void Release(); //赋予特权,特殊声明,friend加了之后为全局函数不是成员函数,类里面定义的所有对象都可以调用,所以可以访问下面的private私有变量 //输出输入流运算符重载,原本输出输入流只能针对基础的数据类型,比如char,int,double,指针,重载后使其能够读取自己定义的类 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); // CMatrix operator+(const CMatrix& m1,const CMatrix& m2); 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 // !CMATRIX_H
#include "CMatrix.h" #include二、运行结果 三、函数 1. 构造函数#include //这种初始化方式提高效率,顺序与成员变量原来的顺序一样,可同时与下面的初始化方式共用 CMatrix::CMatrix() :m_nRow(0), m_nCol(0), m_pData(NULL){ //先申请空间完之后才赋值 //m_nRow = 0; //m_nCol = 0; //m_pData = NULL; } CMatrix::CMatrix(int nRow, int nCol, double* pData) : m_pData(NULL) { //因为Create中有Release(),如果不初始化会因为不是NULL直接delete Create(nRow, nCol, pData); } //拷贝构造函数 CMatrix::CMatrix(const CMatrix& m) : m_pData(NULL) { *this = m; } //方法1: //CMatrix::CMatrix(const CMatrix& m) : { // m_nRow = 0; // m_nCol = 0; // m_pData = NULL; // Create(m_nRow, m_nCol, m_pData); //} //方法2:构造该函数,用另一个构造函数去构造 //CMatrix::CMatrix(const CMatrix& m) : CMatrix(m.m_nRow,m.m_nCol,m.m_pData) { // //} CMatrix::CMatrix(const char* strPath) { m_pData = NULL; m_nRow = m_nCol = 0; ifstream is(strPath); is >> *this; } CMatrix::~CMatrix() { Release(); } bool CMatrix::Create(int nRow, int nCol, double* pData) { Release(); m_nRow = nRow; m_nCol = nCol; //新建空间存储数据 m_pData = new double[nRow * nCol]; //当nRow*nCol数据过大时,m_pData分配空间不足,此时m_pData就会为空 if (m_pData != NULL) { if (pData!=NULL) { //void *memcpy(void *destin, void *source, unsigned n); //作用是:以source指向的地址为起点,将连续的n个字节数据,复制到以destin指向的地址为起点的内存中。 //函数有三个参数,第一个是目标地址,第二个是源地址,第三个是数据长度。 memcpy(m_pData, pData, nRow * nCol * sizeof(double)); } } else { return false; } return true; } //delete之后赋值为空,delete指针之后只是释放了空间,指针依旧存在且指向原来的地址,此时对该指针的操作都将十分容易报错 void CMatrix::Release() { if (m_pData!=NULL) { delete []m_pData; m_pData = NULL; } m_nRow = m_nCol = 0; } CMatrix& CMatrix::operator=(const CMatrix& m) { //判断如果等号左右相同,直接返回,否则会是空,因为Create开头是Release //等号运算符重载该有的判断 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); } //前面无double但是有返回值,因为这是强制类型转换,已经知道返回值就是double 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) { //m.Release();后面Create开始就有 此处可以省略 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; //上面的方法效率更高 //os << m.m_nRow << "" << m.m_nCol << endl; //for (int i = 0; i < m.m_nRow; i++) { // for (int j = 0; j < m.m_nCol; j++) { // os << m.m_pData[i * m.m_nCol + j] << " "; // } // os << endl; //} //return os; }
//不带参数的构造函数 CMatrix(); //如果nRow=0有默认值则之后的都得有默认值 //若都默认值为0,相当于无参数,则会与上一个构造函数CMatrix();产生歧义,不知道调用哪一个 //带行、列及数据指针等参数的构造函数, 并且参数带默认值 CMatrix(int nRow, int nCol, double* pData = NULL); //拷贝构造函数 CMatrix(const CMatrix& m); //带文件路径参数的构造函数 CMatrix(const char* strPath);(1)分类
- 不带参数的构造函数
- 带有参数的构造函数
- 拷贝构造函数
- 带文件路径参数的构造函数
- (2)特点
构造函数具有如下几个特点:
- 名字与类名相同,可以有参数,但是不能有返回值(void也不行);
- 作用是对对象进行初始化工作,如给成员变量赋值等;
- 如果定义类时没有写构造函数,系统会生成一个默认的无参构造函数,默认构造函数没有参数,不做任何工作;
- 如果定义了构造函数,系统不再生成默认的无参构造函数;
- 对象生成时构造函数自动调用,对象一旦生成,不能在其上再次执行构造函数
- 一个类可以有多个构造函数,为重载关系。
- 2. 析构函数
//析构函数名应与类名相同,只是在函数名前面加一个位取反符,以区别于构造函数。 //它不能带任何参数,也没有返回值(包括void类型)。由于没有函数参数,因此它不能被重载,只能有一个析构函数。 //如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数(即使自定义了析构函数,编译器也总是会为我们合成一个析构函数,并且如果自定义了析构函数,编译器在执行时会先调用自定义的析构函数再调用合成的析构函数),它也不进行任何操作。所以许多简单的类中没有用显示的析构函数。 //当对象的生命周期结束时,撤销类对象时候会自动调用析构函数。 //1.对象在生命期结束,撤销类对象时会自动调用析构函数。 //2.如果用new运算动态地建立一个对象,那用delete运算符释放该对象时,才会调用析构函数。 ~CMatrix();
- 格式:在类名前加上~;且与构造函数不同的是,析构函数从来没有参数。
- 作用:当对象的生命周期结束时,撤销类对象时候会自动调用析构函数。 1.对象在生命期结束,撤销类对象时会自动调用析构函数。 2.如果用new运算动态地建立一个对象,那用delete运算符释放该对象时,才会调用析构函数。
- 3. 运算符重载
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);
C++预定义中的运算符的操作对象只局限于基本的内置数据类型,但是对于我们自定义的类型(类)是没有办法操作的。但是大多时候我们需要对我们定义的类型进行类似的运算,这个时候就需要我们对这么运算符进行重新定义,赋予其新的功能,以满足自身的需求。
4. 友元函数//赋予特权,特殊声明,friend加了之后为全局函数不是成员函数,类里面定义的所有对象都可以调用,所以可以访问下面的private私有变量 //输出输入流运算符重载,原本输出输入流只能针对基础的数据类型,比如char,int,double,指针,重载后使其能够读取自己定义的类 friend istream& operator>>(istream& is, CMatrix& m); friend ostream& operator<<(ostream& os, const CMatrix& m);
在实现类之间数据共享时,减少系统开销,提高效率。
5. 内联函数以牺牲代码段空间为代价,提高程序的运行时间的效率(入栈与出栈操作)。
(1)显示 - 放在类外
//显式内联函数,好处相当于直接把函数放过去没有调用函数,调用函数还需要出栈入栈 //十几行较多行的代码,递归,循环不建议写成内联函数 inline void CMatrix::Set(int nRow, int nCol, double dVal) { m_pData[nRow * m_nCol + nCol] = dVal; }(2)隐式- 放在类内
void CMatrix::Set(int nRow, int nCol, double dVal) { m_pData[nRow * m_nCol + nCol] = dVal; }



