模板类和友元函数

模板类的友元分3类:
非模板友元
约束(bound)模板友元,即友元的类型取决于类被实例化时的类型。
非约束(undound)模板友元,即友元的所有具体化都是类的每一个具体化的友元。

1.模板类的非模板友元函数

template<class T>
class HasFriend
{ friend void counts();  //friend to all HaFriend instantiations
  ... };

上诉声明使counts()函数成为模板所有实例化的友元。


     counts()函数不是通过对象调用的,也没有对象参数。它可以访问全局对象;可以使用全局指针访问非全局对象;可以创建自己的对象;可以访问独立于对象的模板类的静态数据成员。

 

为友元函数提供模板类参数,必须提供特定的具体化,如HasFriend<short>。

要提供模板类参数,必须指明具体化:
template<class T>
class HasFriend
{ friend void report(HasFriend<T> & ); 
// bound template friend
  ... };

 

     也就是说,带HasFriend<int>参数的report()将成为HasFriend<int>类的友元函数。同样,带HasFriend<double>参数的report()将是report()的一个重载版本——它将是HasFriend<double>类的友元。

 

report()本省并不是模板函数,而只是使用一个模板作参数。这意味着必须为要使用的友元定义显示具体化:
void report(HasFriend<short> & ) {...} //explicit specialization for short
void report(HasFriend<int> & ) {...}     //explicit specialization for int

 

2.模板类的约束模板友元函数
修改前一个上面的范例,使友元函数本身成为模板。使类的每一个具体化都获得与友元匹配的具体化。包含以下三步:

首先,在类定义的前面声明每个模板函数:
template <typename T> void counts();
template <typename T> void report(T &);

 

然后在函数中再次将模板声明为友元。这些语句根据类模板参数的类型声明具体化:
template<class TT>
class HasFriend
{ friend void counts<TT>();
  friend void report<>(HasFriend<TT> &);
  ... };

 

    上述声明中的<>指出这是模板具体化。对于report(),<>可以为空,这是因为可以从函数参数推断出模板类型参数(HasFriend<TT>)。不过,也可以使用report<HasFriend<TT> >(HasFriend<TT> &)。但counts()函数没有参数,因此必须使用模板参数句法(<TT>)来指明其具体化。还需要注意的是,TT是HasFriend类的参数类型。

 

假设声明了这样一个对象:
HasFriend<int> squack;

则编译器将用int替换TT,并生成下面的类定义:
class HasFriend<int>
{ friend void counts<int>();
  friend void report<>(HasFriend<int> &);
  ... };

于是,模板具体化counts<int>()和report<HasFriend<int> >()被声明为HasFriend<int>类的友元。

 

最后,程序必须为友元提供模板定义,例如:
template <typename T>
void counts() { cout << HasFriend<T>::x << endl;}

template <typename T>
void report(T & hf) {cout << hf.x << endl;}

 

调用时,counts()需要提供具体化参数类型。report()只需直接调用,例如:
counts<int>();  //调用HasFriend<int>的友元函数
HasFriend<double> hfdb;
report(hfdb);   //调用HasFriend<double>的友元函数

3.模板类的非约束模板友元函数
    通过在类内部声明友元函数模板,可以创建非约束友元函数,即每个函数具体化都是每个类具体化的友元:
template <typename T>
class ManyFriend
{...
 template <typename C,typename D> friend void show(C &,D &);
};

 

在类外定义该友元:
template <typename C,typename D>
void show(C & c,D & d){ ... }

 

假如创建ManyFriend<int>类对象(hfi1)和ManyFriend<double>类对象(hfi2),传递给show(),那么编译器将生成如下具体化定义:
void show<ManyFriend<int> &,ManyFriend<double> &>
         (ManyFriend<int> & c,ManyFriend<double> & d){ ... }

<think>嗯,用户想了解C++类模板友元函数的使用方法,需要一个示例。首先,我得回忆一下类模板友元函数的基本概念。类模板允许我们创建可以处理不同数据类型的类,而友元函数则可以访问类的私有成员。但是当两者结合时,可能会有一些语法上的复杂性。 记得友元函数类模板中的声明需要注意模板参数的作用域。比如,在类内部声明友元函数时,如果友元函数本身也是模板函数,需要正确指定模板参数。否则可能会导致链接错误或者访问权限问题。 用户提供的引用中有一个普通类的友元函数示例,但类模板的情况更复杂。例如,在类模板中,友元函数可能需要成为函数模板,或者需要特定的模板参数声明。可能需要使用前向声明或者在类内部定义友元函数。 比如,一个常见的做法是在类模板外部定义友元函数时,必须确保函数模板的参数类模板正确关联。例如,使用`template<typename T> friend void show(const MyClass<T>& obj);`这样的声明。同时,友元函数的实现也需要处理模板参数,可能需要将友元函数定义为模板函数。 另外,要注意友元函数类模板中的两种常见形式:一种是每个模板实例化对应一个友元函数,另一种是所有实例化共享同一个友元函数。用户可能需要前者,即每个类模板实例化的友元函数能访问对应实例的私有成员。 可能还需要考虑运算符重载的情况,比如重载<<运算符作为友元函数,这在类模板中也需要正确的模板声明。例如,在类模板内部声明友元函数时,需要提前声明函数模板,并在类内部声明为友元。 然后,我需要构造一个具体的示例。比如,设计一个类模板`MyClass<T>`,包含一个私有数据成员,然后定义一个友元函数`show`来输出这个私有成员。需要展示如何在类模板内部声明友元函数,并在外部定义它。同时,需要处理模板参数的正确传递,确保编译通过。 还需要注意,友元函数的定义如果在类外部,必须包含模板参数,并且在声明时需要使用正确的语法,例如在类内部声明为`friend void show<>(MyClass<T> &obj);`,其中`<>`表示这是一个函数模板的特化。 另外,用户可能对友元函数在模板中的不同场景应用感兴趣,比如普通友元函数、运算符重载作为友元,或者友元函数模板。可能需要分点说明,并给出不同的示例,比如普通友元函数运算符重载的情况。 最后,确保示例代码的正确性,避免出现常见的错误,比如链接错误,或者访问私有成员失败的问题。可能需要参考之前的引用内容,但用户提供的引用是关于非模板类友元函数,所以需要调整到模板的情况。 总结步骤:1. 类模板的定义,包含私有成员;2. 友元函数的声明,注意模板参数;3. 友元函数的定义,正确处理模板;4. 主函数中的使用示例;5. 可能的扩展,如运算符重载。</think>### C++类模板友元函数定义使用 类模板友元函数需要特别注意**模板参数作用域****友元声明方式**。以下是三种典型场景的实现方法: --- #### 一、基础用法:普通友元函数类模板中声明外部函数为友元时,需显式指定模板参数: ```cpp #include <iostream> using namespace std; template<typename T> class MyClass { private: T data; public: MyClass(T val) : data(val) {} // 声明友元函数(需前置声明模板函数) friend void showData(MyClass<T> obj); }; // 定义模板友元函数 template<typename T> void showData(MyClass<T> obj) { cout << "Data: " << obj.data << endl; // 访问私有成员 } int main() { MyClass<int> a(100); showData(a); // 输出:Data: 100 } ``` **关键点**:友元函数声明需类模板参数绑定`<T>`[^1] --- #### 二、运算符重载友元函数类模板重载运算符时,友元函数需要处理模板参数: ```cpp template<typename T> class Box { private: T width; public: Box(T w) : width(w) {} // 声明友元运算符(需前置声明) friend ostream& operator<<<>(ostream& out, const Box<T>& box); }; // 定义运算符重载 template<typename T> ostream& operator<<(ostream& out, const Box<T>& box) { out << "Box width: " << box.width; return out; } int main() { Box<double> b(10.5); cout << b; // 输出:Box width: 10.5 } ``` **注意**:运算符声明时需添加`<>`表示模板特化[^2] --- #### 三、跨类友元函数(进阶) 多个类模板共享友元函数时,需交叉声明: ```cpp template<typename U> class ClassB; // 前向声明 template<typename T> class ClassA { private: T value; public: ClassA(T v) : value(v) {} friend void showBoth<>(const ClassA<T>& a, const ClassB<T>& b); }; template<typename U> class ClassB { private: U value; public: ClassB(U v) : value(v) {} friend void showBoth<>(const ClassA<U>& a, const ClassB<U>& b); }; template<typename T> void showBoth(const ClassA<T>& a, const ClassB<T>& b) { cout << "A.value: " << a.value << "\nB.value: " << b.value << endl; } int main() { ClassA<int> a(10); ClassB<int> b(20); showBoth(a, b); // 输出两类的私有数据 } ``` ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值