cMatrix类及运算符重载
1.cMarix类代码
——类数据成员
数据成员:
private:
int m_nRow
int m_nCol
double * m_pData
——cMatrix.h
#ifndef CMATRIX_H
#define CMATRIX_H
#include<iostream>
#include<assert.h>
using namespace std;
class cMatrix
{
public:
cMatrix();
cMatrix(int nRow, int nCol, double* pData);
cMatrix(const char *strPath);
cMatrix(const cMatrix &m);
bool create(int nRow, int nCol, double* pData=NULL);
~cMatrix();
void Release();
cMatrix& operator +(const cMatrix& m);
cMatrix& operator -(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);
bool operator ==(const cMatrix& m);
double& operator[](int m)
{
assert(m_nCol*m_nRow > m);
return m_pData[m];
}
double& operator()(int m, int n)
{
assert(m_nCol*m_nRow > m*n+n);
return m_pData[m*n+n];
}
operator double();
friend istream& operator >>(istream &is, cMatrix &c); //友元函数,依然是全局函数,不是成员函数
friend ostream& operator <<(ostream &os, cMatrix &c);
void show();
private:
int m_nRow ;
int m_nCol ;
double * m_pData ;
};
#endif // CMATRIX_H
——部分cMarix.cpp
#include "cmatrix.h"
#include<fstream>
#include<assert.h>
cMatrix::cMatrix():m_nRow(0),m_nCol(0),m_pData(NULL)
{
}
cMatrix::cMatrix(int nRow, int nCol, double *pData)
{
m_pData =NULL;
create(nRow, nCol, pData);
}
cMatrix::cMatrix(const char * strPath)
{
m_pData =NULL;
ifstream file(strPath);
file>>*this;
}
cMatrix::cMatrix(const cMatrix &m)
{
create(m.m_nRow,m.m_nCol,m.m_pData); //申请新的空间
// //*this=m;
// m_nRow = m.m_nRow;
// m_nCol = m.m_nCol;
// m_pData = m.m_pData;
}
bool cMatrix::create(int nRow, int nCol, double *pData/*=NULL*/)
{
Release(); //释放旧的内存空间
m_nRow = nRow;
m_nCol = nCol;
m_pData = new double[nRow*nCol]; //申请新的内存空间
if(m_pData!=NULL) //判断是否申请空间成功
{
if(pData!=NULL)
{
memcpy(m_pData,pData,nRow * nCol * sizeof(double));
}
return true;
}
else
return false;
}
cMatrix::~cMatrix(){
Release();
}
void cMatrix::Release()
{
if(m_pData!=NULL)
{
delete[] m_pData;
m_pData = NULL;
}
m_nRow = m_nCol =0;
}
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_pData[i]+m.m_pData[i];
return *this;
}
cMatrix& cMatrix::operator=(const cMatrix& m)
{
if(&m == this)
return *this; //return 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_pData[i]+m.m_pData[i];
return *this;
}
bool cMatrix::operator>(const cMatrix& m)
{
if(m_nRow==m.m_nRow && m_nCol==m.m_nCol)
{
for(int i=0;i<m_nRow*m_nCol;i++)
if(m_pData[i]<m.m_pData[i])
return false;
return true;
}
else
return false;
}
bool cMatrix::operator==(const cMatrix& m)
{
if(m_pData == m.m_pData)
return true;
if(m_nRow==m.m_nRow && m_nCol==m.m_nCol)
{
for(int i=0;i<m_nRow*m_nCol;i++)
if(m_pData[i]!=m.m_pData[i])
return false;
return true;
}
else
return false;
}
cMatrix::operator double()
{
double dsum=0;
for(int i=0;i<m_nCol*m_nRow;i++)
dsum+=m_pData[i];
}
istream& operator>>(istream &is, cMatrix &c)
{
is>>c.m_nRow>>c.m_nCol;
c.create(c.m_nRow,c.m_nCol,c.m_pData);//重新分配空间,原对象的行列可能不再合适
for(int i=0; i<c.m_nCol*c.m_nRow; i++)
{
is>>c.m_pData[i];
}
return is;
}
void cMatrix::show()
{
if(m_pData==NULL)
cout<<"kong"<<endl;
else
for(int i=0;i<m_nRow;i++)
{
for(int j=0;j<m_nCol;j++)
cout<<m_pData[i*m_nCol+j]<<' ';
cout<<endl;
}
}
——main.cpp
#include <iostream>
#include<cmatrix.h>
using namespace std;
int main()
{
//无参构造 及初始化列表
cout<<"c :"<<endl;
cMatrix c;
cout<<c;
//三参构造 重载<<
cout<<"c1 :"<<endl;
double a1[2]={1,2};
cMatrix c1(1,2,a1);
cout<<c1;
//路径参数
cout<<"c2 :"<<endl;
cMatrix c2("c://c2.txt");
cout<<c2;
//复制构造
cout<<"c3 :"<<endl;
cMatrix c3(c1); //创建c3为m_pData新申请了内存空间,和c1的m_pData不指向同一个地址
cout<<c3;
//
cout<<"c4 :"<<endl;
double b[4]={2,4,2,1};
cMatrix c4(1,2,a1);
cout<<c4;
c4.create(2,2,b);
cout<<c4;
//重载+和=
cout<<"c5 :"<<endl;
cMatrix c5;
c5=c1+c3;
cout<<c1;
cout<<c3;
cout<<c5;
//重载-
cout<<"c6 :"<<endl;
cMatrix c6;
c6=c5-c3;
cout<<c6;
cout<<c5;
cout<<c3;
//重载+=
cout<<"c7 :"<<endl;
double a2[3]={1,2,4};
cMatrix c7(1,3,a2);
double a3[3]={2,4,8};
cMatrix c71(1,3,a3);
c7+=c71;
cout<<c7;
//重载-=
cout<<"c8 :"<<endl;
double a4[3]={1,2,4};
cMatrix c8(1,3,a4);
double a5[3]={2,4,8};
cMatrix c81(1,3,a5);
c8-=c81;
cout<<c8;
//重载><
if(c7>c8)
cout<<"yes"<<endl;
if(c8>c7)
cout<<"yes"<<endl;
else
cout<<"no"<<endl;
//重载==
double a6[3]={1,2,4};
cMatrix c9(1,3,a6);
cMatrix c91(1,3,a6);
double a7[3]={2,4,8};
cMatrix c92(1,3,a7);
if(c9==c91)
cout<<"yes"<<endl;
if(c9==c92)
cout<<"yes"<<endl;
else
cout<<"no"<<endl;
//重载[]()
cout<<c9[2]<<endl;
cout<<c92(0,1)<<endl;
}
——运行结果
2.总结与分析
——函数的定义
类型说明符 函数名(含类型说明的形式参数表)
{
函数体
}
类的成员函数
类型说明符 类名::函数名(含类型说明的形式参数表)
{
函数体
}
函数在调用时才执行,为形参分配存储空间,将实参与形参结合。
1.值传递:为形参分配存储空间,用实参初始化形参,形参改变不影响实参。
2.引用传递(int &x=y): 将引用作为形参,对形参的更改同步更改实参。
引用:是一个被引用变量的别名,通过引用名和变量名访问变量的效果一样。
注意:声明一个引用时必须同时初始化,之后不能改为指向其他对象。
带默认参数值的函数
例 int add(int a=1, int b=2);
注意:对同一个参数的默认值定义在同一个作用域内只能声明一次
默认值形参必须在无默认值形参后。
同时在重载时要注意方式二义性。
函数的重载
两个以上的函数,函数名相同,但形参个数或类型不同。
——类的定义
将抽象得到的数据与操作数据的行为相结合形成一个有机的整体,”类“。
类有数据成员和函数成员构成,并对被成员进行访问控制。
class 类名称
{
public:
外部接口
protect:
保护型成员
private:
私有成员
}
有以下三个类型:
public 类型定义了类的外部接口,是成员可以被外部访问。
private 类型定义成私有成员只能被本类的成员访问,拒绝外部访问。
protected 和private类似只是再继承过程中对产生的新类影响不同。
类的初始化与清理由构造函数和析构函数完成。
构造函数:
在对象被创建时利用特定的值构造对象,将对象初始化为一个特定的状态。
函数名与类名相同,没有返回值,声明为公有函数
默认构造函数:
没有参数的构造函数,没有实现默认构造函数,编译器会自动生成,成为合成的默认构造函数,
注意:1.当定义了其他构造函数,编译器不再自动生成默认构造函数。
2.合成的默认构造函数可能会执错误操作,如将数据成员初始化为未定义的值
3.有时不能自动产生。
析构函数:
会在对象的生命期即将结束的时刻自动调用。
——pData=NULL的作用
3.cMatrix(int nRow, int nCol, double* pData)中m_pData=NULL的作用
create()函数 是一个对象调用create函数申请一个新的内存空间将自己变成一个新的对象,同时为了不浪费内存,要先用release()将原内存释放掉。
release() 会调用delete删除内存,同时需考虑到如果m_pDate为NULL的情况无需执行删除。
这就导致cMatrix函数体需要添加 m_pData=NULL
具体原因:
在用cMatrix(int nRow, int nCol, double* pData)初始化对象时,由于对象的m_pData先初始化为未定义的值(不为NULL),而在cMatrix的函数体内代码复用调用了create()导致执行了release(),此时识别到m_pDate!=NULL,执行了delete会出来爆裂。
同理在cMatrix(const char * strPath)也需要m_pData=NULL。
存在另一种解决方法,在定义类的数据成员时直接定义类内初始值
double * m_pData = NULL;
(定义对象时,先类内初始化值,没有则初始化为未定义值。)
cMatrix::cMatrix(int nRow, int nCol, double *pData)
{
m_pData =NULL;
create(nRow, nCol, pData);
}
bool cMatrix::create(int nRow, int nCol, double *pData/*=NULL*/)
{
Release(); //释放旧的内存空间
m_nRow = nRow;
m_nCol = nCol;
m_pData = new double[nRow*nCol]; //申请新的内存空间
if(m_pData!=NULL) //判断是否申请空间成功
{
if(pData!=NULL)
{
memcpy(m_pData,pData,nRow * nCol * sizeof(double));
}
return true;
}
else
return false;
}
void cMatrix::Release()
{
if(m_pData!=NULL)
{
delete[] m_pData;
m_pData = NULL;
}
m_nRow = m_nCol =0;
}
~cMatrix();
void Release();
——重载运算符
运算重载为成员函数格式
返回类型 类名::operator运算符(形参表)
{
}
运算重载为非成员函数格式
返回类型 operator运算符(形参表)
{
}
下面为隐式内联函数
内联函数在调用时不发生控制转移,而是在编译时将函数体嵌入每一个调用出,
这样就节省了参数传递、控制转移等开销
double& operator[](int m)
{
assert(m_nCol*m_nRow > m);
return m_pData[m];
}
double& operator()(int m, int n)
{
assert(m_nCol*m_nRow > m*n+n);
return m_pData[m*n+n];
}
重载=
需要考虑到这是赋值语句,如果不申请一个新的内存空间,左值和右值将会指向同一个对象。同样在重载>>时用于输入可能原对象的行列不再匹配需要重新申请新的空间
cMatrix& cMatrix::operator=(const cMatrix& m)
{
if(&m == this)
return *this; //return m
create(m.m_nRow, m.m_nCol, m.m_pData); //新建内存空间
return *this;
}
——友元函数
此处为友元函数,仍为全局函数,但是可以访问对象数据成员。
friend istream& operator >>(istream &is, cMatrix &c); //友元函数,依然是全局函数,不是成员函数
friend ostream& operator <<(ostream &os, cMatrix &c);