- 一、源码实现
- 1.1 Main.cpp
- 1.2 CMatrix.cpp
- 1.3 CMatrix.h
- 二、知识小结
- 2.1 构造函数和析构函数
- 2.1.1 构造函数和析构函数的由来
- 2.1.2 构造函数和析构函数的基本语法
- 2.1.3 构造函数的分类和调用
- 2.1.4 构造函数和析构函数的小结
- 2.2 友元函数
- 2.2.1 什么是友元函数
- 2.2.2 使用友元函数的优缺点
- 2.2.3 语法
- 2.3 运算符重载
- 2.3.1 运算符重载的概念理解如果不做特殊处理,C++ 的 +、-、*、/ 等运算符只能用于对基本类型的常量或变量进行运算,不能用于对象之间的运算。
- 2.3.2 运算符重载为友元函数
#include1.2 CMatrix.cppusing 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; }
#include "CMatrix.h" #include1.3 CMatrix.h#include 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; }
#pragma once #includeusing 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 构造函数和析构函数的基本语法- A.构造函数
- C++中的类需要定义与类名相同的特殊成员函数时,这种与类名相同的成员函数叫做构造函数;
- 构造函数可以在定义的时候有参数;
- 构造函数没有任何返回类型;
- 构造函数的调用: 一般情况下,C++编译器会自动的调用构造函数。特殊情况下,需要手工的调用构造函数。
class Test
{
public:
//构造函数
Test()
{
}
}
- B.析构函数
- C++中的类可以定义一个特殊的成员函数清理对象,这个特殊的函数是析构函数;
- 析构函数没有参数和没有任何返回类型;
- 析构函数在对象销毁的时候自动调用;
- 析构函数调用机制: C++编译器自动调用。
class Test
{
~Test()
{
}
}
2.1.3 构造函数的分类和调用
- A.无参构造函数
class Test
{
private:
int x;
public:
Test()
{
this->x=10;
}
}
- Test a(10); 调用有参数构造函数
- B.有参构造函数
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. 必要的时候必须手工的写拷贝构造函数。
在实现类之间数据共享时,减少系统开销,提高效率。如果类A中的函数要访问类B中的成员(例如:智能指针类的实现),那么类A中该函数要是类B的友元函数。
具体来说:为了使其他类的成员函数直接访问该类的私有变量。即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同一函数。
优点:能够提高效率,表达简单、清晰。
缺点:友元函数破环了封装机制,尽量不使用成员函数,除非不得已的情况下才使用友元函数。
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)
{ //能解释c+5
return Complex(real+r, imag);
}
Complex operator + (double r, const Complex & c)
{ //能解释5+c
return Complex (c.real+r, c.imag);
}
本次实验中,通过构造函数,析构函数,运算符重载和友元函数四个方面进行了设计,通过实战,掌握了以上知识点。



