CMatrix类设计与实现

实验内容

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中。
二、析构函数
~CMatrix(): 调用Release();
Release(): 将内存释放,并将行列设置为0;
三、运算符重载
算术运算符重载:+, -, +=, -=
关系运算符重载:>, <, ==
下标操作符:[], ()
强制类型转换: double
赋值运算符:=,尤其注意当m1=m1特殊情况的处理
四、友元函数
输入和输出运输符:<<, >>

代码实现

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 (pData)
    {
        memcpy(m_pData, pData, nRow * nCol * sizeof(double));
    }
    return true;
}
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;
}

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 dVale);
    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 dVal)
{
    m_pData[nRow * m_nCol + nCol] = dVal;
}

Main.cpp

#include <iostream>
#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);
    cin >> m1;
    m2.Set(1, 3, 10);
    cout << m1 << m2 << m3 << m4;
    m4 = m3;
    m4[2] = m4 + 1;
    cout << m4;
    if (m4 == m3)
    {
        cout << "Error !" << endl;
    }
    m4 += m3;
    cout << "sum of m4 = " << (double)m4 << endl;
    return 0;
}

1.txt的内容

在这里插入图片描述

代码结果

在这里插入图片描述

代码分析

构造函数

CMatrix();
//不带参数的构造函数
CMatrix(int nRow, int nCol, double* pData = NULL);
//带行、列及数据指针等参数的构造函数,并且参数带默认值
CMatrix(const CMatrix& m);
//带文件路径参数的构造函数
CMatrix(const char* strPath);
//拷贝构造函数
bool Create(int nRow, int nCol, double* pData = NULL);
//先删除原有空间,根据传入行列创建空间,如果pData不为空要将pData的内容拷贝
  1. 类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
  2. 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。

析构函数

~CMatrix();
//调用Release()
void Release();
//将内存释放,并将行列设置为0
  1. 类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
  2. 析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。

运算符重载

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();

运算符重载的实质就是函数重载或函数多态。运算符重载是一种形式的C++多态。目的在于让人能够用同名的函数来完成不同的基本操作。要重载运算符,需要使用被称为运算符函数的特殊函数形式

分类:

  1. 算术运算符重载:+, -, +=, -=
  2. 关系运算符重载:>, <, ==
  3. 下标操作符:[], ()
  4. 强制类型转换: double
  5. 赋值运算符:=
CMatrix & CMatrix:: operator += (const CMatrix &m)
//表示一个运算符重载函数
operator double()
//无需指明返回类型,double作为一个运算符,该函数用于double运算符重载

友元函数

    friend istream& operator>>(istream& is, CMatrix& m);
    friend ostream& operator<<(ostream& os, const CMatrix& m);
  1. 类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。
  2. 友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend。
  3. 输入和输出运输符:<<, >>
Introduction ============ This is a class for symmetric matrix related computations. It can be used for symmetric matrix diagonalization and inversion. If given the covariance matrix, users can utilize the class for principal component analysis(PCA) and fisher discriminant analysis(FDA). It can also be used for some elementary matrix and vector computations. Usage ===== It's a C++ program for symmetric matrix diagonalization, inversion and principal component anlaysis(PCA). To use it, you need to define an instance of CMatrix class, initialize matrix, call the public funtions, and finally, free the matrix. For example, for PCA, CMarix theMat; // define CMatrix instance float** C; // define n*n matrix C = theMat.allocMat( n ); Calculate the matrix (e.g., covariance matrix from data); float *phi, *lambda; // eigenvectors and eigenvalues int vecNum; // number of eigenvectors (<=n) phi = new float [n*vecNum]; lambda = new float [vecNum]; theMat.PCA( C, n, phi, lambda, vecNum ); delete phi; delete lambda; theMat.freeMat( C, n ); The matrix diagonalization function can also be applied to the computation of singular value decomposition (SVD), Fisher linear discriminant analysis (FLDA) and kernel PCA (KPCA) if forming the symmetric matrix appropriately. For data of very high dimensionality (n), the computation of nxn matrix is very expensive on personal computer. But if the number m of samples (vectors) is smaller than dimenionality, the problem can be converted to the computation of mxm matrix. The users are recommended to read the paper KPCA for how to form mxm matrix: B. Sch枚lkopf, A. Smola, K.-R. M眉ller. Nonlinear component analysis as a kernel eigenvalue problem, Neural Computation, 10(5): 1299-1319, 1998. Example ======= Refer to `example' directory for a simple demonstration.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值