c++ (7)- 友元函数-友元类-运算符重载(基础+提高)
1.友元函数
- 友元函数是一个全局函数
- 友元函数可以修改类的私有属性,破坏了类的封装性;
- 友元函数的参数中必然至少会有一个友元类的指针或者引用,用来操作该类的属性;
友元类的关键字friend 的声明位置没有固定的限制,可以声明在友元类的private或者public下;



1 #include <iostream> 2 using namespace std; 3 4 class A { 5 6 public : 7 friend void setData(A *pA, int i); 8 A(int a) { 9 this->a = a; 10 } 11 12 void printA() { 13 cout << "a:" << a << endl; 14 } 15 private: 16 int a; 17 18 }; 19 20 void setData(A *pA,int i) { 21 pA->a = i; 22 } 23 24 25 int main() 26 { 27 //通过友元函数修改类的私有属性 28 A aObject(1); 29 aObject.printA(); 30 31 setData(&aObject,100); 32 aObject.printA(); 33 34 system("pause"); 35 36 37 }
2.友元类-不重要
2.1 实例
- 若 B 类是 A 类的友员类,则 B 类的所有成员函数都是 A 类的友员函数
- 友元类是具有特殊的固定的使用场景的:友员类通常设计为一种对数据操作或类之间传递消息的辅助类
- 下面的实例中的类的关系:
- 【1】A是B的辅助类,其中B类是A类的友元类;
- 【2】在B类中包含了A类,A是B的子属性;B类可以通过A类的私有类A成员属性,访问A类的私有属性;
- 友元类的不常用,友元函数比较常用




2.2 使用友元类的原因

3.运算符重载
3.1 运算符重载的引入
【实例】复数的加法运算;

3.2 运算符重载的语法


3.3 例子1




3.4 运算符重载的本质:函数的调用;
运算符重载的本质:函数的调用;
3.5 运算符重载的语法



4.二元运算符重载
4.1 语法基础内容
一元运算符重载要比二元运算符重载麻烦


4.2 两种方法的函数原型的书写


4.3 友元函数重载
【说明】一般的类的属性都是私有的,否则外部的全局函数无法修改类的私有属性;
因此需要使用“友元函数”的重载。来打破类的属性的私有性。
【特别注意】友元函数的声明和友元函数的全局声明必须一致,否则会发生乱七八糟的错误;

4.4 成员函数重载

5.一元运算符重载
5.1 友元全局函数重载前置++



5.2成员函数重载前置--


5.3 友元全局函数重载后置++
【说明】后置++是先返回再++,所以要先把值先返回引用或者指针,再累加;
5.3.1 问题:前置++和后置++的函数名字相同会遇到的问题
【说明】此处不属于重载,因为函数的返回值不能作为重载的判断依据;

【语法】因此为了区分,将后置++的函数定义时候需要使用“int”占位符。

【技巧】因为首先返回值,不能直接“return c1”,否则程序直接结束了;
先将c1作为临时变量保存下来,在最后返回tmp,不让程序结束;
在返回之前对c1的数据进行处理。

因为使用到了类的私有属性,所以要声明为该类的友元函数;


5.4 成员函数重载后置--
【技巧】跟之前一样使用到了保存临时变量的技巧


5.5 重载的说明
一般的重载都是使用成员函数进行重载;
5.6 重载左移操作符--必须使用友元




【特别说明】“左移”“右移”操作符只能使用“友元全局函数”重载实现,因为我们开发人员无法拿到ostream的源码;


5.7 左操作符函数的返回值(继续上面的5.6 demo)
【说明】因为5.6重载的左操作符的函数的返回值为void;
下面的demo中的140行的代码等价为142行的代码;
即,最后的结果是143行的代码;
最后返回值void无法继续调用函数导致出错;

【修改之后】修改之后就可以支持链式编程;
修改后的返回值改为引用;


6.使用友元操作符重载的注意点

7.重载的提高
7.1 重载等号=操作符(对象的拷贝)
【说明】如果类中存在“指针”“引用”等成员变量时,可能会出现“深拷贝”“浅拷贝”;



7.2 修改为支持链式操作

7.3 重载等号操作符的结论

浙公网安备 33010602011771号