- 初识C++:CMatrix类的实现
- 1.头文件声明 `Cmatrix.h`
- 2.类内部方法,函数的实现 `CMatrix.cpp`
- 2.1构造器(Constructor)
- 2.1.1 缺省构造器
- 2.1.2 有参构造器
- 2.2析构函数(Destructor)
- 2.3 `CMatrix` 对象方法
- 2.3.1对象初始化
- 2.3.2 对象销毁方法
- 2.4 `CMatrix` 运算符重载
- 2.4.1 赋值运算符重载
- 2.4.2关系运算符重载
- 2.4.3运算符重载
- 2.4.4 操作符重载
- 3.主函数测试样例`main.cpp`
头文件主要用于声明CMatrix类以及类内部的属性和构造函数,和各种实现方法。
#ifndef CMATRIX_H #define CMATRIX_H #includeusing 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 Release(); // 内联函数 void Set(int nRow, int nCol, double dVale); // 友元函数,允许一个函数或类访问类的私有属性 // 重载操作符 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); bool operator ==(const CMatrix& m); bool operator !=(const CMatrix& m); double & operator[](int nIndex); double & operator()(int nRow, int nCol); // 重载类型转换 operator double(); // vscode 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]=dVal; } #endif
其中,这三行代码属于条件编译宏定义,可以根据条件选择性的只编译某段程序,也可以防止重复定义。
#ifndef CMATRIX_H #define CMATRIX_H // ... ... #endif2.类内部方法,函数的实现 CMatrix.cpp 2.1构造器(Constructor)
构造器最大的用处就是在创建对象时执行初始化,当创建一个对象时,系统会为这个对象的实例进行默认的初始化。如果想改变这种默认的初始化,就可以通过自定义构造器来实现。
由于c++面向对象语言的特性,构造器可以实现重载,即一个类可以有多个构造器。一个类的构造器的名称必须与该类的名称一致。
// 无参构造器:
CMatrix::CMatrix()
{
m_nRow = 0;
m_nCol = 0;
m_pData = NULL;
}
无参构造器(使用初始化表达式):
// 无参构造器(使用初始化表达式)
// 其中传入参数的顺序和在类间定义时的顺序一致
// 在初始化时更有效率
CMatrix::CMatrix():m_nRow(0),m_nCol(0),m_pData(0)
{
//初始化为NULL
}
2.1.2 有参构造器
//有参构造器
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; // *this表示对象指针,因此只赋值了地址
}
外部数据流构造函数
// 外部数据流构造函数
CMatrix::CMatrix(const char * strPath):m_nRow(0),m_nCol(0),m_pData(0)
{
ifstream cin(strPath); //通过ifstream定义输入流对象
//将输入流地址赋值给对象指针
cin>>*this;
}
2.2析构函数(Destructor)
析构函数与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。
// 析构函数
// 析构函数无参, 不可重载
// 程序在对象销毁前自动调用析构函数,无需手动调用
CMatrix::~CMatrix()
{
Release(); // 调用类方法
}
2.3 CMatrix 对象方法
2.3.1对象初始化
// 新建类对象方法
bool CMatrix::Create(int nRow, int nCol, double *pData)
{
// 首先在构造前需将其数据指针赋值为空
Release();
// 赋值
m_pData = new double[nRow*nCol];
m_nRow = nRow;
m_nCol = nCol;
if(pData != NULL)
{
// 将传入的pData赋值给类内部变量m_pData(内存拷贝的方式)
memcpy(m_pData, pData, nRow*nCol*sizeof(double));
}
}
2.3.2 对象销毁方法
// 销毁对象方法
void CMatrix::Release()
{
//如果指针非空将其指向空
if(m_pData != NULL)
{
delete []m_pData;
m_pData = NULL;
}
//初始化0
m_nRow = m_nCol = 0;
}
2.4 CMatrix 运算符重载
在c++中,可以重定义或重载大部分内置的运算符。这样就可以使用自定义类型的运算符,实现更为复杂的运算。
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
2.4.1 赋值运算符重载//运算符重载(对已有运算符重新定义,赋予其另一种功能,以适应不同的数据类型)
// "="重载
CMatrix& CMatrix::operator=(const CMatrix& m)
{
//如果自己对自己赋值就直接跳过,这是因为Create方法会首先调用Release(),导致原数据被释放
if(this!=&m){
// 这里的“=”赋值采用Create方法,是深拷贝
Create(m.m_nRow, m.m_nCol, m.m_pData);
}
return *this;
}
2.4.2关系运算符重载
运算符”==“重载
//运算符”==“重载
bool CMatrix::operator == (const CMatrix& m)
{
//如果两者连尺寸都不相等则直接返回不相等
if(!(m_nRow==m.m_nRow && m_nCol==m.m_nCol)){
return false;
}
//否则一个个比较元素
for(int i=0;i
“!=“运算符重载
// !=运算符重载
bool CMatrix::operator !=(const CMatrix& m){
//"=="重载实现"!="重载
return !((*this)==m);
}
2.4.3运算符重载
// "+="重载
CMatrix& CMatrix::operator+=(const CMatrix& m)
{
//assert断言函数,对括号内的假设进行判断,假如不符合条件就抛出错误,终止程序运行
// 这里的断言函数保证运算符两边的size相等
assert(m_nRow==m.m_nRow && m_nCol==m.m_nCol);
for (int i=0;i
"-="重载
// "-="重载
CMatrix& CMatrix::operator-=(const CMatrix& m)
{
//assert断言函数,对括号内的假设进行判断,假如不符合条件就抛出错误,终止程序运行
// 这里的断言函数保证运算符两边的size相等
assert(m_nRow==m.m_nRow && m_nCol==m.m_nCol);
for (int i=0;i
"+"重载
// "+"重载
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;
}
2.4.4 操作符重载
下标操作符[]重载
// 下标操作符[]重载
double & CMatrix::operator[](int nIndex)
{
//保证下标不越界
assert(nIndex
操作符()重载
// 操作符()重载
// a(2,5)读取矩阵a的第二行第五列
double & CMatrix::operator()(int nRow, int nCol)
{
//保证下标不越界
assert(nRow * m_nCol + nCol < m_nRow * m_nCol);
return m_pData[nRow * m_nCol + nCol];
}
操作符”>>“重载
// 重载操作符”>>“
// 使得“>>”操作符能够读取 CMatrix 数据类型
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_pData[i];
}
return is;
}
操作符”<<“重载
// 重载操作符”<<“
// 使得“<<”操作符能够打印 CMatrix 数据类型
ostream & operator<<(ostream& os, const CMatrix &m)
{
os<<"size:["<
重载强制类型转换
// 重载强制类型转换
CMatrix::operator double()
{
double dS=0;
// 将类型转换重载为矩阵所有元素相加
for(int i=0;i
3.主函数测试样例main.cpp
#include
#include
#include "cmatrix.h"
using namespace std;
int main(int argc, char** argv) {
double pData[10]={2,3,4,5};
CMatrix m1, m2(2,5,pData), m3("../1.txt"), m4(m2);
cin>>m1;
m2.Set(1,3,10);
m4=m3;
m4[2] = m4 + 1;
cout<
运行结果:
pi@raspberrypi:~/Desktop/cpp/build $ ./main
2 2
4 4 4 4
size:[2,2]
4 4
4 4
size:[2,5]
2 3 4 5 0
0 0 0 10 0
size:[2,2]
1 2
3 4
size:[2,2]
1 2
11 4
m4 -= m3:
size:[2,2]
0 0
8 0
m4 -= m3 = 8
pi@raspberrypi:~/Desktop/cpp/build $
值得注意的是,在执行m4 + 1(或者1 + m4)运算的过程中,程序会默认先将m4解析为(double)m4,然后再加1。(这里先留一个小疑问)
还有就是对于双目运算符"+" , "-"的重载,必须定义在类的外部,否则编译过程中会报错。



