模板与友元(转自大佬)_(¦3」∠)_

Template所代表的泛型编程是C++语言中的重要的组成部分,我将通过几篇blog对这半年以来的学习做一个系统的总结,本文是基础篇的第四部分。

类友元

类模板之间、类模板与普通类之间共有三种友元的形式:

友元 普通类 类模板
普通类 不在讨论范围内 类模板友元
类模板 类友元 类模板的类模板友元

普通类的类模板友元

一对一关系

可以将类模板的一个实例声明为普通类的友元。

template <typename T>
class Pal {
public:
    static void Call(T& t) {
        t.show();
    }
};

class HasFriend {
//只有Pal<HasFriend>才是友元,其他实例不行。
//注意这里将未完整定义的class放入了模板。
friend class Pal<HasFriend>; 
private:
    void show() {
        cout << "Calling private method" << endl;
    }
};

HasFriend hf;
Pal<HasFriend>::Call(hf); //Pal<HasFriend>是HasFriend的友元
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

一对多关系

也可以把类模板声明为类的友元模板,这意味着这个类模板的所有实例都是类的友元。声明时要使用template和class关键字(这一点和模板的模板参数很像)。

template <typename T> class Pal;

class HasFriend {
template <typename T> friend class Pal; //注意这里的template、class关键字与friend的前后关系
private:
    void show() {
        cout << "Calling private method" << endl;
    }
};

template <typename T>
class Pal {
public:
    static void Call(HasFriend& hf) {
        hf.show();
    }
};

HasFriend hf;
Pal<void>::Call(hf); //Pal<void>是HasFriend的友元
Pal<int>::Call(hf); //Pal<int>是HasFriend的友元
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

类模板的普通类友元

可以将一个普通类声明为类模板的友元。

class Pal;

template <typename T>
class HasFriend {
friend class Pal;
private:
    void show() {
        cout << "Calling private method" << endl;
    }
};

class Pal {
public:
    static void Call() {
        HasFriend<int> hf;
        hf.show();
    }
};

Pal::Call(); //Pal是HasFriend<int>的友元
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

类模板的类模板友元

一对一关系

可以通过共享类型参数T,在类模板与类模板友元之间达成一对一的关系。

template <typename T>
class Pal;

template <typename T>
class HasFriend {
friend class Pal<T>;
private:
    void show() {
        cout << "Calling private method" << endl;
    }
};

template <typename T>
class Pal {
public:
    static void Call() {
        HasFriend<T> hf;
        hf.show();
    }
};

Pal<int>::Call(); //Pal<int>是HasFriend<int>的友元
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

多对多关系

为类模板友元声明一个不同的类型参数,可以达到多对多关系,也就是说template B的所有实例都是template A的所有实例的友元。

template <typename T>
class Pal;

template <typename T>
class HasFriend {
template <typename U> friend class Pal;
private:
    void show() {
        cout << "Calling private method" << endl;
    }
};

template <typename T>
class Pal {
public:
    static void Call() {
        HasFriend<int> hf;
        hf.show();
    }
};

Pal<double>::Call(); //Pal<double>是HasFriend<int>的友元
Pal<void>::Call(); //Pal<void>是HasFriend<int>的友元
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

函数友元

类(类模板)与函数(函数模板)之间共有三种友元的形式:

友元 普通函数 函数模板
普通类 不在讨论范围内 函数模板友元
类模板 函数友元 类模板的函数模板友元

普通类的函数模板友元

一对一关系

可以将函数模板的一个实例声明为普通类的友元。

template <typename T>
void call(T& t) {
    t.show();
}

class HasFriend {
friend void call<HasFriend>(HasFriend&);
private:
    void show() {
        cout << "Calling private method" << endl;
    }
};

HasFriend hf;
call(hf); //ok, void call<HasFriend>(HasFriend&)是HasFriend的友元
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

一对多关系

也可以把函数模板声明为类的友元模板,这意味着这个函数模板的所有实例都是类的友元。声明时注意要使用template关键字。

template <typename T, typename U>
void call(T& t, U& u) {
    cout << t << endl;
    u.show();
}

class HasFriend {
template <typename T, typename U> friend void call(T&, U&);
private:
    void show() {
        cout << "Calling private method" << endl;
    }
};

HasFriend hf;
int i = 1;
call(i, hf); //void call(int&, HasFriend&)是HasFriend的友元,注意这里的类型自动推导
double d = 2.0;
call(d, hf); //void call(double&, HasFriend&)是HasFriend的友元,注意这里的类型自动推导
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

类模板的函数友元

可以将一个普通函数声明为类模板的友元,这样,这个普通函数就是这个类模板的所有实例的友元。

void call();

template <typename T>
class HasFriend {
friend void call();
private:
    void show() {
        cout << "Calling private method" << endl;
    }
};

void call() {
    HasFriend<int> hf1; 
    HasFriend<double> hf2;
    hf1.show(); //ok,友元
    hf2.show(); //ok,友元
}

call();
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

类模板的函数模板友元

一对一关系

可以通过共享类型参数T,在类模板与函数模板友元之间达成一对一的关系。

template <typename T>
void call(const T& t);

template <typename T>
class HasFriend {
friend void call<T>(const T& t);
private:
    void show() {
        cout << "Calling private method" << endl;
    }
};

template <typename T>
void call(const T& t) {
    HasFriend<T> hf;
    hf.show();
}

call(1); //ok,共享同一个类型实参int
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

多对多关系

为函数模板友元声明一个不同的类型参数,可以达到多对多关系。

template <typename T>
void call(const T& t);

template <typename T>
class HasFriend {
template <typename U> friend void call(const U& u);
private:
    void show() {
        cout << "Calling private method" << endl;
    }
};

template <typename T>
void call(const T& t) {
    HasFriend<int> hf;
    hf.show();
}

call(1.0f); //call<float>是HasFriend<int>的友元
call(2.0); //call<double>是HasFriend<int>的友元
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

模板参数友元

在C++11中,我们还可以将模板类型参数声明为友元。

template <typename T>
class HasFriend {
friend T; //T是HasFriend<T>的友元
private:
    void show() {
        cout << "Calling private method" << endl;
    }
};

class Pal {
public:
    static void call() {
        HasFriend<Pal> hf;
        hf.show();
    }
};

Pal::call();
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

猜你喜欢

转载自blog.csdn.net/weixin_44489823/article/details/90081784