🥥友元
2022-5-15
| 2023-8-2
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
Property

类可以允许其他类或函数访问它的非公有成员,方法是使用关键字friend将其他类或函数声明为它的友元(friend)
友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。
 

友元函数

友元函数可以访问这个类中的私有成员:
友元声明只能出现在类定义的内部,具体位置不限。友元不是类的成员,也不受它所在区域访问级别的约束。通常情况下,最好在类定义开始或结束前的位置集中声明友元。
友元声明仅仅指定了访问权限,而并非一个通常意义上的函数声明。如果希望类的用户能调用某个友元函数,就必须在友元声明之外再专门对函数进行一次声明(部分编译器没有该限制)。许多编译器并未强制限定友元函数必须在使用之前在类的外部声明。一些编译器允许在尚无友元函数的初始声明的情况下就调用它,不过即使编译器支持,最好还是提供一个独立的函数声明。
为了使友元对类的用户可见,通常会把友元的声明(类的外部)与类本身放在同一个头文件中。
 
除了顶层函数可以被定义为友元函数之外,其它类的成员函数同样可以声明为本类的友元函数:
除了普通函数,类还可以把其他类或其他类的成员函数声明为友元。此外, 友元函数能定义在类的内部, 这样的函数是隐式内联的。
 

友元类

假如Window_mgr类的某些成员可能需要访问它管理的Screen类的内部数据。例如,需要为Window_mgr添加一个名为clear的成员,负责把一个指定的Screen的内容都设为空白。为了完成这一任务,clear需要访问Screen的私有成员;而要想令这种访问合法,Screen需要把Window_mgr指定成它的友元:
 
 
 
友元类的成员函数可以访问此类包括非公有成员在内的所有成员。通过上面的声明,window_mgr被指定为Screen的友元,因此可以将Window_mgrclear成员写成如下的形式:
  • 如果clear不是screen的友元,上面的代码将无法通过编译,因为clear将不能访问screenheightwidthcontents成员
  • 而当screenwindow_mgr指定为其友元之后,Screen的所有成员对于window_mgr就都变成可见的了
注意:友元关系不存在传递性。如果window_mgr有它自己的友元,则这些友元并不能理所当然地具有访问screen的特权。每个类负责控制自己的友元类或友元函数
 
 

令成员函数作为友元

除了令整个Window_mgr作为友元之外,Screen还可以只为clear提供访问权限。当把一个成员函数声明成友元时,必须明确指出该成员函数属于哪个类:
要想令某个成员函数作为友元,必须仔细组织程序的结构以满足声明和定义的彼此依赖关系。在这个例子中,必须按照如下方式设计程序:
  • 首先定义Window_mgr类,其中声明clear函数,但是不能定义它。在clear使用screen的成员之前必须先声明Screen
  • 接下来定义Screen,包括对于clear的友元声明
  • 最后定义clear,此时它才可以使用screen的成员
 

函数重载和友元

尽管重载函数的名字相同,但它们仍然是不同的函数。因此,如果一个类想把一组重载函数声明成它的友元,它需要对这组函数中的每一个分别声明:
Screen类把接受ostream&storeOn函数声明成它的友元,但是接受BitMap&作为参数的版本仍然不能访问Screen
 
 

友元声明和作用域

类和非成员函数的声明不是必须在它们的友元声明之前。当一个名字第一次出现在一个友元声明中时,我们隐式地假定该名字在当前作用域中是可见的。然而,友元本身不一定真的声明在当前作用域中。
甚至就算在类的内部定义该函数,也必须在类的外部提供相应的声明从而使得函数可见。换句话说,即使仅仅是用声明友元的类的成员调用该友元函数,它也必须是被声明过的:
友元声明的作用是影响访问权限,它本身并非普通意义上的声明。注意,有的编译器并不强制执行上述关于友元的限定规则。
  • C++
  • 可变数据成员mutable类的作用域
    目录