C++类模板与友元详解
C++ 模板
下面分四种情况分别讨论。
1. 函数、类、类的成员函数作为类模板的友元
函数、类、类的成员函数都可以作为类模板的友元。程序示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | void Func1() { } class A { }; class B { public : void Func() { } }; template < class T> class Tmpl { friend void Func1(); friend class A; friend void B::Func(); }; int main() { Tmpl< int > i; Tmpl< double > f; return 0; } |
类模板实例化时,除了类型参数被替换外,其他所有内容都原样保留,因此任何从 Tmp1 实例化得到的类都包含上面三条友元声明,因而也都会把 Func1、类 A 和 B::Func 当作友元。
2. 函数模板作为类模板的友元
例题:在《C++类模板(模板类)》一节中我们定义了 Pair 模板,将<<
运算符重载为一个函数模板,并将该函数模板作为 Pair 模板的友元,这样,任何从 Pair 模板实例化得到的对象都能用<<
运算符通过 cout 输出。
程序代码如下(函数模板作为类模板的友元):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <iostream> #include <string> using namespace std; template < class T1, class T2> class Pair { private : T1 key; //关键字 T2 value; //值 public : Pair(T1 k, T2 v) : key(k), value(v) { }; bool operator < ( const Pair<T1, T2> & p) const ; template < class T3, class T4> friend ostream & operator << (ostream & o, const Pair<T3, T4> & p); }; template < class T1, class T2> bool Pair <T1, T2>::operator< ( const Pair<T1, T2> & p) const { //“小”的意思就是关键字小 return key < p.key; } template < class Tl, class T2> ostream & operator << (ostream & o, const Pair<T1, T2> & p) { o << "(" << p.key << "," << p.value << ")" ; return o; } int main() { Pair<string, int > student( "Tom" , 29); Pair< int , double > obj(12, 3.14); cout << student << " " << obj; return 0; } |
程序的输出结果是:
1 | (Torn, 29) (12, 3.14) |
第 13、14 行将函数模板 operator<< 声明为类模板 Pair 的友元。在 Visual Studio 中,这两行也可以用下面的写法替代:
1 | friend ostream & operator<< <T1, T2>(ostream & o, const Pair<T1, T2> & p); |
但在 Dev C ++ 中,替代后编译就无法通过了。
编译本程序时,编译器自动生成了两个 operator << 函数,它们的原型分别是:
1 2 | ostream & operator << (ostream & o, const Pair<string, int > & p); ostream & operator << (ostream & o, const Pair< int , double > & p); |
前者是 Pair <string, int> 类的友元,但不是 Pair<int, double> 类的友元;后者是 Pair<int, double> 类的友元,但不是 Pair<string, int> 类的友元。
3. 函数模板作为类的友元
实际上,类也可以将函数模板声明为友元。程序示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #include <iostream> using namespace std; class A { int v; public : A( int n) :v(n) { } template < class T> friend void Print( const T & p); }; template < class T> void Print( const T & p) { cout << p.v; } int main() { A a(4); Print(a); return 0; } |
程序的输出结果是:
1 | 4 |
编译器编译到第 19 行Print(a);
时,就从 Print 模板实例化出一个 Print 函数,原型如下:
1 | void Print( const A & p); |
这个函数本来不能访问 p 的私有成员。但是编译器发现,如果将类 A 的友元声明中的 T 换成 A,就能起到将该 Print 函数声明为友元的作用,因此编译器就认为该 Print 函数是类 A 的友元。
思考题:类还可以将类模板或类模板的成员函数声明为友元。自行研究这两种情况该怎么写。
4. 类模板作为类模板的友元
一个类模板还可以将另一个类模板声明为友元。程序示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #include <iostream> using namespace std; template < class T> class A { public : void Func( const T & p) { cout << p.v; } }; template < class T> class B { private : T v; public : B(T n) : v(n) { } template < class T2> friend class A; //把类模板A声明为友元 }; int main() { B< int > b(5); A< B< int > > a; //用B<int>替换A模板中的 T a.Func(b); return 0; } |
程序的输出结果是:
1 | 5 |
在本程序中,A< B<int> > 类成为 B<int> 类的友元。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通