模板的一般友员函数

1 #include <iostream>                                                                                                                                                                   
 2 #include <string.h>
 3 
 4 using namespace std;
 5 
 6 template < class T >
 7 class myvector
 8 {
 9     private://在内部定义
10         friend ostream& operator<< (ostream& o, const myvector<T>& value)
11         {       
12             cout << value.age << endl;
13             cout << value.name << endl;
14         }       
15 
16     private:
17         int age;
18         char name[10];
19 
20     public: 
21         myvector(void)
22         {       
23             age = 24;
24             strcpy(name, "SOOCHOW");
25         }       
26 
27         myvector(const myvector& value)
28         {       
29             age = value.age;
30             strcpy(name, value.name);
31         }       
32 
33         myvector& operator= (const myvector& value)
34         {       
35             age = age + value.age;
36             strcpy(name, value.name);
37 
38             return *this;
39         }       
40 
41         int getvalue(void)
42         {       
43             return age;
44         }       
45 };
46 
47 int main(void)
48 {
49     myvector<int> test_one;
50     myvector<int> test_two = test_one;
51 
52     cout << test_two << endl;
53 
54     return 0;
55 }

引述自:http://www.linuxtopia.org/online_books/programming_books/c%2B%2B_practical_programming/c++_practical_programming_125.html

A friend function declaration inside a class allows a non-member function to access non-public members of that class. If the friend function name is qualified, it will be found in the namespace or class that qualifies it. If it is unqualified, however, the compiler must make an assumption about where the definition of the friend function will be, since all identifiers must have a unique scope. The expectation is that the function will be defined in the nearest enclosing namespace (non-class) scope that contains the class granting friendship. Often this is just the global scope. The following non-template example clarifies this issue:
//: C05:FriendScope.cpp#include usingnamespacestd;classFriendly {inti;public:Friendly(inttheInt) { i = theInt; }friendvoidf(constFriendly&);// Needs global def.voidg() { f(this); }};voidh() {f(Friendly(1));// Uses ADL}voidf(constFriendly& fo) {// Definition of friendcout << fo.i << endl;}intmain() {h();// Prints 1Friendly(2).g();// Prints 2}///:~
The declaration of
f( ) inside the Friendly class is unqualified, so the compiler will expect to be able to eventually link that declaration to a definition at file scope (the namespace scope that contains Friendly in this case). That definition appears after the definition of the function h( ). The linking of the call to f( ) inside h( ) to the same function is a separate matter, however. This is resolved by ADL. Since the argument of f( ) inside h( ) is a Friendly object, the Friendly class is searched for a declaration of f( ), which succeeds. If the call were f(1) instead (which makes some sense since 1 can be implicitly converted to Friendly(1)), the call should fail, since there is no hint of where the compiler should look for the declaration of f( ). The EDG compiler correctly complains that f* is undefined in that case.

Now suppose that Friendly and f are both templates, as in the following program:
//: C05:FriendScope2.cpp#include usingnamespacestd;// Necessary forward declarations:template<classT>classFriendly;template<classT>voidf(constFriendly&);template<classT>classFriendly {T t;public:Friendly(constT& theT) : t(theT) {}friendvoidf<>(constFriendly&);voidg() { f(this); }};voidh() {f(Friendly<int>(1));}template<classT>voidf(constFriendly& fo) {cout << fo.t << endl;}intmain() {h();Friendly<int>(2).g();}///:~
First notice that angle brackets in the declaration of
f inside Friendly. This is necessary to tell the compiler that f is a template. Otherwise, the compiler will look for an ordinary function named f and not find it. We could have inserted the template parameter (*) in the brackets, but it is easily deduced from the declaration.

The forward declaration of the function template f before the class definition is necessary, even though it wasn t in the previous example when f was a not a template; the language specifies that friend function templates must be previously declared. To properly declare f, Friendly must also have been declared, since f takes a Friendly argument, hence the forward declaration of Friendly in the beginning. We could have placed the full definition of f right after the initial declaration of Friendly instead of separating its definition and declaration, but we chose instead to leave it in a form that more closely resembles the previous example.

One last option remains for using friends inside templates: fully define them inside the host class template definition itself. Here is how the previous example would appear with that change:
//: C05:FriendScope3.cpp {-bor}// Microsoft: use the -Za (ANSI-compliant) option#include usingnamespacestd;template<classT>classFriendly {T t;public:Friendly(constT& theT) : t(theT) {}friendvoidf(constFriendly& fo) {cout << fo.t << endl;}voidg() { f(this); }};voidh() {f(Friendly<int>(1));}intmain() {h();Friendly<int>(2).g();}///:~
There is an important difference between this and the previous example:
f is not a template here, but is an ordinary function. (Remember that angle brackets were necessary before to imply that f( ) was a template.) Every time the Friendly class template is instantiated, a new, ordinary function overload is created that takes an argument of the current Friendly* specialization. This is what Dan Saks has called making new friends. [68] This is the most convenient way to define friend functions for templates.

To clarify, suppose you want to add non-member friend operators to a class template. Here is a class template that simply holds a generic value:
template<classT>classBox {T t;public:Box(constT& theT) : t(theT) {}};
Without understanding the previous examples in this section, novices find themselves frustrated because they can t get a simple stream output inserter to work. If you don t define your operators inside the definition of Box, you must provide the forward declarations we showed earlier:
//: C05:Box1.cpp// Defines template operators.#include usingnamespacestd;// Forward declarationstemplate<classT>classBox;template<classT>Boxoperator+(constBox&,constBox&);template<classT>ostream&operator<<(ostream&,constBox&);template<classT>classBox {T t;public:Box(constT& theT) : t(theT) {}friendBoxoperator+<>(constBox&,constBox&);friendostream&operator<< <>(ostream&,constBox&);};template<classT>Boxoperator+(constBox& b1,constBox& b2) {returnBox(b1.t + b2.t);}template<classT>ostream&operator<<(ostream& os,constBox& b) {returnos << '[' << b.t << ']';}intmain() {Box<int> b1(1), b2(2);cout << b1 + b2 << endl;// [3]// cout << b1 + 2 << endl; // No implicit conversions!}///:~
Here we are defining both an addition operator and an output stream operator. The main program reveals a disadvantage of this approach: you can t depend on implicit conversions (the expression b1 + 2) because templates do not provide them. Using the in-class, non-template approach is shorter and more robust:
//: C05:Box2.cpp// Defines non-template operators.#include usingnamespacestd;template<classT>classBox {T t;public:Box(constT& theT) : t(theT) {}friendBoxoperator+(constBox& b1,constBox& b2) {returnBox(b1.t + b2.t);}friendostream&operator<<(ostream& os,constBox& b) {returnos << '[' << b.t << ']';}};intmain() {Box<int> b1(1), b2(2);cout << b1 + b2 << endl;// [3]cout << b1 + 2 << endl;// [3]}///:~
Because the operators are normal functions (overloaded for each specialization of Box just int in this case), implicit conversions are applied as normal; so the expression b1 + 2 is valid.

Note that there s one type in particular that cannot be made a friend of Box, or any other class template for that matter, and that type is T or rather, the type that the class template is parameterized upon. To the best of our knowledge, there are really no good reasons why this shouldn t be allowed, but as is, the declaration friend class T is illegal, and should not compile.

Friend templates

You can be precise as to which specializations of a template are friends of a class. In the examples in the previous section, only the specialization of the function template f with the same type that specialized Friendly was a friend. For example, only the specialization f(const Friendly&) is a friend of the class Friendly. This was accomplished by using the template parameter for Friendly to specialize f in its friend declaration. If we had wanted to, we could have made a particular, fixed specialization of f a friend to all instances of Friendly, like this:
// Inside Friendly:friendvoidf<>(constFriendly<double>&);
By using double instead of T, the double specialization of f has access to the non-public members of any Friendly specialization. The specialization f( ) still isn t instantiated unless it is explicitly called.

Likewise, if you declare a non-template function with no parameters dependent on T, that single function is a friend to all instances of Friendly:
// Inside Friendly:friendvoidg(int);// g(int) befriends all Friendlys
As always, since g(int) is unqualified, it must be defined at file scope (the namespace scope containing Friendly).

It is also possible to arrange for all specializations of f to be friends for all specializations of Friendly, with a so-called friend template, as follows:
template<classT>classFriendly {template<classU>friendvoidf<>(constFriendly&);
Since the template argument for the friend declaration is independent of T, any combination of T and U is allowed, achieving the friendship objective. Like member templates, friend templates can appear within non-template classes as well.
原文链接: https://www.cnblogs.com/openix/archive/2013/05/06/3063380.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/87404

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 下午11:05
下一篇 2023年2月9日 下午11:06

相关推荐