zoukankan      html  css  js  c++  java
  • 模板的一般友员函数

     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 <iostream>
    using namespace std;
     
    class Friendly {
    int i;
    public:
    Friendly(int theInt) { i = theInt; }
    friend void f(const Friendly&); // Needs global def.
    void g() { f(*this); }
    };
     
    void h() {
    f(Friendly(1)); // Uses ADL
    }
     
    void f(const Friendly& fo) { // Definition of friend
    cout << fo.i << endl;
    }
     
    int main() {
    h(); // Prints 1
    Friendly(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 <iostream>
    using namespace std;
     
    // Necessary forward declarations:
    template<class T> class Friendly;
    template<class T> void f(const Friendly<T>&);
     
    template<class T> class Friendly {
    T t;
    public:
    Friendly(const T& theT) : t(theT) {}
    friend void f<>(const Friendly<T>&);
    void g() { f(*this); }
    };
     
    void h() {
    f(Friendly<int>(1));
    }
     
    template<class T> void f(const Friendly<T>& fo) {
    cout << fo.t << endl;
    }
     
    int main() {
    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 (<T>) 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 <iostream>
    using namespace std;
     
    template<class T> class Friendly {
    T t;
    public:
    Friendly(const T& theT) : t(theT) {}
    friend void f(const Friendly<T>& fo) {
    cout << fo.t << endl;
    }
    void g() { f(*this); }
    };
     
    void h() {
    f(Friendly<int>(1));
    }
     
    int main() {
    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<class T> class Box {
    T t;
    public:
    Box(const T& 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 <iostream>
    using namespace std;
     
    // Forward declarations
    template<class T> class Box;
     
    template<class T>
    Box<T> operator+(const Box<T>&, const Box<T>&);
     
    template<class T>
    ostream& operator<<(ostream&, const Box<T>&);
     
    template<class T> class Box {
    T t;
    public:
    Box(const T& theT) : t(theT) {}
    friend Box operator+<>(const Box<T>&, const Box<T>&);
    friend ostream& operator<< <>(ostream&, const Box<T>&);
    };
     
    template<class T>
    Box<T> operator+(const Box<T>& b1, const Box<T>& b2) {
    return Box<T>(b1.t + b2.t);
    }
     
    template<class T>
    ostream& operator<<(ostream& os, const Box<T>& b) {
    return os << '[' << b.t << ']';
    }
     
    int main() {
    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 <iostream>
    using namespace std;
     
    template<class T> class Box {
    T t;
    public:
    Box(const T& theT) : t(theT) {}
    friend Box<T> operator+(const Box<T>& b1,
    const Box<T>& b2) {
    return Box<T>(b1.t + b2.t);
    }
    friend ostream&
    operator<<(ostream& os, const Box<T>& b) {
    return os << '[' << b.t << ']';
    }
    };
     
    int main() {
    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<int>(const Friendly<int>&) is a friend of the class Friendly<int>. 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:
    friend void f<>(const Friendly<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<double>( ) 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:
    friend void g(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<class T> class Friendly {
    template<class U> friend void f<>(const Friendly<U>&);
     

    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.

  • 相关阅读:
    LintCode2016年8月22日算法比赛----骰子求和
    LintCode2016年8月22日算法比赛----平面列表
    LintCode2016年8月22日算法比赛----将数组重新排序以构造最小值
    LintCode2016年8月22日算法比赛----克隆二叉树
    Leetcode算法比赛----Longest Absolute File Path
    Leetcode算法比赛----First Unique Character in a String
    vue运行报错Error: listen EADDRNOTAVAIL 192.168.1.105:8080
    vue使用lrz插件压缩图片
    <input type="file">原型难看
    vue创建全局变量以及全局方法
  • 原文地址:https://www.cnblogs.com/openix/p/3063380.html
Copyright © 2011-2022 走看看