C++基础知识-DAY6
1. 友元
采用类的机制后实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一般定义为公有的,,依此提供类与外界间的通信接口。
但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,有时可以将这些函数定义为该类的友元函数,除了友元函数外,还有友元类,两者统称为友元。
友元的作用是提高了程序的运行效率(即减少了类型和安全性检查及调用的时间开销),但他破坏了类的封装性和隐 藏性,使得非成员函数可以访问类的私有成员。
友元可以是一个函数,该函数被称为友元函数,友元也可以是一个类,该类被称为友元类。
1. Get/set
Get方法和set方法,是常见的获取数据成员的方式,比如在游戏中,任务遭到攻击后血量的减少就要用到set方法,而实时的显示就需要set方法
由于_lifeBlood是私有的,为了访问他,我们必须要做的事情就是通过函数来访问他,这就意味着,在这个过程中需要不断的压栈与出栈,那么就面临一个问题,怎么样才能提高战斗的效率呢
如果fight()内部的函数可以写成如下
这样就可以省去很多压栈出栈的开销,节约成本,但是由于_lifeBlood是私有的,不可以这样访问,除此之外,由于真正在游戏中,参与fight的对象是不定的,可以是多个,所以说fight常被写成全局函数,这样就更不能直接访问私有变量了,为了解决这些问题,引入友元friend的概念,在类内声明friend void fight(Sprite &sp);
友元主要是用来提升效率
其中get方法和set方法是标准封装的结果,friend破坏了这种封装,但又带来了效率的提高
(1) 采用类的机制后实现了对数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一般定义为共有的,以此提供类与外界间的通信接口,但是,有时需要定义一些函数,这些函数不是类的一部分,但又频繁的访问类的数据成员,这时可以将这些函数定义为该类的友元函数,除了友元函数外,还有友元函数类,两者统称为友元
友元的作用是提高了程序的运行效率(即减少了类型和安全检查及调用的时间开销),但他破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员
友元可以是一个函数,该函数称为友元函数,友元也可以是一个类,该类称为友元类
(2) 关系
a. 同类间无私处
b. 异类间有友元
c. 友元不是成员
友元函数终究不是成员函数,成员中有隐参this指针,可以直接访问成员,而 友元没有,必须得通过对象来访问
友元仅是打破了外部访问中的private权限,声明为谁的友元,就可以通过谁的对象,访问谁的私有成员,一定要注意,是通过对象访问的
(3) 友元函数(全局做友元函数)
(4) 类成员做友元,涉及到一个前向声明的问题
C++是先声明,后使用,由以上,在用友元函数的时候,其是没有对magagePoint有任何的声明,因此我们需要加一个前向声明。前向声明是一种不完全类型的声明,其是不能定义对象的,但是可以定义指针和引用,做参数和返回值,仅用作函数的声明
你中有我,我中有你的情况是最难确定顺序的,如上,getDistance必须要看到了其定义才能用,而对于ManagePoint中的Point只需要class Point前向声明即可
(5) 前向声明,是一种不完全声明,其特点为
a. 不能定义对象
如最开始的前向声明class Point 中,如class Point a,b,c等声明对象的行为是不可以的
b. 可以用于定义指向这个类型的指针或引用
前两种都是可以的,可以定义指向这个类的指针或引用
c.
(6) 友元类
当希望一个类中所有成员函数,均可存取另一个类的私有成员时,可以将该类声明为另一个类的友元
class A
{
friend class B;
public:
private:
}
在实际工作中,程序员喜欢友元类
(7)
2. 友元结论
声明位置
友元声明以关键字friend开始,他只能出现在类定义中,因为友元不是类授权的成员,所以他不受其所在类的声明区域public,private和protected的影响,因此我们选择把所有友元声明组织在一起并放在类头之后
友元
友元利弊
友元不是类函数,但是他可以通过对象访问类中的私有成员,友元的作用在于提高程序的运行效率,但是,他破坏了类的封装性和隐蔽性,使得非成员函数可以访问类的私有成员
注意
友元关系不能被继承
友元关系是单向的,不具有交换性,若类B是类A 的友元,若类A不一定是类B的友元
若类B是类A 的友元,类C是类B 的友元,则类C不一定是类A的友元
3. 运算符重载
运算符重载的本质是函数重载,函数名即operator x
但凡涉及到自定义类型,想要跟普通数据类型一样的操作体验,就需要重载
友元重载,即全局函数重载
对于运算符重载,我们首先举两个例子,第一个是+
对于加号上面的const是否要加的问题, 对于int a; int b; int c; (a=b)=c是可以的,而(a+b)=c则是不可以的,但是对于对象a,y来说,这种赋值是可以的,相当于将对象x,y加起来赋给一个匿名空间,这样是不好的,因此我们加了一个const使其直接无法编译过去
这个就是const做返值修饰符的概念,
C++引入引用的概念后,表达式可以被赋值的现象出现了,有的表达式可以被赋值,有些表达式则不可以被赋值,比如对于int a; int b; int c; (a=b)=c是可以的,而(a+b)=c则是不可以的,重新的运算符是否会导致表达式可以被赋值应该以基础类型为准,返回类型通常通过加const加以限定来实现
第二个例子是=
4. 重载范例
(1) 双目举例
对于+=的情况,我们可以先写成如下
但是这样会报错,原因是ca+=(cb+=cc)中,cb+=cc会产生一个临时变量,临时变量只能赋给const,
(2) 单目列举(a++,++a)
首先和int 类型的-n做类比
这样可以编译过去,但是如果加上其他的功能,比如说-n=10这种在int类型中是编译不过去的,类比-n=10,我们有如下的代码
在编译过程中,我们发现-cc=Complex(-10,0);是可以编译过去的,这个不是我们要的,因此我们可以引入const做返值修饰符,专门解决这个问题
再次对功能进行扩充
但是-(-c)是编译不过去的,相当于返值再次调用了operator-函数,相当于(c.operator-()). operator-();这里出现的问题是c.operator-()返回了一个const对象,const对象再调用一个非const函数,所以说会报错,因此将函数写成const
(3) 在整个程序中我们使用到几次匿名对象,匿名对象是可以被赋值的,可以发起成员函数的调用,