C++实验(一)—— CMatrix类设计与实现

目录

一、代码理解

        CMatrix.h

        CMatrix.cpp

        Main.cpp

        运行结果

二、总结


一、代码理解

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

CMatrix operator+(const CMatrix& m1, const CMatrix& m2);
CMatrix operator-(const CMatrix& m1, const CMatrix& m2);

inline void CMatrix::Set(int nRow, int nCol, double dVal) 
{
	m_pData[nRow * m_nCol + nCol + nCol] = dVal;
}

#endif // !CMATRIX_H

  • 友元函数:友元函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数。友元函数可以访问当前类中的所有成员,包括 public、protected、private 属性的  

        详细可以看这篇文章:(30条消息) C++ friend 用法总结_eskimoer的专栏-CSDN博客_c++ friendicon-default.png?t=L892https://blog.csdn.net/ddupd/article/details/38053159

  • #ifndef/#define/#endif  :防止头文件被重复引用,Eg:存在a.h文件#include "c.h"而此时b.cpp文件导入了#include "a.h" 和#include "c.h"此时就会造成c.h重复引用。
  • C++重载运算符  :重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。Box operator+(const Box&);

C++ 重载运算符和重载函数 | 菜鸟教程 (runoob.com)icon-default.png?t=L892https://www.runoob.com/cplusplus/cpp-overloading.html

 

  • inline内联函数:在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。

    栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。

        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);//通过ifstream定义输入流对象
	cin >> *this;
}
//析构函数
CMatrix::~CMatrix() {
	//Release()基本就是用来释放资源的
	Release();
}

bool CMatrix::Create(int nRow, int nCol, double* pData)
{
	//将数据赋值为空
	Release();
	m_pData = new double[nRow * nCol];
	m_nCol = nCol;
	m_nRow = nRow;
	if (pData != NULL)
	{
		//void* memcpy(void* str1, const void* str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1。
		//https://www.runoob.com/cprogramming/c-function-memcpy.html
		memcpy(m_pData, pData, nRow * nCol * sizeof(double));
	}
	return true;
}
void CMatrix::Release()
{
	if (m_pData!=NULL)
	{
		delete[]m_pData;
		m_pData = NULL;
	}

	m_nRow = m_nCol = 0;
}

//运算符重载

//C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。
//重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
//https://www.runoob.com/cplusplus/cpp-overloading.html


//一、关系运算符重载
//1.赋值运算符重载
CMatrix& CMatrix::operator=(const CMatrix& m)
{
	if (this != &m) {
		Create(m.m_nRow, m.m_nCol, m.m_pData);
	}
	return *this;
}
//2.恒等号运算符重载
bool CMatrix::operator == (const CMatrix& m)
{
	if (!m_nRow == m.m_nRow && m_nCol == m.m_nRow) {

		return false;
	}
	//比较元素是否相等
	for (int i = 0; i < m_nCol * m_nRow; i++) {
		if (m_pData[i] != m.m_pData[i])
			return false;
	}

	return true;
}
bool CMatrix::operator != (const CMatrix& m)
{
	return !((*this) == m);
}

//二、算术运算符重载
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;
}
CMatrix operator-(const CMatrix& m1, const CMatrix& m2)
{
	CMatrix m3(m1);
	m3 -= m2;
	return m3;
}
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;
}
//三、操作符重载
double& CMatrix::operator[](int nIndex)
{
	assert(nIndex < m_nCol* m_nRow);
	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];
}

//强制类型转换
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_nCol >> m.m_nRow;
	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;

}

//C++中的ostream这个类型,通常作为某个类的友元函数出现,用于<<操作重载中

// 重载操作符”<<“
// 使得“<<”操作符能够打印 CMatrix 数据类型
ostream& operator<<(ostream& os, const CMatrix& m)
{
	os << "size:[" << 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 <stdio.h>
#include "cmatrix.h"
#include<fstream>
using namespace std;


int main(int argc, char** argv) {
    double pData[10] = { 2,3,4,5 };

    ifstream file;
    file.open("1.txt");
    if (!file.is_open())
    {
        std::cerr << "cannot open the file" << endl;
    }
    else
        std:cout << "文件读取成功" << endl;
    CMatrix m1, m2(2, 5, pData), m3("1.txt"), m4(m2);
    cout << "输入数据" << endl;
    cin >> m1;

    cout <<"输出"<< m1 << m2 << m3 << m4;

    m2.Set(0, 2, 10);
    cout << "修改后的m2" << m2 << endl;
    if (m4 == m3)
    {
        cout << "Error !" << endl;
    }
    m3 += m1;
    cout << "m3 += m1:\n" << m3;
    return 0;
}

        运行结果

 

二、总结

构造函数&析构函数

  • 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
  • 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

构造函数语法:类名(){}

  1. 构造函数,没有返回值也不写void
  2. 函数名称与类名相同
  3. 构造函数可以有参数,因此可以发生重载
  4. 程序在调用对象时候会自动调用构造函数,无须手动调用,而且只会调用一次

析构函数语法: ~类名(){}

  1. 析构函数,没有返回值也不写void
  2. 函数名称与类名相同,在名称前加上符号~
  3. 析构函数不可以有参数,因此不可以发生重载
  4. 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次

构造函数的分类

两种分类方式:

​ 按参数分为: 有参构造和无参构造

​ 按类型分为: 普通构造和拷贝构造

通过本次实验了解了构造函数,析构函数,运算符重载和友元函数的部分知识,并通过代码实践

推荐阅读:

(30条消息) C++核心编程(二)_Augenstern_QXL的博客-CSDN博客_c++icon-default.png?t=L892https://blog.csdn.net/Augenstern_QXL/article/details/117253730?spm=1001.2014.3001.5501

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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、付费专栏及课程。

余额充值