您的位置:首页 > 编程语言 > C语言/C++

C++ Primer 学习笔记 — 友元

2013-11-05 20:54 274 查看
友元机制允许一个类将对其非公有成员的访问权授予指定的函数或者类。友元的声明以关键字friend开始,只能出现在类定义的内部,友元的声明可以出现在类内部的任何地方。通常,将友元成组地放在类的开始或者结尾是个好主意。

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的友元。

⑥ 友元关系不能继承,基类的友元对派生类的成员没有特殊的访问权限。如果基类被授予友元关系,则只有基类具有特殊的访问权限。该基类的派生类不能访问授予友元关系的类。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: