IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++程序设计:实验一 CMatrix类设计与实现 -> 正文阅读

[C++知识库]C++程序设计:实验一 CMatrix类设计与实现

前言

在实验一当中,主要内容为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文件

  1. 在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内联函数用于矩阵赋值,内联函数可以提高效率;
  2. 然后我们设计析构函数,用于释放内存:
    ~CMatrix();//析构函数,调用Release方法释放内存
    void Release();//将内存释放,并将行列设置为0;
  3. 运算符的重载,包括算数运算符以及关系运算符:
    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判断语句避免错误;
  4. 友元函数包括输入和输出函数:
    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);//先删除原有空间,根据传入行列创建空间,如果pData不为空要将pData的内容拷贝到m_pData中
    void set(int nRow,int nCol,double dValue);
//    inline void CMatrix::set(int nRow,int nCol,double dVale) //隐含的内联函数
//    {
//        m_pData[nRow*m_nCol+m_nCol]=dVale;
//    }
    void Release();//将内存释放,并将行列设置为0;
    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 // CMATRIX_H

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) //先删除原有空间,根据传入行列创建空间,如果pData不为空要将pData的内容拷贝到m_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)); //memcpy为内存拷贝函数
        }
    }
}

该函数为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); //ifstream默认以输入方式打开文件
    cin>>*this;
}

该函数为带文件路径参数的构造函数,ifstream是以输入方式打开指定文件
5.

CMatrix::~CMatrix() //析构函数
{
    Release();
}

该函数为析构函数,调用了Release函数进行内存的释放

void CMatrix::Release()//将内存释放,并将行列设置为0;
{
    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(): //不带参数的构造函数,初始化成员变量
//{
//    m_nRow=0;
//    m_nCol=0;
//    m_pData=NULL;
//}
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); //ifstream默认以输入方式打开文件
    cin>>*this;
}
CMatrix::~CMatrix() //析构函数
{
    Release();
}
bool CMatrix::Create(int nRow, int nCol, double *pData) //先删除原有空间,根据传入行列创建空间,如果pData不为空要将pData的内容拷贝到m_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)); //memcpy为内存拷贝函数
        }
    }
}
void CMatrix::Release()//将内存释放,并将行列设置为0;
{
    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(/*int argc,char ** argv*/)
{
    double pData[10]={2,3,4,5};
    CMatrix m1,m2(2,5,pData),m3("d:\\1.txt"),m4(m2);
//    cin>>m1;
//    m2.set(1,3,10);
    cout<<m1<<m2<<m3<<m4;
//    m4=m3;
    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.实验结果

在这里插入图片描述

总结

  1. 构造函数:虽然函数名相同,但根据参数列表的不同,可以构造多个函数,这种方式称为重载。参数列表中出现的const修饰函数参数使得传递过来的参数在函数内不可改变。
  2. 内联函数可以提高效率。
  3. 下标运算符函数中的【】代表数组,因此只能有一个参数,而()就可以含有多个参数
  4. 友元函数的作用相当于授权给函数能够调用私有变量。
  5. 在release函数当中delete后的【】不能缺少,同时在释放内存后还要记得将行列都设置为0。
  6. 在赋值函数当中需要注意的是在该函数当中要考虑到m=m的情况。防止在创建内存之前先将原有的空间释放掉,防止赋值错误。
  7. 强制类型转换函数当中返回double型数据,因此无需在函数前再添加一个double。
  8. 在输出函数中,在双重循环体内,为了提高算法效率,我们可以先在循环体前插入double * pData = m.m_pData;语句,将m.m_pData替代,这样有利于算法效率的提高。
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-09 16:05:38  更:2021-10-09 16:06:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 19:24:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计