一、什么是友元
在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; // 先声明一个类Test class 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; }
五、总结
友元的作用是在某些场景提高程序的效率,但是同时也破坏了类的封装性和数据的隐藏性。声明友元时,要注意友元的位置,编译器是否已经识别或者编译了所声明的友元,如果没有,就会报错,所以可以采用再类中定义友元,把友元类的函数在类外实现,具体例子看上面的案例。