概念
C++是从结构化的C语言发展而来,通常对私有成员访问是通过公有的成员函数间接实现。虽然这种方式对数据隐藏有好处,但对程序员而言增加书写的麻烦,以至于不适合特定的编程问题。因此C++设计者提出友元的概念,通过友元可以访问类中的私有成员。友元有3种:
友元函数友元类友元成员函数友元函数
在定义一个类的时候,可以把一些函数(包括全局函数和其他类的成员函数)声明为“友元”,这样那些函数就成为该类的友元函数,在友元函数内部就可以访问该类对象的私有成员了。将全局函数声明为友元的方法:friend 返回值类型 函数名(参数表); 举个例子:
#include <iostream> using namespace std; class Box { public: friend void print_width(Box box); //不是任何类的成员函数 void set_width(double wid);//成员函数定义 private: double width; static double high; }; double Box::high = 20;//设置高度 void Box::set_width(double wid) { width = wid; } void print_width(Box box) { //print_width()是 Box 的友元,它可以直接访问该类的任何成员 cout << "Width of box : " << box.width << endl; cout << "High of box : " << box.high << endl; } int main() { Box box; box.set_width(10.0); print_width(box); return 0; }
常用的友元函数就是重载 << 运算符,使之能与cout一起显示对象的内容。通常cout << Box语句是不能编译通过的,然后重载<<运算符可以输出我们想要的结果。其实ostream类也是对<<运算符进行了重载,将其转换成一个输出工具。举个例子:
#include <iostream> using namespace std; class Box { public: friend void print_width(Box box); //不是任何类的成员函数 friend ostream& operator << (ostream& os, const Box& box);//不是任何类的成员函数 void set_width(double wid);//成员函数定义 private: double width; static double high; }; double Box::high = 20;//设置高度 void Box::set_width(double wid) { width = wid; } void print_width(Box box) { //print_width()是 Box 的友元,它可以直接访问该类的任何成员 cout << "Width of box : " << box.width << endl; cout << "High of box : " << box.high << endl; } ostream& operator << (ostream& os, const Box& box) { os << box.width << " " << box.high; return os; } int main() { Box box; box.set_width(10.0); print_width(box); cout << "箱子的宽和高:" << box << endl; operator << ((cout << "箱子的宽和高:"), box) << endl; return 0; }
其中ostream& operator << (ostream& os, const Box& box)函数返回类型是ostream&,意味着该函数返回ostream对象的引用。函数开始运行时,程序传递了一个参数给它,最终结果是函数返回值就是传递给它的对象,可以理解为:
cout << "箱子的宽和高:" << box << endl;
将被转换成:
operator << ((cout << "箱子的宽和高:"), box) << endl;
其中cout << "箱子的宽和高:")作为一个对象参数传递给operator <<函数。
友元类
友元类的所有成员函数都是另一个类的友元函数,意味着都快可以访问另一个类中的私有成员。关于友元类需要注意几点:
友元关系不能被继承友元关系是单向的,并不具有交换性。若类B是A的友元,类A不一定是类B的友元,要看类中是否有相应的声明。 友元关系不具有传递性。若类B是类A的友元,类C是类B的友元,类C不一定是类A的友元,要看类中是否有相应的声明。举个例子:
#include <iostream> using namespace std; class Box { public: friend class BigBox; friend void print_width(Box box); //不是任何类的成员函数 friend ostream& operator << (ostream& os, const Box& box);//不是任何类的成员函数 void set_width(double wid);//成员函数定义 private: double width; static double high; }; class BigBox { public: void Print(int width, Box& box) { // BigBox是Box的友元类,它可以直接访问Box类的任何成员 box.set_width(width); cout << "Width of box : " << box.width << endl; } }; double Box::high = 20;//设置高度 void Box::set_width(double wid) { width = wid; } void print_width(Box box) { //print_width()是 Box 的友元,它可以直接访问该类的任何成员 cout << "Width of box : " << box.width << endl; cout << "High of box : " << box.high << endl; } ostream& operator << (ostream& os, const Box& box) { os << box.width << " " << box.high; return os; } int main() { Box box; BigBox big; // 使用成员函数设置宽度 box.set_width(10.0); // 使用友元函数输出宽度 print_width(box); // 使用友元类中的方法设置宽度 big.Print(20, box); return 0; }
其中类BigBox是类Box的友元类,可以访问类Box的任意私有成员。
友元成员函数
当类B中的成员函数声明为类A的友元函数,这样类B的该成员函数就可以访问类A中私有成员。举个例子:
#include <iostream> using namespace std; class Box; //类BigBox引用了类Box,一定要提前声明。注意,这里是声明即可 class BigBox { public: void Print(int width, Box& box); }; class Box { public: friend void BigBox::Print(int width, Box& box); //在这里之前,必须要先有BigBox的定义,注意是“定义”,不能是声明,所以前面在定义BigBox类 friend void print_width(Box box); //不是任何类的成员函数 void set_width(double wid);//成员函数定义 private: double width; static double high; }; double Box::high = 20;//设置高度 void Box::set_width(double wid) { width = wid; } void print_width(Box box) { //print_width()是 Box 的友元,它可以直接访问该类的任何成员 cout << "Width of box : " << box.width << endl; cout << "High of box : " << box.high << endl; } void BigBox::Print(int width, Box& box) { // BigBox是Box的友元类,它可以直接访问Box类的任何成员 box.set_width(width); cout << "Width of box : " << box.width << endl; } int main() { Box box; BigBox big; // 使用成员函数设置宽度 box.set_width(10.0); // 使用友元函数输出宽度 print_width(box); // 使用友元类中的方法设置宽度 big.Print(20, box); return 0; }
其中类BigBox引用了类Box,一定要提前声明,然而这里是声明即可,不然编译器无法找到类Box。
还没有评论,来说两句吧...