将模板申明为友元

代码编译运行环境:VS2012+Debug+Win32


严格来说,函数模板(类模板)是不能作为一个类的友元的,就像类模板之间不能发生继承关系一样。只有当函数模板(或类模板)被实例化之后生成模板函数(或模板类),该函数(或类)才能作为其他的类的友元。为了叙述的方便,我们也称一个函数模板(或类模板)是一个类或类模板的友元,其实真正的含义是函数模板(或类模板)被实例化后生成的模板函数(模板类)作为类(或模板类)的友元。

1. 把函数模板声明为类模板的友元

将函数模板申明为类模板的友元有三种方式。

1.1在类模板内部声明友元的函数模板

考察如下代码:

#include <iostream>
using namespace std;

template<typename T>class A{
    T num;
public:
    A(){
        num=T(5.5);
    }
    template<typename T> friend void show(const A<T>&a);
};

template<typename T> void show(const A<T>&a){
    cout<<a.num<<endl;
}

int main(){
    A<int> a;
    show<int>(a);
}

程序正确运行并输出5。

1.2在类模板内部对显示模板参数的函数模板进行友元申明

这种方法需要前置申明函数模板,考察如下程序。

#include <iostream>
using namespace std;
template<typename T>class A;
template<typename T>void show(const A<T>&a);

template<typename T>class A{
    T num;
public:
    A(){
        num=T(5.5);
    }
    friend void show<T>(const A<T>&a);
};

template<typename T> void show(const A<T>&a){
    cout<<a.num<<endl;
}

int main(){
    A<int> a;
    show<int>(a);
}

程序正确运行并输出5。

1.3在模板类内部直接声明并定义友元函数

这种情况只能在模板类内部一起把函数的定义写出来,不能在外部实现,因为外部需要类型参数,而需要类型参数就是模板了。其实这种情况相当于一般的模板类的成员函数,也相当于一个函数模板。考察如下代码。

#include <iostream>
using namespace std;

template<typename T>class A{
    T num;
public:
    A(){
        num=T(5.5);
    }
    friend void show(const A<T>&a){
        cout<<a.num<<endl;
    }
};

int main(){
    A<int> a;
    show(a);
    getchar();
}

程序正常编译运行并输出5。当然,将友元函数的定义改为:

template<typename T> void show(const A<T>&a){
    cout<<a.num<<endl;
}

也是完全可以的,如果将函数模板放在类模板外定义的话,和第一种方式相同。由于无论是江友元函数申明为一个使用了模板类的普通函数,还是一个函数模板,由于将友元函数直接定义在类模板体内,所以不会出现申明和定义见的不一致型。


2.把类模板声明为类模板的友元

把类模板声明为类模板的友元可以有两种方式。

2.1在类模板内部对模板类进行友元申明

这里要注意是对实例化后的模板类将其申明为类模板的友元,而不是类模板。因此实例化类模板时,类模板需要前置申明。考察如下程序。

#include <iostream>
using namespace std;

template<typename T>class B; //类模板前置申明

template<typename T>class A{
    T num;
public:
    A(){
        num=T(5.5);
    }
    friend class B<T>;
};

template<typename T>class B{
public:
    static void show(const A<T>& a){
        cout<<"a.num:"<<a.num<<endl;    
    }
};

int main(){
    A<int> a;
    B<int>::show(a);
}

程序正常编译运行并输出:a.num:5。

2.2在类模板内部对类模板进行友元申明

这里要注意是直接将类模板申明为类模板的友元,而不是实例化后的模板咧,要与上面区别对待。这里就不需要将类模板B提前申明了,在类模板A中将B申明为:

template< class T>friend class B;

同样可以将类模板B申明为类模板A的友元。

不过,这两种方式在概念上还是有一些差异。第一种方式,类模板B的实例化依赖于类模板A的参数T。也就是说,对于一个特定的模板类A< t>来说,只有一个B的实例B< t>是它的友元类。而在第二中方式中,对于一个特定的类模板A< t>来说,B的任何实例B< u>都是它的友元类。


参考文献

[1]http://www.cppblog.com/unixfy/archive/2011/05/27/147448.html [2]陈刚.C++高级进阶教程[M].武汉:武汉大学出版社,2008[6.2(P218-P222)]

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java达人

Java虚拟机

1、Java虚拟机是什么 “Java虚拟机“可以指三种不同的东西 抽象规范 一个具体的实现 一个运行中的虚拟机实例 当运行一个Java程序的同时,也就是在运行一...

271100
来自专栏程序员互动联盟

【编程基础第十一讲】代码如何写才最漂亮第一篇

存在问题: 好多小伙伴对编码的格式作用模糊,以为只要完成功能就行,其实这种观点是错误的,一定要重视代码规范,不然你哭的地都找不到。 如何实施: 良好的代码开发习...

27970
来自专栏达摩兵的技术空间

es6入门

es6作为最新的js语言版本,有很多特性是不得不晓的。下面将语法中常用的分析出来,对应到基本对象类型的会在对象里描述。

9520
来自专栏程序员八阿哥

王老板Python面试(10):17道python笔试面试真题

GIL 是python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序的时候会霸占python解释器(加了一把锁即GIL),使该进程...

17320
来自专栏JavaEdge

HotSPot虚拟机对象探秘1 对象的创建过程2 对象的内存布局3 访问对象的过程

398160
来自专栏Golang语言社区

Golang语言的函数调用信息

函数的调用信息是程序中比较重要运行期信息, 在很多场合都会用到(比如调试或日志). Go语言 runtime 包的 runtime.Caller / runti...

57160
来自专栏不止是前端

从实现一个Promise说起

14230
来自专栏java思维导图

HashMap为什么是线程不安全的?

一直以来只是知道HashMap是线程不安全的,但是到底HashMap为什么线程不安全,多线程并发的时候在什么情况下可能出现问题?

24420
来自专栏遊俠扎彪

C语言C99标准中的变长数组(VLA)

长期以来,我都很自然的认为定义和声明数组时,数组大小必须是一个常量表达式,因为刚学编程的时候在这个上面翻过好多次语法错误。那个时候大致会写如下的代码:

44890
来自专栏不止是前端

从实现一个Promise说起

尽管工作中用了无数次Promise async await,但是在写下这篇文章之前,却不知道Promise背后发生了些什么,我一直以为的逻辑是先等待Promis...

17740

扫码关注云+社区

领取腾讯云代金券