概要
友元函数(friend)使用,访问类中的私有变量
技术细节
目的:让一个函数或者类访问另一个类中私有成员
友元三种实现:
(1)全局函数做友元
(2)类做友元
(3)成员函数做友元
全局函数做友元:
class Room { //把全局函数声明在类中加friend修饰可以访问类中私有变量 friend void FriendFun(Room* room); public: Room() { sittingRoom = "客厅"; bedRoom = "卧室"; } string sittingRoom; private: string bedRoom; }; //全局函数 void FriendFun(Room * room) { std::cout << room->bedRoom << std::endl; } int main() { Room room; FriendFun(&room); }
类做友元:
class Room { //把友元类加friend修饰可以访问类中私有变量 friend class FriendClass; public: Room() { sittingRoom = "客厅"; bedRoom = "卧室"; } string sittingRoom; private: string bedRoom; }; //友元类 class FriendClass { public: FriendClass(); void FriendFun(); Room* room; }; FriendClass::FriendClass() { room = new Room(); } void FriendClass::FriendFun() { std::cout << room->bedRoom << std::endl; } int main() { FriendClass fc; fc.FriendFun(); }
成员函数做友元(易错!):
class Room; //友元类 class FriendClass { public: void FriendFun(Room& room); }; class Room { //把友元类加friend修饰可以访问类中私有变量 friend void FriendClass::FriendFun(Room& room); public: Room() { sittingRoom = "客厅"; bedRoom = "卧室"; } string sittingRoom; private: string bedRoom; }; void FriendClass::FriendFun(Room& room) { std::cout << room.bedRoom << std::endl; } int main() { Room room; FriendClass fc; fc.FriendFun(room); }
FriendClass类成员函数想访问Room类中的私有成员
如果一开始把Room类的定义放在最前面而不是声明,这样会报错,因为Room类中引入了友元函数FriendFun,而FriendFun函数是在FriendClass类中定义的,在定义Room类的时候FriendFun函数还没有出现,所有会报错,这就需要把FriendClass类定义在最前面。
又由于FriendClass类的FriendFun函数引入了需要传入Room类的引用,所以必须在FriendClass类前声明Room类告诉FriendFun函数传入的Room类的引用是存在的。FriendFun函数要写在Room类之后,因为函数内部用到了bedroom变量,这是Room类中的变量,所以Room类要先定义。(如果bedRoom打红杠是因为编译器没有识别出来,但不影响编译,可以编译通过,不用理会)
如果先声明FriendClass类,在定义Room类对不对呢?
这样不对,先声明FriendClass类,说明可以在Room类中传入FriendClass类引用了,但Room类中有友元函数FriendFun,目前我只知道FriendClass类声明了,有这个类,但我不知道类中会不会有FriendFun函数,所以Room类中有友元函数FriendFun是不对的,所以不能先声明FriendClass类在定义Room类。
易错写法:!!!
class Room; //友元类 class FriendClass { public: void FriendFun(); Room room; }; class Room { //把友元类加friend修饰可以访问类中私有变量 friend void FriendClass::FriendFun(); public: Room() { sittingRoom = "客厅"; bedRoom = "卧室"; } string sittingRoom; private: string bedRoom; }; void FriendClass::FriendFun() { std::cout << room.bedRoom << std::endl; } int main() { Room room; FriendClass fc; fc.FriendFun(); }
报错:严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C2079 “FriendClass::room”使用未定义的 class“Room”
这样写按道理没有错,为啥还报room使用未定义的类Room?
class Room;是一个前向声明,在类的声明之后,定义之前,此类是一个不完全类型,即已知前向声明过的类是一个类型,但不知道包含哪些成员。不完全类型只能以有限方式使用,不能定义该类型对象,不完全类型只能用于定义指向该类型的指针或者引用,或者用于声明(而不是定义)使用该类型作为形参类型或者返回类型的函数。
这样的话怎么修改?
把Room room改为指针类型Room *room; 同时要在FriendClass 类中写一个无参构造,里面给room分配动态内存,room=new Room; 不然room是野指针。
第二种修改就是声明带该类型作为形参的函数void FriendFun(Room &room);或void FriendFun(Room room);