C++-实验一 CMatrix类设计

本文详细介绍了CMatrix类的构造函数(包括默认、带参数和从文件加载)、析构函数、运算符重载(算术、关系、下标和类型转换)、以及友元函数的实现。同时涵盖了CComplex类的构造和友元函数,展示了如何处理复数的输入输出。实验通过实例代码展示了这些概念的实际应用。
摘要由CSDN通过智能技术生成

实验内容

一、构造函数
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特殊情况的处理
四、友元函数
输入和输出运输符:<<, >>

实验代码

1.项目结构

 2.源码

CComplex.h

 #ifndef CCOMPLEX_H
 #define CCOMPLEX_H
 #include <iostream>
 using namespace std;
 struct SComplex
 {
    double m_dReal;
    double m_dImag;
 };
 double Modulus(const SComplex & sc);
 void Output(const SComplex & sc);
 void Input(SComplex & sc);
 class CComplex
 {   
 public:
     double m_dReal;
     double m_dImag;
     double Modulus();
     void Output();
     void Input();
 };
 istream& operator>>(istream& is, CComplex& cc);
 ostream& operator<<(ostream& os, const CComplex& cc);
 #endif

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 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;
} 
#endif

CComplex.cpp

 #include "CComplex.h"
 #include <math.h>
 #include <stdio.h>
 double Modulus(const SComplex & sc)
 {
     return sqrt(sc.m_dReal*sc.m_dReal+sc.m_dImag*sc.m_dImag);
 }
 
 void Output(const SComplex & sc)
 {
     printf("%f%f\n",sc.m_dReal,sc.m_dImag);
}

 void Input(SComplex & sc)
 {
     scanf("%lf%lf",&sc.m_dReal,&sc.m_dImag);
}
 double CComplex::Modulus()
 {
     return sqrt(m_dReal*m_dReal+m_dImag*m_dImag);
 }
 
 void CComplex::Output()
{
     printf("%f %f\n",m_dReal,m_dImag);
 }
 
 void CComplex::Input()
 {
     scanf("%lf%lf",&m_dReal,&m_dImag);
 }

 istream& operator>>(istream& is, CComplex& cc)
 {
     is>>cc.m_dReal>>cc.m_dImag;
     return is;
 }
 
ostream& operator<<(ostream& cout, const CComplex& cc)
 {
    cout<<cc.m_dReal<<" "<<cc.m_dImag<<endl;
    return cout;
 }

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

main.cpp

 #include <iostream>
 #include "CComplex.h"
 #include <stdio.h>
 #include "CMatrix.h"
 #include<string.h>
 using namespace std;
 int main(int argc, char** argv) {
     
     double pData[10]={2,3,4,5};
     CMatrix m1,m2(2,4,pData), m3("D:\\pang.txt"),m4(m2);
     cin>>m1;
     m2.Set(1,1,7);
     cout<<"\nm1:\n"<<m1<<"\nm2:\n"<<m2<<"\nm3:\n"<<m3<<"\nm4:\n"<<m4;
     
     m4=m3;
     m4[0]=m4+1;
     cout<<"\nm4+1:\n"<<m4;
     
     if(m4==m3)
     {
         cout<<"Error !"<<endl;
     }
     m4 += m3;
     cout<<"\nm4+m3:\n"<<m4;
     cout<<"sum of m4 = "<<(double)m4<<endl;
     return 0;
 }

3.运行结果

1 2
8 8

m1:
1 2
8 8

m2:
2 4
2 3 4 5
0 7 0 0

m3:
9 8
7 6 5 6 4 3 6 7
5 3 5 7 3 4 9 6
2 5 9 1 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

m4:
2 4
2 3 4 5
0 0 0 0

m4+1:
9 8
104 6 5 6 4 3 6 7
5 3 5 7 3 4 9 6
2 5 9 1 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

m4+m3:
9 8
111 12 10 12 8 6 12 14
10 6 10 14 6 8 18 12
4 10 18 2 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
sum of m4 = 303

--------------------------------
Process exited after 11.75 seconds with return value 0
请按任意键继续. . .

 实验总结

一. 构造和析构函数:
在实际应用中,通常需要给每个类定义构造函数。如果我们不提供构造和析构,编译器会提供编译器提供的构造函数和析构函数是空实现。
构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作
构造函数语法:类名(){}
a) 构造函数,没有返回值也不写void
b) 函数名称和类名相同
c) 构造函数可以有参数,因此可以发生重载
d) 程序在调用对象时候会自动调用构造,无须手动调用,并且只会调用一次
析构函数语法:~类名(){}
a) 析构函数,没有返回值也不写void
b) 函数名称与类名相同,在名称前加上符号~
c) 析构函数不可以有参数,因此不可以发生重载
d) 程序在对象销毁前会自动调用析构,无须手动调用,并且只会调用一次
构造函数的分类:
两种分类方式:
a)有参分: 有参构造和无参构造(默认构造)
b)按类型分: 普通构造和拷贝构造(const Person &p)
拷贝构造函数调用时机:
a)使用一个已经创建完毕的对象来初始化一个新对象
b)值传递的方式来给函数参数传值
c)以值的方式返回局部对象
默认情况下,C++编译器至少给一个类添加3个函数:
a)默认构造函数(无参,函数体为空)
b)默认析构函数(无参,函数体为空)
c)默认拷贝函数,对属性进行值拷贝
CMatrix(int nRow,int nCol,double pData=NULL);该构造函数为带默认参数的构造,在建立对象的时候可省去pData的实参,*pData的默认值为NULL。


二. 运算符重载:
概念:对已有德运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

本次实验中主要对:
a)算术运算符重载:+, -, +=, -=,
b)关系运算符重载:>, <, ==
c)下标操作符:[], ()
d)强制类型转换: double
e)赋值运算符:=,尤其当m1=m1的时候要特殊情况的处理:如果m1=m1,直接返回this如果不是就先Create(m.m_nRow, m.m_nCol, m.m_pData),再返回this。
CMatrix & CMatrix:: operator = (const CMatrix &m)表示一个运算符重载函数,在理解时可将operator和运算符(如operator=)视为一个函数名。
this是指向自身对象的指针,*this是自身对象。也就是说return *this返回的是当前对象的克隆或者本身(若返回类型为A, 则是克隆, 若返回类型为A&, 则是本身 )。return this返回当前对象的地址(指向当前对象的指针)。
CMatrix:: operator double()函数无需指明返回类型,double作为一个运算符,该函数用于double运算符重载。


三. 友元函数:
概念: 让一个函数或者类访问另一个类中私有成员,
特殊关键字:friend,
友元的三种实现:
• 全局函数做友元
• 类做友元
• 成员函数做友元
本次实验中用了输入输出符号的重载作为友元函数。

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、付费专栏及课程。

余额充值