类模板的友元函数(转载)

from:

http://topic.youkuaiyun.com/u/20071106/17/c562631f-fd24-4836-9e13-43c53157bd8c.html

首先感谢大家的关注和回答.但是发现大家热心有余,认真不足-------因为没有一个人真的编译过我的问题代码..
我在帖子中给的问题代码,因为去除了所有其他的不相关代码,所以是可以编译通过的.如下:
/////////////// Matrix.h 文件内容 (部分代码)//////////////////
#include
//// Matrix 模板前向声明 /////
template
class Matrix;
/////////////////////////////
template
std::ostream& operator * (std::ostream& os,const Matrix & mat);/// 编译通过
template
std::ostream& operator < < (std::ostream& os,const Matrix & mat); /// /// 编译通过
template
class Matrix
{
friend std::ostream& operator * (std::ostream&,const Matrix &); /// 编译 通过
friend std::ostream& operator < < (std::ostream&,const Matrix &); /// 编译 通过
};
而我之前之所以不能编译通过,是因为我的实际代码中声明 了 一个 operator * 的重载成员函数,
导致它和友元的operator * 模板函数冲突 (但实际不应该这样啊.没看见过C++有这类语法要求.)
真正编译不通过的代码如下:
/////////////// Matrix.h 文件内容 (这段代码编译不通过)//////////////////
#include
//// Matrix 模板前向声明 /////
template
class Matrix;
/////////////////////////////
template
std::ostream& operator * (std::ostream& os,const Matrix & mat);/// 编译通过
template
std::ostream& operator < < (std::ostream& os,const Matrix & mat); /// /// 编译通过
template
class Matrix
{
const Matrix operator *(const Matrix&) const; //////// 注意..这里是问题的根源!!!!!!
friend std::ostream& operator * (std::ostream&,const Matrix &); /// 编译不通过
friend std::ostream& operator < < (std::ostream&,const Matrix &); /// 编译 通过
};
昨天发现出现编译不通过的问题后,我被引入了误区,一直以为是operator * 的问题
甚至发现 operator +, operator -,operator / 都不可以.
唯独 operator < < 可以.
后来我发现如果在类中也声明一个 operator < < 的重载成员函数,那么
friend std::ostream& operator < < (std::ostream&,const Matrix &);
这一段也将编译不通过...
所以找到解决方案------ 把所有的friend 声明,都写在类的成员定义之前.代码如下:
/////////////// Matrix.h 文件内容 ( 编译 成功!yeah)//////////////////
#include
//// Matrix 模板前向声明 /////
template
class Matrix;
/////////////////////////////
template
std::ostream& operator * (std::ostream& os,const Matrix & mat);/// 编译通过
template
std::ostream& operator < < (std::ostream& os,const Matrix & mat); /// /// 编译通过
template
class Matrix
{
//////注意,,把所有 friend 声明都放在成员定义之前..////////////
friend std::ostream& operator * (std::ostream&,const Matrix &); /// 编译 通过
friend std::ostream& operator < < (std::ostream&,const Matrix &); /// 编译 通过
const Matrix operator *(const Matrix&) const; //////// 注意..这里是问题的根源!!!!!!
};
------------------------------------------------------------------------------------------------------------------------

//from EuMatrix3.h

//history 1
//关于类模板的友元函数模板
//EuVector3 operator * (const EuVector3 & rkPoint, const EuMatrix3 & rkMatrix);
// EuMatrix3 operator* (TReal fScalar, const EuMatrix3 & rkMatrix);
//参考C++ primer 类模板中的友元声明 三种情况
//here, for second
//I use dev and vc 2005, 发现vc2005支持差,只有当把这两个友元在类中的声明放置在
//其它重载运算符*的函数(eg:EuMatrix3 operator* (const EuMatrix3& rkMatrix) const等)
//前面!!!!!
//才能编译成功!
//而dev no problem!!!!!!
//参考 http://topic.youkuaiyun.com/u/20071106/17/c562631f-fd24-4836-9e13-43c53157bd8c.html

<think>嗯,用户这次的问题是关于C++类模板中友函数的三种类型:非模板友元、约束模板友元和非约束模板友元。从用户的问题描述和引用的资料来看,他应该正在学习C++模板编程的高级特性,可能遇到了实际开发中的友元访问问题。用户显然已经看过一些资料,但对这三者的本质差异和适用场景还不够清晰。他特别强调了“区别”和“适用场景”,说明需要的是实践指导而非纯理论。结合用户提供的三个引用,可以看出:-引用[1]展示了约束模板友元的代码实现-引用[2]解释了多类访问时友元的必要性-引用[3]演示了非约束模板友元的声明方式需要注意用户特别强调的“相互独立”和“不重载”这个关键点。在回复时应该突出:1.语法层面的声明差异(尤其是<>符号的使用)2.实例化机制的差异(一对一vs一对多)3.典型错误场景(比如未前置声明的编译错误)4.性能影响其实不大,主要考虑设计需求用户可能被模板友元的复杂语法困扰,所以示例代码要精简。考虑到他正在编码实践中,应该给出明确的场景选择建议(如日志函数用非约束,运算符重载用约束等)。最后的相关问题延伸了性能优化和模板元编程,满足可能的进阶需求。从专业角度需要澄清一个易错点:非约束友元中的模板参数名遮蔽问题(如引用[3]中内外都用T可能引发歧义),这个细节要体现在对比表格里。另外C++17之后的推导指引对友元的影响可以留到相关问题里扩展。</think> 以下是C++类模板中三类友元函数的区别与适用场景的详细说明,结合您提供的引用资料进行技术分析: --- ### **一、类模板友元函数类型对比** | **类型** | **声明方式** | **实例化特性** | **访问范围** | **适用场景** | |------------------------|-----------------------------------------------------------------------------|-----------------------------------|--------------------------|--------------------------------| | **非模板友元函数** | `friend void func(MyClass<T>& obj);` | 所有模板实例共享**同一函数** | 仅能访问**特定T类型**实例 | 固定类型操作(如日志、调试) | | **约束模板友元函数** | 前置声明模板 → 类内特化声明:<br>`friend void func<>(MyClass<T>& obj);` | **每个T类型实例化独立友元函数** | 可访问**同类型T**的实例 | 类型相关的重载运算符(如`operator<<`) | | **非约束模板友元函数** | 类内声明独立模板:<br>`template <typename U>`<br>`friend void func(MyClass<U>& a, MyClass<U>& b);` | 所有函数模板实例可访问**所有类模板实例** | **任意类型**的实例均可访问 | 跨类型操作(如比较不同T的实例) | --- ### **二、关键区别分析** 1. **实例化机制** - **非模板友元**:仅有一个函数实体,无法适配不同类型 - **约束模板友元**:每个`MyClass<int>`、`MyClass<string>`生成独立的`func()`函数 - **非约束模板友元**:`func<int>()`可访问`MyClass<int>`和`MyClass<float>`等**所有实例** > 引用[1]明确约束模板友元的特性:*"模板类实例化时,每个实例化的类对应一个友元函数"* 2. **类型兼容性** - 当需要操作**不同类型参数**的模板实例时(如`MyClass<int>`与`MyClass<double>`相加),**必须使用非约束模板友元**。 3. **封装性破坏程度** - 非约束友元会**完全暴露所有模板实例的私有成员**给友元函数,需谨慎使用。 --- ### **三、典型代码示例** #### 1. 约束模板友元(实现`operator<<`) ```cpp template<typename T> class MyClass { T data; // 声明特化的友元模板 friend std::ostream& operator<< <>(std::ostream& os, const MyClass<T>& obj); }; template<typename T> std::ostream& operator<<(std::ostream& os, const MyClass<T>& obj) { return os << obj.data; // 可访问私有成员data } ``` > 适用于类型相关的流输出,每个T类型有专属实现[^1][^3] #### 2. 非约束模板友元(跨类型比较) ```cpp template<typename T> class Box { T content; public: // 声明为所有Box类型的友元 template<typename U> friend bool Compare(const Box<U>& a, const Box<U>& b); }; template<typename U> bool Compare(const Box<U>& a, const Box<U>& b) { return a.content == b.content; // 可比较任意U类型的Box } ``` --- ### **四、使用场景建议** 1. **选择约束模板友元当**: - 需要为不同模板参数实现**类型特定行为**(如运算符重载) - 需平衡封装性与灵活性(如引用[3]的加法操作) 2. **选择非约束模板友元当**: - 需操作**多个不同模板参数**的实例(如工厂模式创建关联对象) - 实现**跨类型通用算法**(如比较任意类型的容器) 3. **避免使用非模板友元**: - 在模板场景下功能受限,易导致链接错误(ODR违规) > 引用[2]强调:*"当函数需访问多个类的私有数据时,友元是必要设计手段"*[^2] --- **
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值