码迷,mamicode.com
首页 > 其他好文 > 详细

friend 不仅仅可以作为友元

时间:2014-05-07 06:47:02      阅读:285      评论:0      收藏:0      [点我收藏+]

标签:effective c++   friend   

friend是C++中封装的漏网之鱼。

C++中的friend允许另外的类或者是函数访问本类的任何成员,甚至是private成员,只要该类声明其为友元。

可是,在有些情况下,并不是允许外界访问类的内部实现而使用友元。这就是在 “模板定义” 与 “类型转换” 之间的一个trick了。

首先,看一个简单的有理数的模板类,该类定义了有理数,并且实现有理数的乘法。


注:下述代码中,将operator*声明为非成员函数,是因为 

“如果你需要对成员函数所有的参数(所有的,当然也就包括this指针啦)进行类型转换,那么将该函数声明为非成员函数”。

这对C++模板类同样适用。



在上述代码中,重载了 * 符号,用于计算两个有理数之间的乘法。


一个自然而然的道理,如果我们需要支持 有理数 * 自然数 ,这是一个无可厚非的要求。当我们才有下面的调用 


Rational<int> a = Rational(1,2);

Rational<int> ret = a * 2; 


编译不通过,在非模板类中这是很正常的事,可是在模板类中却出现了问题.

下面一一进行分析:

当编译器看到operator*的调用的时候,编译器不知道我们调用哪个函数,编译器看到这个模板函数时,第一要做的就是将该

函数实例化出来,也就是要首先推断出T的类型,但是几经周折,发现不行。

首先,为了推导出T,编译器对 * 调用的两个参数进行入手,分别为 Rational<int>   和 int, 由第一个参数可以得到 T

为int, 但是在第二个实参呢,编译器怎么推断 T 的类型。 你也许会说,此时编译器就应该使用 Rational<int> 的隐式构造函数

啊。不就可以 推导出 T 的类型了吗。 但是,编译器绝不会这么做,因为在 模板实参  的推导过程当中是不会 考虑隐式转换的。


这是本文最重要的一句话。


因此,在面对这样的 实参推导 的问题是,friend 变出场了,由于 friend 可以在  模板类 中指明某个特定的函数,也就是说,

在函数调用之前,声明该函数,那么在函数调用时,相应的类模板 就不再需要 依赖于 模板实参的推导了,而只需要对这个

友元函数进行参数推导即可。

因此将operator * 声明为该类的友元。


但是,还有一个问题,便是链接时的问题了,只在类定义体中声明该函数,如果不定义的话,连接器便会发出抱怨,找不到

定义体(这里没看懂。需要仔细斟酌。)


因此,将 operator* 声明为友元函数并且将实现定义在类中。


于是,在类模板定义时,出现了同样的话,如果  在编写一个类模板的时候,而 该类的与模板相关的函数  需要支持函数参数隐式转换的时候,将该函数定义为模板类类中的friend函数。





friend 不仅仅可以作为友元,布布扣,bubuko.com

friend 不仅仅可以作为友元

标签:effective c++   friend   

原文地址:http://blog.csdn.net/xuqingict/article/details/25077777

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!