一、源码实现
1.1 Main.cpp
#include<iostream>
using namespace std;
#include"CMatrix.h"
int main()
{
double pData[10] = { 2,3,4,5 };
CMatrix m1, m2(2, 5, pData);
cin >> m1;
m2.Set(1, 3, 10);
cout << m1 << m2;
CMatrix ms[4] = { CMatrix(),CMatrix(2,5,pData),CMatrix(ms[1]),CMatrix("C:\\1.txt") };
cout << ms[1] << ms[2];
if (ms[1] != ms[2])
{
cout << "Error occur!" << endl;
}
ms[1] += ms[2];
ms[1][1] = 100;
ms[1](1, 1) = 50;
cout << ms[1];
cout << "sum of m1=" << double(ms[1]);
double d = 1.2;
int i = int(d);
return 0;
}
1.2 CMatrix.cpp
#include "CMatrix.h"
#include<fstream>
#include<assert.h>
CMatrix::CMatrix()
{
m_nRow = 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;
}
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& 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 + 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;
}
1.3 CMatrix.h
#pragma once
#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;
}
运行结果: 图1.1
二、知识小结
2.1 构造函数和析构函数
2.1.1 构造函数和析构函数的由来
???类的数据成员不能在类的声明时候初始化,为了解决这个问题? 使用构造函数处理对对象的初始化。构造函数是一种特殊的成员函数,与其他函数不同,不需要用户调用它,而是创建对象的时候自动调用。析构函数是对象不再使用的时候,需要清理资源的时候调用。
2.1.2 构造函数和析构函数的基本语法
- A.构造函数
- C++中的类需要定义与类名相同的特殊成员函数时,这种与类名相同的成员函数叫做构造函数;
- 构造函数可以在定义的时候有参数;
- 构造函数没有任何返回类型;
- 构造函数的调用: 一般情况下,C++编译器会自动的调用构造函数。特殊情况下,需要手工的调用构造函数。
class Test
{
public:
Test()
{
}
}
- B.析构函数
- C++中的类可以定义一个特殊的成员函数清理对象,这个特殊的函数是析构函数;
- 析构函数没有参数和没有任何返回类型;
- 析构函数在对象销毁的时候自动调用;
- 析构函数调用机制: C++编译器自动调用。
class Test
{
~Test()
{
}
}
2.1.3 构造函数的分类和调用
class Test
{
private:
int x;
public:
Test()
{
this->x=10;
}
}
- Test a(10); 调用有参数构造函数
class Test
{
private:
int x;
public:
Test(int x)
{
this->x=x;
}
}
有参数构造函数的调用时机:
- Test a(10); 调用有参数构造函数
- Test b=(2,3); 逗号表达式的值是最后一位,调用有参数构造函数
- Test c=Test(2); 产生一个匿名对象,直接转化成c(只会调用一次有参数构造函数)
2.1.4 构造函数和析构函数的小结
a. 构造函数时C++中用于初始化对象状态的特殊函数; b. 构造函数在对象创建的时候自动调用; c. 构造函数和普通成员函数都遵循重载原则; d. 拷贝构造函数是对象正确初始化的重要保障; e. 必要的时候必须手工的写拷贝构造函数。
2.2 友元函数
2.2.1 什么是友元函数
在实现类之间数据共享时,减少系统开销,提高效率。如果类A中的函数要访问类B中的成员(例如:智能指针类的实现),那么类A中该函数要是类B的友元函数。 具体来说:为了使其他类的成员函数直接访问该类的私有变量。即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同一函数。
2.2.2 使用友元函数的优缺点
优点:能够提高效率,表达简单、清晰。
缺点:友元函数破环了封装机制,尽量不使用成员函数,除非不得已的情况下才使用友元函数。
2.2.3 语法
声明: friend + 普通函数声明
实现位置:可以在类外或类中
实现代码:与普通函数相同
调用:类似普通函数,直接调用
2.3 运算符重载
2.3.1 运算符重载的概念理解如果不做特殊处理,C++ 的 +、-、*、/ 等运算符只能用于对基本类型的常量或变量进行运算,不能用于对象之间的运算。
有时希望对象之间也能用这些运算符进行运算,以达到使程序更简洁、易懂的目的。例如,复数是可以进行四则运算的,两个复数对象相加如果能直接用+运算符完成,这样显得很直观和简洁。 利用 C++ 提供的“运算符重载”机制,赋予运算符新的功能,就能解决用+将两个复数对象相加这样的问题。 运算符重载,就是对已有的运算符赋予多重含义,使同一运算符作用于不同类型的数据时产生不同的行为。运算符重载的目的是使得 C++ 中的运算符也能够用来操作对象。 运算符重载的实质是编写以运算符作为名称的函数。不妨把这样的函数称为运算符函数。运算符函数的格式如下:
返回值类型 operator 运算符(形参表)
{
....
}
2.3.2 运算符重载为友元函数
一般情况下,将运算符重载为类的成员函数是较好的选择。但有时,重载为成员函数不能满足使用要求,重载为全局函数又不能访问类的私有成员,因此需要将运算符重载为友元。
例如,对于复数类 Complex 的对象,希望它能够和整型以及实数型数据做四则运算,假设 c 是 Complex 对象,希望c+5和5+c这两个表达式都能解释得通。
将+重载为 Complex 类的成员函数能解释c+5,但是无法解释5+c。要让5+c有意义,则应对+进行再次重载,将其重载为一个全局函数。为了使该全局函数能访问 Complex 对象的私有成员,就应该将其声明为 Complex 类的友元。具体写法如下:
class Complex
{
double real, imag;
public:
Complex(double r, double i):real(r), imag(i){};
Complex operator + (double r);
friend Complex operator + (double r, const Complex & c);
};
Complex Complex::operator + (double r)
{
return Complex(real+r, imag);
}
Complex operator + (double r, const Complex & c)
{
return Complex (c.real+r, c.imag);
}
本次实验中,通过构造函数,析构函数,运算符重载和友元函数四个方面进行了设计,通过实战,掌握了以上知识点。
|