友元、运算符重载

友元

友元是一种定义在类外部的普通函数或类,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend

类的三种访问权限从:大家均可访问(public)到仅子类可访问(protected)到类外均不可访问(private).这三种访问范围其实是有漏洞的,并没有考虑到一种情况,比如我现在让类内的数据部分公开,即部分函数/类可用,这时类的三种访问权限任何一种都无法满足需求.所以就有了友元,它提供了除类的三种访问权限之外的一种模式,我称它为自定义访问权限.

这样做是当然有弊端的.类的一个重要特征就是封装.将一些数据私有化,使得类外无法直接访问,而友元会破坏这种特征.这可能就是封装与共享的矛盾的一种妥协,一般来说不建议使用.

友元的两种形式

需要说明的是,友元的声明只要在类内即可,与其在什么访问权限下无关.

友元函数

在需要获取权限的类内以**"friend+函数声明"的方式声明友元函数**.
下面的代码展示了如何声明并使用一个友元友元函数.

#include <iostream>
using namespace std;

class Man {
public:
	Man(int m = 0):money(m){}
	int getMoney() {
		return money;
	}
	friend void changeMoney(Man& man);//友元函数的声明,既可以声明为public,也可为private、protected
private:
	int money;
};

void changeMoney(Man& man) {//该函数为Man类的友元函数,可访问并改变Man类内的所有成员
	man.money += 100;
}

int main(void) {
	Man man(100);
	cout << "拥有的钱:" << man.getMoney() << endl;

	changeMoney(man);
	cout << "改变后钱的数量为:" << man.getMoney() << endl;

	system("pause");
	return 0;
}

在这里插入图片描述

友元类

友元类与友元函数类似,在需要获取权限的类内以**"friend+(友元)类声明"的方式声明友元类**.
下面的代码展示了如何声明并使用一个友元类.

#include <iostream>
using namespace std;

class Man {
public:
	Man(int m = 0):money(m){}
	int getMoney() {
		return money;
	}
	friend class Woman;//友元类的声明,既可以声明为public,也可为private、protected
private:
	int money;
};

class Woman {//该类为Man类的友元类,该类内部的所有方法都可访问并改变Man类内的任意成员
public:
	Woman(){}
	void useAllMoney(Man& man) {
		man.money = 0;
	}
};

int main(void) {
	Man man(100);
	cout << "拥有的钱:" << man.getMoney() << endl;

	Woman woman;
	woman.useAllMoney(man);
	cout << "改变后钱的数量为:" << man.getMoney() << endl;

	system("pause");
	return 0;
}

在这里插入图片描述

运算符重载

C++提供了对基本数据类型(int float double char等)的操作,如"+"、"-"、"*"、"/",而当我们自定义一个结构体或是对象的时候,这些基本的操作却无法使用,这时候我们就要用到运算符重载.由你决定如何运算,此时狭义运算变为广义运算.
运算符重载有两种方式,一种是成员函数重载,一种是友元函数重载.

成员函数重载

下面的代码展示了如何通过成员函数重载运算符"+".

#include <iostream>
using namespace std;

class Man {
public:
	Man(int m = 0):money(m){}
	int getMoney() {
		return money;
	}
	int operator+(Man& man) {//广义"+",不仅返回被加两对象的money总和,并且改变第一个对象的money值
		this->money += man.money;
		return this->money;
	}
private:
	int money;
};

int main(void) {
	Man man1(100);
	cout << "man1拥有的钱:" << man1.getMoney() << endl;

	Man man2(400);
	//man1+man2可替换,因为实际上执行man1.operator+(man2);
	cout << "man对象在+运算后的结果为:" << man1+man2 << endl;

	cout << "man1拥有的钱:" << man1.getMoney() << endl;
	cout << "man2拥有的钱:" << man2.getMoney() << endl;

	system("pause");
	return 0;
}

在这里插入图片描述
"+"运算需要两个参数,当采用成员函数重载时,只需传入一个,因为this指针提供了一个参数,并且提供的是第一个参数,所以传进来的参数是第二个参数.这就是为什么在做man1+man2的操作时是man1的成员发生了改变.

友元函数重载

下面的代码展示了如何通过友元函数重载运算符"+".这里的友元函数就不以内联的方式展示,而是分开写,使其更像一个函数.并且多重载一个"<<".(<<也是需要两个参数的)

#include <iostream>
using namespace std;

class Man {
public:
	Man(int m = 0):money(m){}
	int getMoney() {
		return money;
	}
	friend int operator+(Man& man1, Man& man2);
private:
	int money;
	friend ostream& operator<<(ostream& os, Man& man);//os:输出流对象
};

int operator+(Man& man1, Man& man2) {
	man1.money += man2.money;
	return man1.money;
}

ostream& operator<<(ostream& os, Man& man) {//思考将输出流对象作为返回值返回的目的?
	os << "拥有的钱的数量:" << man.money << endl;
	return os;
}

int main(void) {
	Man man1(100);
	cout << "man1拥有的钱:" << man1.getMoney() << endl;

	Man man2(400);
	cout << "man对象在+运算后的结果为:" << man1+man2 << endl;//operator(man1, man2);
	//实际上执行:operator<<(operator<<(cout, man1), man2);
	cout << man1 << man2;//使用重载后的"<<"

	system("pause");
	return 0;
}

在这里插入图片描述
我在用EasyX图形库在控制台上"放视频"、VC的字符集一文中末尾提到过cout和cin的连写,为什么能连写呢?原因就在返回值上,返回了输出/输入流对象,于是返回值自动做了第一个参数,后面的参数做第二个参数,一起传入,继续调用operator<<或operator>>函数.这就是能连写的秘密.

使用建议
  1. 一般情况下,单目运算符重载,使用成员函数进行重载更方便(不用写参数)
  2. 一般情况下,双目运算符重载,使用友元函数更直观(注意一些特殊情况,如有时候a+b可能和b+a的结果不同)
总结

不能被重载的运算符

含义符号
成员访问.
域运算::
内存长度运算sizeof
三目运算?::
预处理#

可以被重载的运算符

含义符号
双目运算符+ - * / %
关系运算符== != < <= > >=
逻辑运算符&&
单目运算符+ (正号) - (负号) * (指针) & (取地址) ++ –
位运算&
赋值运算符= += -= *= /= %= &=
内存分配new delete new[ ] delete[ ]
其他( )函数调用 ->成员访问 [ ]下标 ,逗号
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值