前言
在实验一当中,主要内容为CMatrix类的设计与实现,包含了CMatrix.h,CMatrix.cpp以及main.cpp三大文件。
一、实验要求:
1、构造函数
?CMatrix(): 不带参数的构造函数; ?CMatrix(int nRow, int nCol, double *pData=NULL) : 带行、列及数据指针等参数的构造函数,并且参数带默认值; ?CMatrix(const char * strPath): 带文件路径参数的构造函数; ?CMatrix(const CMatrix& m): 拷贝构造函数 ?此外会用列表初始化成员变量:CMatrix(): m_nRow(0), m_nCol(0), m_pData(NULL); ?bool Create(int nRow, int nCol, double *pData=NULL): 先删除原有空间,根据传入行列创建空间,如果pData不为空要将pData的内容拷贝到m_pData中。
2、析构函数
?~CMatrix(): 调用Release(); ?Release(): 将内存释放,并将行列设置为0;
3、运算符重载
?算术运算符重载:+, -, +=, -= ?关系运算符重载:>, <, == ?下标操作符:[], () ?强制类型转换: double ?赋值运算符:=,尤其注意当m1=m1特殊情况的处理
4、友元函数
输入和输出运输符:<<, >>
5、作业提交方式
写完请发表博客,上传博客链接
二、实验过程
1.CMatrix.h文件
- 在CMatrix.h头文件当中,要先声明所需要的公有变量以及私有变量。然后根据实验要求,我们需要设计CMatrix构造函数,主要有以下几个函数:
CMatrix(); //不带参数的构造函数 CMatrix(int nRow,int nCol,double *pData=NULL); //带行、列及数据指针等参数的构造函数,并且参数带默认值 CMatrix(const CMatrix& m); //拷贝构造函数,const修饰函数参数使得传递过来的参数在函数内不可改变 CMatrix(const char * strPath);//带文件路径参数的构造函数 这几个函数,虽然它们的函数名相同,但它们具有不同的参数列表,这种方式叫做重载。同时,我们需要再设计一个create函数用于创建矩阵,即bool Create(int nRow, int nCol, double *pData=NULL);另外,再设计一个set内联函数用于矩阵赋值,内联函数可以提高效率; - 然后我们设计析构函数,用于释放内存:
~CMatrix();//析构函数,调用Release方法释放内存 void Release();//将内存释放,并将行列设置为0; - 运算符的重载,包括算数运算符以及关系运算符:
CMatrix& operator+=(const CMatrix& m); CMatrix operator+(const CMatrix& m1,const CMatrix& m2); bool operator == (const CMatrix& m); 下标操作符包括: double & operator[](int nIndex); double & operator()(int nRow,int nCol); 这里需要注意的是【】代表数组,因此只能有一个参数,而()就可以含有多个参数; 强制类型转换函数: operator double(); 赋值运算符: CMatrix& operator=(const CMatrix& m); 这里需要注意的是当m1=m1时的特殊情况,若直接调用create函数会先将原有的内存空间进行release释放处理,那么相当于赋值为空,会发生赋值错误,因此需要加个if判断语句避免错误; - 友元函数包括输入和输出函数:
friend istream & operator>>(istream& is,CMatrix & m);//全局函数 friend ostream & operator<<(ostream& os,const CMatrix &m); 若输入和输出函数不设置为友元函数的话,那么程序就会报错说调用了私有变量,友元函数的作用相当于授权给函数能够调用私有变量。
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 dValue);
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);
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 dValue)
{
m_pData[nRow*m_nCol+m_nCol]=dValue;
}
#endif
2.CMatrix.cpp文件
在CMatrix.cpp文件当中,包括的函数如下: 1.
CMatrix::CMatrix():m_nRow(0),m_nCol(0),m_pData(0)
{
}
这是不带参数的CMatrix构造函数,并初始化了成员变量,同时该函数也可以写成:
CMatrix::CMatrix():
{
m_nRow=0;
m_nCol=0;
m_pData=NULL;
}
CMatrix::CMatrix(int nRow,int nCol,double *pData):m_pData(0)
{
Create(nRow,nCol,pData);
}
该函数带了行、列及数据指针三个参数,在函数体内调用了create函数用于创建矩阵。
bool CMatrix::Create(int nRow, int nCol, double *pData)
{
Release();
m_pData = new double[nRow*nCol];
m_nRow = nRow;
m_nCol = nCol;
if (m_pData!=NULL)
{
if(pData)
{
memcpy(m_pData,pData,nRow*nCol*sizeof(double));
}
}
}
该函数为create函数,在创建内存空间时,首先要调用Release函数将之前的内存空间释放,然后再根据传入的行列创建内存空间,若pData不为空则将pData的内容拷贝到m_pData中,memcpy为内存拷贝函数。 3.
CMatrix::CMatrix(const CMatrix& m):m_pData(0)
{
*this = m;
}
该函数为拷贝构造函数,方便将类对象作为函数参数进行调用。 4.
CMatrix::CMatrix(const char * strPath)
{
m_pData = 0;
m_nRow = m_nCol = 0;
ifstream cin(strPath);
cin>>*this;
}
该函数为带文件路径参数的构造函数,ifstream是以输入方式打开指定文件 5.
CMatrix::~CMatrix()
{
Release();
}
该函数为析构函数,调用了Release函数进行内存的释放
void CMatrix::Release()
{
if(m_pData)
{
delete []m_pData;
m_pData = NULL;
}
m_nRow = m_nCol = 0;
}
该函数为Release函数,若m_pData数值不为空时,则进行delete操作,但需注意的是delete后的【】不能缺少,同时在释放内存后还要记得将行列都设置为0。 6.
CMatrix& CMatrix::operator=(const CMatrix &m)
{
if(this!=&m)
{
Create(m.m_nRow,m.m_nCol,m.m_pData);
}
return *this;
}
该函数为赋值运算符函数,需要注意的是在该函数当中要考虑到m=m的情况,由于在调用create函数时会先将原来的内存空间进行释放,若出现了m=m的情况,则会由于空间的释放而发生赋值错误,因此,我们需要先加一个if条件判断语句,防止错误。 7.
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;
}
这两个函数为算术运算符函数,其中assert函数的作用为如果它的条件返回错误,则终止程序执行,即判断两个矩阵行列大小是否一致。然后再将矩阵进行相加。 8.
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];
}
上述两个函数为下标操作符函数,其中需要注意【】代表数组,因此只能带一个参数,而()则可以带多个参数,在这两个函数中都需要先判断是否越界再返回元素值。 9.
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);
}
这两个函数为判断两个矩阵是否相等的函数。 10.
CMatrix::operator double()
{
double dS=0;
for(int i=0;i<m_nRow*m_nCol;i++)
{
dS+=m_pData[i];
}
return dS;
}
该函数为强制类型转换函数,通过该函数返回double型数据,因此无需在函数前再添加一个double。 11.
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_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;
}
这两个函数为输入输出运算符函数,在输入函数当中,要先根据输入的行列创建相应的内存空间,然后再依次输入数值;在输出函数中,在双重循环体内,为了提高算法效率,我们可以先在循环体前插入double * pData = m.m_pData;语句,将m.m_pData替代,这样有利于算法效率的提高。 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);
cin>>*this;
}
CMatrix::~CMatrix()
{
Release();
}
bool CMatrix::Create(int nRow, int nCol, double *pData)
{
Release();
m_pData = new double[nRow*nCol];
m_nRow = nRow;
m_nCol = nCol;
if (m_pData!=NULL)
{
if(pData)
{
memcpy(m_pData,pData,nRow*nCol*sizeof(double));
}
}
}
void CMatrix::Release()
{
if(m_pData)
{
delete []m_pData;
m_pData = NULL;
}
m_nRow = m_nCol = 0;
}
CMatrix& CMatrix::operator=(const CMatrix &m)
{
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);
}
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_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;
}
3. main.cpp文件
#include <iostream>
#include "CComplex.h"
#include <stdio.h>
#include "CMatrix.h"
using namespace std;
int main()
{
double pData[10]={2,3,4,5};
CMatrix m1,m2(2,5,pData),m3("d:\\1.txt"),m4(m2);
cout<<m1<<m2<<m3<<m4;
m4[1]+=m4;
if(m4==m3)
{
cout<<"Error !"<<endl;
}
m4+=m2;
cout<<"sum of m4 = \n"<<(double)m4<<endl;
return 0;
}
在该main函数中,首先对pData数组赋值,然后采取不同的构造方法创建矩阵,再输出查看生成的矩阵,然后在m4矩阵的第二个数值上再加上m4矩阵的大小,判断m4与m3是否相等,再将m2与m4相加赋值给m4,最后输出m4矩阵的大小。
4.实验结果
总结
- 构造函数:虽然函数名相同,但根据参数列表的不同,可以构造多个函数,这种方式称为重载。参数列表中出现的const修饰函数参数使得传递过来的参数在函数内不可改变。
- 内联函数可以提高效率。
- 下标运算符函数中的【】代表数组,因此只能有一个参数,而()就可以含有多个参数
- 友元函数的作用相当于授权给函数能够调用私有变量。
- 在release函数当中delete后的【】不能缺少,同时在释放内存后还要记得将行列都设置为0。
- 在赋值函数当中需要注意的是在该函数当中要考虑到m=m的情况。防止在创建内存之前先将原有的空间释放掉,防止赋值错误。
- 强制类型转换函数当中返回double型数据,因此无需在函数前再添加一个double。
- 在输出函数中,在双重循环体内,为了提高算法效率,我们可以先在循环体前插入double * pData = m.m_pData;语句,将m.m_pData替代,这样有利于算法效率的提高。
|