友元

前面加friend关键字,可声明为友元

友元函数

类A的友元函数可以访问类A的私有成员

(通常要提前声明其他类便于使用)

友元类

类A的友元类B的所有成员函数都可以访问类A的私有成员

  • 友元类之间的关系不能传递,不能继承

运算符重载

作用

扩展运算符的作用范围,让两个对象也能进行运算操作,比如复数求和。

重载

实质上就是函数重载,对不同的对象(实参)可以实现不同的功能

形式上是把含运算符的表达式转换成对运算符函数的调用

形式

返回值类型 operator 运算符(形参表){
...
}

alt

既可以重载为成员函数,也可以重载为普通函数

c=a+b;		//等价于c=operator+(a,b);普通函数

a-b;		//等价于a.operator(b);成员函数

赋值运算符的重载

赋值运算符‘=’只能重载为成员函数

alt

问题1:

如果有s = s;这样的语句呢? alt

问题2:

为什么返回值类型要是string &呢?

对运算符进行重载时,应尽可能保留运算符原有的特性(结合律、交换律等)

alt

为了避免指向同一个地址空间,复制构造函数也要自己编写

运算符重载为友元

使用情景

重载为成员函数不能满足要求,重载为普通函数又不能访问私有成员

比如,重载为成员函数时,

c = 5 + c;	//等价于5.operator(c),编译出错

解决方法

将其重载为普通函数,这样可以使上述语句不会出错;(原有的成员函数还在)

声明其为友元函数,则可以访问类的私有成员

流插入运算符和流提取运算符的重载

即移位运算符"<<" ">>"的重载

首先,cout实际上是iostream中定义的ostream类的一个对象,移位运算符在其中被重载

对于以下语句,是怎么实现的呢?
cout<<a.name<<b;		//相当于cout.operator<<(a.name).operator<<(b)

显然,对于cout<<a.name;和cout<<b;分别实现都是很简单的,只要和之前一样对运算符进行重载即可。

但问题是,怎么让上述语句成立呢?

由前面我们知道,要调用运算符函数,运算符"<<"前面必须是一个对象,在这里则应该是cout对象,即"cout<<a.name"仍然应该返回一个cout对象

所以流插入运算符重载为函数返回值类型必须是ostream &,即返回cout本身

这样就相当于从左到右逐步执行cout语句

自增、自减运算符的重载

为了区分前置、后置表达式,C++规定,前置运算符作为一元运算符重载,后置作为二元运算符(多一个没用的参数)

++i;		//相当于operator++(i)
i++;		//相当于operator++(i, 0)

由于这两条语句功能不同,所以要返回的值也不同。

  • 前者要返回的是修改后的值,所以返回的是对象的引用(修改后)

  • 而后者要返回的是修改前的值,所以要在函数中声明一个临时的对象,且最终也要返回一个对象。在此过程中,会调用(复制)构造函数、析构函数,因此开销更大

alt

所以在程序中,应该尽量用++i的形式

程序设计与算法(三)C++面向对象程序设计 https://www.bilibili.com/video/BV1Ns411n7ui?p=11