《C++》基础入门_13——运算符的重载

以下内容为大学期间学习C++语言总结的知识:

《C++》基础入门_01——数据存储,表示形式,基本运算
《C++》基础入门_02——面向对象的总体概括
《C++》基础入门_03——程序的开发过程
《C++》基础入门_04——四大语句
《C++》基础入门_05——函数详解篇
《C++》基础入门_06——面向对象的详述
《C++》基础入门_07——数据的共享保护:const
《C++》基础入门_08——利用数组实现对批量数据的处理
《C++》基础入门_09——指针和引用的讲解
《C++》基础入门_10——用户自定义数据类型详细篇
《C++》基础入门_11——友元的讲解
《C++》基础入门_12——类模板
《C++》基础入门_13——运算符的重载
《C++》基础入门_14——继承与派生
《C++》基础入门_15——多态性
《C++》基础入门_16——输入输出流详讲
《C++》基础入门_17——对象串行化
《C++》基础入门_18——异常处理
《C++》基础入门_19——命名空间
《C++》基础入门_20——文件操作
《C++》基础入门_21——在函数中返回数组的常用方法



一、多态基本概念

  • 多态性是面向对象程序设计的重要特征之一。
  • 多态性是指发出同样的消息被不同类型的对象接收时有可能导致完全不同的行为。
  • 多态的实现:
    1. 函数重载
    2. 运算符重载
    3. 虚函数


二、运算符重载的实质

  • 运算符重载是对已有的运算符赋予多重含义
  • 必要性
    C++中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型(如类)
  • 实现机制
    1. 将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参。
    2. 编译系统对重载运算符的选择,遵循函数重载的
      选择原则。


三、c++中可以被重载的运算符

空间申请和释放:new  delete    new[]   delete[]
双目运算符:+  -   *  /    % 
逻辑运算符:! ||   && 
单目运算符:+(正) -()   *(指针)  &(取地址)
自增自减运算符:++  -- 
位运算符:^    |    &  ~  <<    >>  
赋值运算符:  =   +=  -=  *=  /=  %=   ^=    &=    |=  >>=  <<=  
其他·:  ->*(成员指针访问)  -> (成员访问)     ()(函数调用)     [](下标)  ,(逗号)
  • 只能重载C++语言中已有的运算符,不可臆造新的。
  • 不改变原运算符的优先级和结合性。
  • 不能改变操作数个数。
  • 经重载的运算符,其操作数中至少应该有一个是自定义类型。


四、运算符函数

  • 声明形式:
    函数类型  operator  运算符名称(形参){
         ......
    }
    
    1. operator是关键字,专门用于定义重载运算符的函数的。
    2. 运算符名称是C++现有的运算符
    3. 运算符函数的名称是operator与运算符的组成
  • 运算符被重载后,原有功能任然保留,没有丧失和改变。


五、运算符重载函数两种处理方式

5.1 作为类的成员函数

  1. 重载为类成员函数时参数个数=原操作数个数-1(后置++、–除外)
  2. 因为重载函数是类成员函数,因此有一个参数是隐含的,运算符函数是用this指针隐式访问类对象的成员
  3. 适用于参加运算的第一个参数为类对象
  4. c++规定赋值运算符=,下标运算符[],函数调用运算符(),成员运算符->必须作为成员函数重载
  5. 单目运算符和复合运算符重载为成员函数
  6. 例如下面的对+的重载,重载函数访问的是两个对象的成员
    1. this指针指向的对象中的成员
    2. 形参对象中的成员
#include <iostream>
using namespace std;
class Complex {
public:
	Complex(double a = 0.0, double b = 0.0):real(a), imag(b) {}
	Complex operator + (const Complex &c2) const;
	Complex operator - (const Complex &c2) const;
	void display() const;
private:
	double real;  //复数实部
	double imag;//复数虚部
};
//运算符+ 重载成员函数
Complex Complex ::operator+(const Complex &c2) const {
	return Complex(real + c2.real, imag + c2.imag);
}
//运算符- 重载成员函数
Complex Complex:: operator-(const Complex &c2) const {
	return Complex(real - c2.real, imag - c2.imag);//建立了一个临时对象,这个临时对象没有名字,在建立临时对象时调用构造函数
}
void Complex::display() const {
	cout << "(" << real << "," << imag << ")" << endl;
}
void main() {
	Complex c1(2, 5), c2(5, 9);
	Complex c3;
	c3 = c1 - c2; 
	c3.display();
	c3 = c1 + c2;//编译器把它解释为c3=c1.operator+(c2)
	c3.display();
}

5.2 作为普通函数(不是类的成员函数),在类中将其声明为友元函数

  1. 重载为非成员函数时 参数个数=原操作数个数,且至少应该有一个自定义类型的形参。
  2. 若函数想要访问类的私有成员,必须声明为友元函数
  3. 第一个参数可以不是类对象
  4. 流插入运算符<<和流提取运算符>>,类型转换运算符只能作为友元函数
  5. 一般双目运算重载为友元函数
	#include <iostream>
	using namespace std;
	class Complex {
	public:
		Complex() { real = 0; imag = 0; }
		Complex(double r, double i) { real = r; imag = i; }
		friend Complex operator + (Complex &c1,Complex &C2);//重载运算符+函数作为友元函数
		void display();
	private:
		double real;
		double imag;
	};
	
	Complex operator + (Complex &c1,Complex &c2) {
		return Complex(c1.real + c2.real, c1.imag + c2.imag);
	}
	void Complex::display()  {
		cout << "(" << real << "," << imag << ")" << endl;
	}
	void main() {
		Complex c1(2, 5), c2(5, 9);
		Complex c3;
		c3 = c1 + c2;//c++编译系统将程序中的表达式c1+c2解释为operator+(c1,c2)
		c3.display();
	}



六、运算符成员函数的设计

6.1 对于双目运算符 B:

  • 如果要重载 B 为类成员函数,使之能够实现表达式 oprd1 B oprd2,其中 oprd1 为A 类对象,则 B 应被重载为 A 类的成员函数,形参类型应该是 oprd2 所属的类型。
  • 经重载后,表达式 oprd1 B oprd2 相当于oprd1.operator B(oprd2)

6.2 前置单目运算符 U

  • 如果要重载 U 为类成员函数,使之能够实现表达式 U oprd,其中 oprd 为A类对象,则 U 应被重载为 A 类的成员函数,无形参。
  • 经重载后,表达式 U oprd 相当于 oprd.operatorU()

6.3 后置单目运算符 ++和–

  • 如果要重载 ++或–为类成员函数,使之能够实现表达式 oprd++ 或 oprd-- ,其中 oprd 为A类对象,则++或-- 应被重载为 A 类的成员函数,且具有一个int 类型形参(c++、为区分++,–规定的)。
  • 经重载后,表达式 oprd++ 相当于oprd.operator ++(0)
#include <iostream>
using namespace std;
class Clock {
public :
	Clock(int ho = 0, int mi = 0, int se = 0) :h(ho), m(mi), s(se) {}
	void showTime() {
		cout << "现在时间:" << h << ":" << m << ":" << s << endl;
	}
	Clock operator ++ ();   //前置单目运算符重载:++i,先自增,后运算
	Clock operator ++ (int); //后置单目运算符重载:i++,先运算,后自增
private:
	int h;
	int s;
	int m;
};
//前置单目运算符重载函数
Clock Clock::operator++() {
	s++;
	if (s >= 60) {
		m++;
		s -= 60;
		if (m >= 60) {
			m -= 60;
			h++;
			if (h >= 24) {
				h -= 24;
			}
		}
	}
	return *this;//返回当前对象值
}
//后置单目运算符重载,注意形参表中的整型参数
Clock Clock::operator ++ (int) {
	Clock old = *this;//建立临时对象或者Clock old(*this);
	++(*this); // 调用前置“ ++” 运算符
	return old;
} 
int main() {
	Clock c(23, 59, 59);
	c.showTime();          //现在时间:23:59:59
	(c++).showTime();  //现在时间:23:59:59
	(++c).showTime();  //现在时间:0:0:1
	return 0;
}



七、重载流运算符

  • “<<”“>>”流运算符是c++编译系统在类库中提供的,所以编译系统都在类库中提供输入流类istream和输出流类ostream。cin和cout分别是istream和ostream类的对象。c++编译系统对“<<”和:“>>”做了重载,使之成为流提取运算符和流插入运算符,用来输出和输入C++标准类型的数据。所以需要用到cin>>和cout<<时需要#include 把头文件包含到本程序中。

  • 用户自己定义的类型的数据不可以直接用<<和>>,若要使用,需要自己对其重载。

  • 重载函数形式:
    istream & operator >> (istream & ,自定义类 &);

    1. 第一个参数和函数类型必须是istream&类型即istream类对象的引用
    2. 第二个参数是自定义需要输入的类

    ostream & operator << (ostream &,自定义类 &);

    1. 第一个参数和函数类型必须是ostream&类型,即ostream类对象的引用
    2. 第二个参数是自定义需要输出的类
#include <iostream>
using namespace std;
class Complex {
	public:
		Complex() { real = 0; imag = 0; }
		Complex(double r,double i):real(r),imag(i) {}
		Complex operator + ( Complex &c2);
		friend ostream& operator << (ostream& o,Complex &c);
	private:
		double real;
		double imag;
};
Complex Complex ::operator+( Complex &c2) {
    return Complex(real + c2.real, imag + c2.imag);
}
ostream & operator << (ostream& o, Complex& c) {
   o << "(" << c.real << "+" << c.imag << "i)"<<endl;
   return o;
}

void main() {
	Complex c1(2, 3), c2(4, 7), c3;
	c3 = c1 + c2; // 编译系统把cout<<c3解释为operator<<(cout,c3), 调用函数时,形参o成为实参cout的引用,形参c成为c3的引用
	cout << c3;  //(6+10i)
}

上面代码return o作用:能连续向输出流插入信息,o是ostream类对象的引用,cout通过传送地址给o,使他们共享同一段存储单元,将输出流现状返回,即保留输出流的现状。

cout<<c3<<c1;
先处理cout<<c3,然后在处理cout<<c1;



八、不同类型数据间的转换

8.1 标准类型数据转换

  • 隐式类型转换
    计算机进行计算时自动进行的转换
  • 显式类型转换
    类型名(数据)

8.2 用转换构造函数进行不同类型数据的转换

  • 转换构造函数:将一个其他类型的数据转化成一个类的对象
  • 格式:类名(指定类型的数据)
  • 只能有一个形参
  • 是构造函数的重载

例如:
Complex(double r){real=r;imag=0;}
Complex c(3.5) 即 (3.5+0i)
Complex c1=c+3.5;//错误,类不可以和浮点数相加
Complex c2=c+Complex(3.5)//正确,将浮点转化成为一个Complex类进行计算

8.3 类型转换函数

  • 类型转换函数:将一个类的对象转换成另一类型的数据。

  • 格式: operator 类型名() {实现转换的语句}

  • 在函数名前不可以指定函数类型,函数无参数

  • 返回值类型由函数名指定的类型确定

    operator double(){…}返回double类型数据

  • 只能作为成员函数,因为转换的主体是本类对象

    double d1,d2;
    Complex c1,c2;

    • d1=d2+c1;//编译系统发现“+”左侧为double型,右侧是Complex型,就去找是否有对“+”的重载,若没有就去找类型转换函数,发现有类型重载函数,调用此函数,把c1转化成double型,建立一个临时的double型数据,进行运算。
    • c1=c2+d1;//编译系统发现“+”左侧为Complex型,右侧是double型,就去找是否有对“+”的重载,发现有operator+ 友元函数,但由于它是二个Complex类型参数,而本类又无对double的重载的情况下,就去找转换构造函数,发现有,调用此函数,把的d1转化成Complex型,建立一个临时的Complex型对象,在调用operator+函数进行计算
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值