一、什么是友元
在C++中,为了提高程序的效率,在一些场景下,引入友元,但同时类的封装性就会被破坏。
二、怎么实现友元
友元关键字(friend)
// 在类中声明另一个类的成员函数来做为友元函数 // 以关键字(friend)开头:比如friend 返回值类型 类名::类成员函数(参数列表) friend void A::test(Test &t);// 全局函数做友元函数// friend 普通函数的声明friend void print(Test &t);// 友元类,要在另外一个类中声明 class 类名1 {friend class 友元类名; // 在类里面声明友元类 }
三、友元的特点
1、友元关系是单向的,不具备交换性。
2、友元关系不能被继承。
3、友元关系不具有传递性。
4、友元不是类成员,但是它可以通过对象访问类中私有成员,友元作用在于提高程序的运行效率,但是,它破坏了类的封装和数据隐藏性。除非调用访问私有成员变量的频率频繁,才会考虑牺牲封装和数据隐藏性,来换取运行效率。
5、模板类中声明的友元函数必须要指定具体类型才行,不能声明一个友元函数模板。
四、案例
1、 在类中声明另一个类的成员函数来做为友元函数
#include <iostream>using namespace std;class Base; class Test { public:// 不可以在类中实现,只能在类外实现, 此时编译器还没有编译Base类,无法识别出友元void show(Base &other); // {// cout << "a = " << other.a << endl;// }};class Base { private:int a; public:Base(int a = 0){this->a = a;}friend void Test::show(Base &other); };// 不可以在类中实现,只能在类外实现,此时编译器已识别出友元 void Test::show(Base &other) {cout <<"void Test::show(Base &other)" << endl;cout << "a = " << other.a << endl; }int main() {Base A(10);Test test;test.show(A);return 0; }
2、全局函数做友元函数
#include <iostream>using namespace std;class Base { private:int a; public:Base(int a = 0){this->a = a;}// 全局函数声明为友元函数friend void show(Base &other); };// 全局函数声明为友元函数 void show(Base &other) {cout << "void show(Base &other)" << endl;cout << "a = " << other.a << endl; }int main() {Base A(10);show(A);return 0; }
3、友元类
#include <iostream>using namespace std;class Test; // 先声明一个类Testclass Base { private:int a; public:Base(int a = 0){this->a = a;}friend class Test; // 把类Test声明为友元类 };class Test { public:void show(Base &other){cout << "void Test::show(Base &other)" << endl;cout << "a = " << other.a << endl;}};int main() {Base A(10);Test test;test.show(A);return 0; }
4、模板类中声明的友元函数必须要指定具体类型才行,不能声明一个友元函数模板。
#include <iostream>using namespace std;template <class T> class Test { private:T a; public:Test(T a = T()){this->a = a;}// 定义一个友元函数模板,编译不能通过friend ostream& operator << (ostream& output, const Test<T> &other);};template <class T> ostream& operator << (ostream& output, const Test<T> &other) {output << "a = " << other.a << endl;return output; }int main() {Test<int> A(10);cout << A << endl;return 0; }
改正:
#include <iostream>using namespace std;template <class T> class Test { private:T a; public:Test(T a = T()){this->a = a;}// 指定友元函数的具体模板类型,但是这样模板类的作用几乎失效friend ostream& operator << (ostream& output, const Test<int> &other);};// 指定模板类为int类型 ostream& operator << (ostream& output, const Test<int> &other) {output << "ostream& operator << (ostream& output, const Test<int> &other)" << endl;output << "a = " << other.a;return output; }int main() {Test<int> A(10);cout << A << endl;return 0; }
五、总结
友元的作用是在某些场景提高程序的效率,但是同时也破坏了类的封装性和数据的隐藏性。声明友元时,要注意友元的位置,编译器是否已经识别或者编译了所声明的友元,如果没有,就会报错,所以可以采用再类中定义友元,把友元类的函数在类外实现,具体例子看上面的案例。