友元函数
原则上,类的private和protected成员不能在其声明的类外进行访问。但是,这一规则对友元不起作用。
友元是通过关键字friend声明的函数或类。
如果声明一个外部函数为一个类的友元,这样就允许此函数操作这个类的private和protected成员。通过在类的内部声明这个外部函数,并在其前面加上friend关键字:
// friend functions #include <iostream> using namespace std; class CRectangle { int width, height; public: void set_values (int, int); int area () {return (width * height);} friend CRectangle duplicate (CRectangle); }; void CRectangle::set_values (int a, int b) { width = a; height = b; } CRectangle duplicate (CRectangle rectparam) { CRectangle rectres; rectres.width = rectparam.width*2; rectres.height = rectparam.height*2; return (rectres); } int main () { CRectangle rect, rectb; rect.set_values (2,3); rectb = duplicate (rect); cout << rectb.area(); return 0; }
输出:24
函数duplicate是类CRectangle的一个友元。在这个函数内部我们就可以操作CRectangle不同对象的private成员width和height。无论是在duplicate声明中,还是在之后main()中的使用。我们都没有认为duplicate是类CRectangle的一个成员。它不是!它只是可以操作类的private和protected成员,而不是其成员。
友元函数可以作用于,例如,操作两个不同的类。通常来说,友元函数的运用已经超出了面向对象的编程方法,因此最好通过同一类的成员来操作此类。就像之前的例子,若将duplicate()整合到类CRectangle中,整个例子就会更加精简。
友元类
就像我们可以定义一个友元函数,我们也可以定义类的友元类。假设第一个类可以操作第二个类的protected和private成员。
// friend class #include <iostream> using namespace std; class CSquare; class CRectangle { int width, height; public: int area () {return (width * height);} void convert (CSquare a); }; class CSquare { private: int side; public: void set_side (int a) {side=a;} friend class CRectangle; }; void CRectangle::convert (CSquare a) { width = a.side; height = a.side; } int main () { CSquare sqr; CRectangle rect; sqr.set_side(4); rect.convert(sqr); cout << rect.area(); return 0; }
输出:16
在这个例子中,我们将CRectangle声明为CSquare的一个友元,因此CRectangle成员函数就可以操作CSquare的protected和private成员,具体就是描述正方形边长的CSquare::side。
你也可以在这段程序的开头看到一些新东西:类CSquare的空声明。这是需要的,因为在类CRectangle的声明中我们涉及到类CSquare(作为convert()的参数)。类CSquare的定义在后面,如果我们不在之前包括其空声明,CSquare在CRectangle定义内部就是不可见的。
友元不是相互的,如果我们不显示指定。在我们的例子中,CRectangle是类CSquare的一个友元,但是CRectangle并不认为CSquare是其友元。因此CRectangle可以操作CSquare的protected和private成员,但反之不然。当然,如果需要,我们可以将CSquare声明为CRectangle的一个友元。