1.友元的概念
传统友元类的概念是:让某个类 B B B成为另外一个类 A A A的友元类,这样,类 B B B就可以在其成员函数中访问类 A A A的所有成员(成员变量,成员函数等),而不管这些成员在类 A A A中是用什么修饰符 ( p r i v a t e 、 p r o t e c t e d 、 p u b i c ) (private、protected、pubic) (private、protected、pubic)修饰的。
现在,当类 A A A和类 B B B都成为了类模板,那么如何让类 B B B成为类 A A A的类模板呢?以下我们详细介绍。
2.让类模板的某个实例成为友元类
如果我们只需要让类模板的一个实例访问另一个类的内部成员,那么我们可以只指定其特定的类型成为友元类。
一般情况下,如果我们这样写,是无法访问其内部成员的:
mplate<typename T>
class A {private:int data;
};template<typename U>
class B {
public:void callBAF() {A<int>a;a.data = 5; //类外无法访问private类型std::cout << a.data << "\n";}
};
原因显然,就是因为类外部不能直接访问 p r i v a t e private private成员。
现在,我们实例化其一个类型作为友元类:
//让类模板的某个实例成为友元类template<typename U> //前向声明
class B;tmplate<typename T>
class A {//增加某个实例的友元类,不需要public或private限制friend class B<int>; //让B<int>成为A的友元类private:int data;
};template<typename U>
class B {
public:void callBAF() {A<int>a;a.data = 5; //访问成功std::cout << a.data << "\n";}
};
因为类 B B B在类 A A A之后定义,所以记得前向声明一下类模板 B B B。
我们看下面调用:
void Test1() {//成功访问B<int>b1;b1.callBAF();//访问失败B<long>b2;b2.callBAF();}
因为我们只实例化了 B < i n t > B<int> B<int>作为 A A A的友元类,因此只有 B < i n t > B<int> B<int>才能访问到 A A A的内部成员,而其他类型的实例化将被拒绝访问。
2. 让类模板成为友元类模板
如果我们想让类模板全部类型都成为另一个类模板的友元类呢?
我们可以使用以下的方法:
我们重新写一个类 C C C,让其成为类 A A A的友元类
//让类模板成为友元类模板
template<typename V>
class C {
public:void callCAF() {A<int>a;a.data = 10;std::cout << a.data << "\n";}
};
在类 A A A中修改:
template<typename T>
class A {//增加某个实例的友元类,不需要public或private限制friend class B<int>; //让B<int>成为A的友元类//让类模板成为友元类,此时也不需要前向声明了template<typename>friend class C;//这样不行,因为会实例化template<typename V>friend class C<V>; //注意这里不能加<V>private:int data;
};
这里注意以下几点:
1.不需要前向声明类模板 C C C
2.定义友元类 C C C的时候不能加上 < V > <V> <V>
前者是因为我们不需要实例化出类 C C C,所以不需要声明。
后者则是因为我们不能尝试实例化出一个不确定的类型 V V V,而应该是一个确定的类型 i n t , d o u b l e int,double int,double等,因此我们应该使用 f r i e n d c l a s s C friend \ class \ C friend class C来声明,这是符合友元类语法的。
3.让类模板参数成为友元类
这是 C + + 11 C++11 C++11引入的新标准,注意这里我们的参数必须是在类类模板的,而不是一般类,如 ( i n t , c h a r ) (int,char) (int,char)等,并且必须在类内使用友元内,超出了类内,也就无效了。
参考下面的代码:
这里我们让 C F CF CF类内拥有一个可以访问 A 2 A2 A2的友元参数 a 1 a1 a1,在 A 2 A2 A2类内定义了友元类 T T T。
这样在类 C F CF CF中实例化的时候,就能将 T T T推导为 C F CF CF了,也就能访问内部成员了。
//让类模板参数成为友元类
template<typename T>
class A2 {friend T;
private:int data;
};class CF {
public:void callCFAF() {A2<CF>a1; //T类型推导为CF类型,所以CF类型是友元类a1.data = 12;std::cout << a1.data << "\n";//不是类类型,将忽略T作为友元类 A2<int>a2;a2.data = 13;std::cout << a2.data << "\n";}
};
而类内的 a 2 a2 a2的类型不是类类型,因此友元类的定义对其无效,编译器会自动忽略。
在类外使用仍然是无效的,即使使用类类型去实例化:
void Test4() {CF cf1;cf1.callCFAF(); //成功访问//只能在当前模板内生效A2<CF>cf2;cf2.data = 12; //访问失败std::cout << cf2.data << "\n";}
这里的 A 2 < C F > c f 2 A2<CF>cf2 A2<CF>cf2对类内友元类型 T T T是无效的,因为其作用域超出了类内。