C++ Primer 学习笔记 — 友元
2013-11-05 20:54
274 查看
友元机制允许一个类将对其非公有成员的访问权授予指定的函数或者类。友元的声明以关键字friend开始,只能出现在类定义的内部,友元的声明可以出现在类内部的任何地方。通常,将友元成组地放在类的开始或者结尾是个好主意。
1.友元关系:一个例子
友元可以是普通的非成员函数,或者前面定义的其他类的成员函数,或者整个类。将一个类设为友元,则友元类的的所有成员函数都可以访问授予友元关系的那个类的非公有成员。
2.使其他类的成员函数成为友元
错误示例1:
注解:编译到Screen时,由于Screen类使用到Window_Mgr的成员函数,虽然前面给出了Window_Mgr的声明,但此时还清楚Window_Mgr的完整定义,所以编译出错。
错误示例2:
注解:编译到relocate时,由于Screen& s的实现使用到Screen的成员变量,虽然前面给出了Screen的声明,但此时还清楚Screen的完整定义,所以编译出错。
正确示例3:
注解:将Window_Mgr::relocate的实现移动到最后,由于编译类Window_Mgr时,并不需要Screen&s 的实现细节,问题得到解决。
结论:Window_Mgr必须先定义,否则,Screen类就不能将Window_Mgr中的成员函数指定为友元,并且,只有在定义类Screen后,才能定义relocate函数——将其设为友元就是为了访问Screen的成员,否则,当其访问Screen类中成员时,将会编译出错,如实例2。
若将某个类中的成员函数设为另外一个类的友元,则有严格的顺序:必须先定义包含成员函数的类,再将成员函数设为另外一个类的友元,最后是该成员函数的实现。
3.重载函数与友元关系
类必须将重载函数集中每一个希望设为友元的函数都声明为友元
类Screen将接受一个ostream&的storeOn版本设为自己的友元,接受一个BitMap&的版本对Screen没有特殊访问权。
4.总结
① 友元可以访问类的私有成员,友元只能出现在类定义内部,友元声明可以在类中的任何地方,通常,将友元成组地放在类的开始或者结尾。
② 友元可以是普通的非成员函数,或前面定义的其他类的成员函数,或整个类。
③ 类必须将重载函数集中每一个希望设为友元的函数都声明为友元。
④ 友元关系是单向的。若类B是类A的友元,类A不一定是类B的友元。
⑤ 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元。
⑥ 友元关系不能继承,基类的友元对派生类的成员没有特殊的访问权限。如果基类被授予友元关系,则只有基类具有特殊的访问权限。该基类的派生类不能访问授予友元关系的类。
1.友元关系:一个例子
class Screen{ //声明一个友元类,该类必须提前定义 friend class Window_Mgr; }; //Window_Mgr的成员可以直接引用Screen的私有成员 Window_Mgr& Window_Mgr::relocate(Screen::index r, Screen::index c, Screen &s ) { //引用height和width s.height +=r; s.width +=c; return *this; }
友元可以是普通的非成员函数,或者前面定义的其他类的成员函数,或者整个类。将一个类设为友元,则友元类的的所有成员函数都可以访问授予友元关系的那个类的非公有成员。
2.使其他类的成员函数成为友元
错误示例1:
class Window_Mgr; class Screen { public: friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s); private: int height; int width; } class Window_Mgr { public: typedef std::string::size_type index; Window_Mgr& Window_Mgr::relocate(index r, index c, Screen& s) { s.height += r; s.width += c; return *this; } }
注解:编译到Screen时,由于Screen类使用到Window_Mgr的成员函数,虽然前面给出了Window_Mgr的声明,但此时还清楚Window_Mgr的完整定义,所以编译出错。
错误示例2:
class Screen; class Window_Mgr { public: typedef std::string::size_type index; Window_Mgr& Window_Mgr::relocate(index r, index c, Screen& s) { s.height += r; s.width += c; return *this; } } class Screen { public: friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s); private: int height; int width; }
注解:编译到relocate时,由于Screen& s的实现使用到Screen的成员变量,虽然前面给出了Screen的声明,但此时还清楚Screen的完整定义,所以编译出错。
正确示例3:
class Screen; class Window_Mgr { public: typedef std::string::size_type index; Window_Mgr& Window_Mgr::relocate(index r, index c, Screen& s); } class Screen { public: friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s); private: int height; int width; } Window_Mgr& Window_Mgr::relocate(Window_Mgr::index r, Window_Mgr::index c, Screen& s) { s.height += r; s.width += c; return *this; }
注解:将Window_Mgr::relocate的实现移动到最后,由于编译类Window_Mgr时,并不需要Screen&s 的实现细节,问题得到解决。
结论:Window_Mgr必须先定义,否则,Screen类就不能将Window_Mgr中的成员函数指定为友元,并且,只有在定义类Screen后,才能定义relocate函数——将其设为友元就是为了访问Screen的成员,否则,当其访问Screen类中成员时,将会编译出错,如实例2。
若将某个类中的成员函数设为另外一个类的友元,则有严格的顺序:必须先定义包含成员函数的类,再将成员函数设为另外一个类的友元,最后是该成员函数的实现。
3.重载函数与友元关系
类必须将重载函数集中每一个希望设为友元的函数都声明为友元
//函数重载 extern std::ostream& storeOn(std::ostream&, Screen&) extern BitMap& storeOn(BitMap&, Screen&) class Screen{ //接受一个ostream&的storeOn版本可以访问Screen类的私有成员 friend std::ostream& storeOn(std::ostream&, Screen&); // ... }
类Screen将接受一个ostream&的storeOn版本设为自己的友元,接受一个BitMap&的版本对Screen没有特殊访问权。
4.总结
① 友元可以访问类的私有成员,友元只能出现在类定义内部,友元声明可以在类中的任何地方,通常,将友元成组地放在类的开始或者结尾。
② 友元可以是普通的非成员函数,或前面定义的其他类的成员函数,或整个类。
③ 类必须将重载函数集中每一个希望设为友元的函数都声明为友元。
④ 友元关系是单向的。若类B是类A的友元,类A不一定是类B的友元。
⑤ 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元。
⑥ 友元关系不能继承,基类的友元对派生类的成员没有特殊的访问权限。如果基类被授予友元关系,则只有基类具有特殊的访问权限。该基类的派生类不能访问授予友元关系的类。
相关文章推荐
- c++ primer 学习笔记23 友元 static类成员
- C++ Primer 学习笔记_53_类和数据抽象 --友元、static员
- C++ Primer 学习笔记_53_类与数据抽象 --友元、static成员
- c++ primer 学习笔记:类之友元
- [C++ 学习] C++ Primer 笔记 bitset 和 位操作
- C++ Primer 中文版 学习笔记(十二)
- C++ Primer 学习笔记_102_特殊工具与技术 --运行时类型识别[续]
- C++ Primer(第4版)-第3部分:类和数据抽象——学习笔记
- C++ primer (5th) 随想与学习笔记 1 谈谈坚持的方法与意义
- 《c++ primer》 第13章 拷贝控制 学习笔记
- C++ Primer 学习笔记_12_指针(续)
- C++ Primer 学习笔记(1)——vector的使用方法
- C++ Primer 学习笔记 2012.4.5
- C++ Primer学习笔记- 第三章:标准库类型之三
- C++ primer (5th) 随想与学习笔记 2 怎样在Linux上安装GCC
- C++ Primer 学习笔记4 变量和基本类型 (变量初始化规则、声明和定义)
- 【C++ Primer 学习笔记】Chapter14
- C++ primer第二次阅读学习笔记(第11章:泛型算法)
- C++ Primer 学习笔记(第四章)
- C++ Primer学习笔记2--c++顺序容器