【C++ 1】、cMarix类的实现,及运算符重载。

本文详细介绍了C++中实现cMatrix类的过程,包括数据成员、构造函数、拷贝构造函数、析构函数以及运算符重载。类中使用了友元函数以实现输入输出流的重载。同时,分析了pData设为NULL的原因,以避免在对象初始化时可能出现的问题。代码展示了如何通过重载运算符+、-、=、[]、()以及比较运算符,实现矩阵的加减、赋值、索引访问和比较功能。
摘要由CSDN通过智能技术生成

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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值