C++ Primer Plus 书之--C++ 模板类深究2--模板类和友元

2023-11-19

模板类和友元

模板类声明也可以有友元, 模板的友元分为3类:

1.非模板友元

2.约束模板友元, 即友元的类型取决于类被实例化时的类型

3.非约束模板友元, 即友元的所有具体化都是类的每一个具体化的友元.

1.模板类的非模板友元函数:

在模板类中将一个常规函数声明为友元:

template <class T>
class HasFriend
{
public:
	friend void counts();
};

上述声明使counts()函数称为模板所有实例化的友元. 例如: 它将是类HasFriend<int>和HasFriend<string>的友元.

counts()函数不是通过对象调用的(它是友元, 不是成员函数)

假设要为友元函数提供模板类参数, 看如下的声明:

friend void report(HasFriend &);

这个声明是错误的, 因为不存在HasFriend这样的对象, 而只有特定的具体化如:HasFriend<short>, HasFriend<int>, 要提供模板类参数, 必须知名具体化, 例如可以这么写:

template<class T>
class HasFriend
{
	friend void report(HasFriend<T> &);
};

注意report()本身并不是模板函数, 而只是使用了一个模板作为参数

来看一个完整的例子:

// 模板类的非模板友元函数例子
// frnd2tmp.cpp
#include <iostream>
using std::cout;
using std::endl;

template<typename T>
class HasFriend
{
private:
	T item;
	// 静态成员, 意味着每个类的特定具体化都将有自己的静态成员.
	static int ct;
public:
	HasFriend(const T & i): item(i) {ct++;}
	~HasFriend() {ct--;}
	friend void counts();
	friend void reports(HasFriend<T> &);
};

template<typename T>
int HasFriend<T>::ct = 0;

// 非模板友元函数, 所有HasFriend<T>都有该函数
void counts()
{
	cout << "int count: " << HasFriend<int>::ct << "; ";
	cout << "double count: " << HasFriend<double>::ct << endl;
}

// 非模板友元函数, 对应于HasFriend<int> class
void reports(HasFriend<int> & hf)
{
	cout << "HasFriend<int>: " << hf.item << endl;
}

// 非模板友元函数, 对应于HasFriend<double> class
void reports(HasFriend<double> & hf)
{
	cout << "HasFriend<double>: " << hf.item << endl;
}

int main()
{
	cout << "No objects declared: ";
	counts();
	HasFriend<int> hfi1(10);
	cout << "After hfi1 declared: ";
	counts();
	HasFriend<int> hfi2(20);
	cout << "After hfi2 declared: ";
	counts();
	HasFriend<double> hfi3(10.1);
	cout << "After hfi3 declared: ";
	counts();
	reports(hfi1);
	reports(hfi2);
	reports(hfi3);
	return 0;
}

程序运行结果为:

需要注意的地方都写注释了

 

2.模板类的约束模板友元函数

在上面这个示例基础上加以修改, 要使类的每一个具体化都获得与友元匹配的具体化, 需要以下三步:

1.在类定义的前面声明每个模板函数:

template<typename T> void counts();
template<typename T> void report(T &);

2.在函数中再次将模板声明为友元. 这些语句根据类模板参数的类型声明具体化:

template <typename TT>
class HasFriendT
{
...
	friend void counts<TT>();
	friend void report<>(HasFriendT<TT> &);
};

声明中的<>指出这是模板具体化, 对于report(), <>可以为空, 因为可以从函数参数推断出如下模板类型参数:

HasFriendT<TT>

然而也可以使用:

friend void report<HasFriendT<TT>>(HasFriendT<TT> &);

但counts()函数没有参数, 因此必须使用模板参数语法<TT>来指明其具体化.

3.为友元提供模板定义.

下面看一个完整的例子:

// 模板类的约束模板友元函数
// tmp2tmp.cpp
#include <iostream>
using std::cout;
using std::endl;

// 在类定义前面要声明每个模板函数原型
template<typename T> void counts();
template<typename T> void report(T &);

// 模板类
template<typename TT>
class HasFriendT
{
private:
	TT item;
	// 静态成员, 每个类的具体化都会有自己的静态成员
	static int ct;
public:
	HasFriendT(const TT & i):item(i){ct++;}
	~HasFriendT() {ct--;}
	friend void counts<TT>();
	friend void report<>(HasFriendT<TT> &);
};


template<typename TT>
// 记得这里一定要写成HasFriendT<TT>, 不能只写HasFriendT, 因为不存在HasFriendT这个类
int HasFriendT<TT>::ct = 0;

// 模板友元函数定义
template <typename T>
void counts()
{
	cout << "template size: " << sizeof(HasFriendT<T>) << ";";
	cout << "template counts() : " << HasFriendT<T>::ct << endl;
}

template<typename T>
void report(T & hf)
{
	cout << hf.item << endl;
}

int main()
{
	counts<int>();
	HasFriendT<int> hf1(10);
	HasFriendT<int> hf2(20);
	HasFriendT<double> hf3(10.1);
	report(hf1);
	report(hf2);
	report(hf3);
	cout << "counts<int> output: " << endl;
	counts<int>();
	cout << "counts<double>() output: " <<endl;
	counts<double>();
	return 0;
}

程序运行结果为:

3.模板类的非约束模板友元函数

约束模板友元函数是在类外面声明的模板的具体化, int类具体化获得int函数具体化, 以此类推. 通过在类内部声明模板, 可以创建非约束友元函数, 即每个函数具体化都是每个类具体化的友元. 对于非约束友元, 友元模板类型参数和模板类类型参数是不同的:

template<typename T>
class ManyFriend
{
	template<typename C, typename D> friend void show2(C &, D &);
}

来看一个demo:

// 非约束模板友元
// manyfrnd.cpp
#include <iostream>
using std::cout;
using std::endl;

template<typename T>
class ManyFriend
{
private:
	T item;
public:
	ManyFriend(const T & i): item(i){}
	// 非约束模板友元
	template<typename C, typename D> friend void show2(C &, D &);
};

template<typename C, typename D> void show2(C & c, D & d)
{
	cout << c.item << ", " << d.item << endl;
}

int main()
{
	ManyFriend<int> hf1(10);
	ManyFriend<int> hf2(20);
	ManyFriend<double> hf3(10.1);
	cout << "hf1, hf2: ";
	show2(hf1, hf2);
	cout << "hf3, hf2: ";
	show2(hf3, hf2);
	return 0;
}

程序运行结果为:

 

模板别名

可以使用typedef为模板具体化指定别名:

格式如下:

template<typename T> using arrtype = std::array<T, 12>;

这将arrtype定义为一个模板别名, 可使用其来指定类型例如:

// 实际为std::array<double, 12>这种类型
arrtype<double> gallons;

// 实际为std::array<int, 12>这种类型
arrtype<int> days;

// 实际为std::array<std::string, 12>这种类型
arrtype<std::string> months;

C++允许将语法using = 用于非模板, 用于模板时, 这种语法与常规typedef等价

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ Primer Plus 书之--C++ 模板类深究2--模板类和友元 的相关文章

  • 是否有与 posix_memalign 对应的 C++ 版本?

    当我打电话时posix memalign http man7 org linux man pages man3 posix memalign 3 html为类型的对象分配对齐的内存Foo在我的 C 代码中 我需要做一个reinterpret
  • 计算 XML 中特定 XML 节点的数量

    请参阅此 XML
  • GetType() 在 Type 实例上返回什么?

    我在一些调试过程中遇到了这段代码 private bool HasBaseType Type type out Type baseType Type originalType type GetType baseType GetBaseTyp
  • ComboBox DataBinding 导致 ArgumentException

    我的几个类对象 class Person public string Name get set public string Sex get set public int Age get set public override string
  • 如何在C(Linux)中的while循环中准确地睡眠?

    在 C 代码 Linux 操作系统 中 我需要在 while 循环内准确地休眠 比如说 10000 微秒 1000 次 我尝试过usleep nanosleep select pselect和其他一些方法 但没有成功 一旦大约 50 次 它
  • 查找进程的完整路径

    我已经编写了 C 控制台应用程序 当我启动应用程序时 不使用cmd 我可以看到它列在任务管理器的进程列表中 现在我需要编写另一个应用程序 在其中我需要查找以前的应用程序是否正在运行 我知道应用程序名称和路径 所以我已将管理对象搜索器查询写入
  • Visual Studio 在构建后显示假错误

    我使用的是 Visual Studio 2017 构建后 sln在调试模式下 我收到错误 但是 当我通过双击错误列表选项卡中的错误来访问错误时 错误会从页面中消失 并且错误数量也会减少 我不太确定这种行为以及为什么会发生这种情况 有超过 2
  • 从客户端访问 DomainService 中的自定义对象

    我正在使用域服务从 Silverlight 客户端的数据库中获取数据 在DomainService1 cs中 我添加了以下内容 EnableClientAccess public class Product public int produ
  • 使用可变参数包类型扩展的 C++ 函数调用者包装器

    我绑定了一些 API 并且绑定了一些函数签名 如下所示 static bool WrapperFunction JSContext cx unsigned argc JS Value vp 我尝试将对象和函数包装在 SpiderMonkey
  • 将 Long 转换为 DateTime 从 C# 日期到 Java 日期

    我一直尝试用Java读取二进制文件 而二进制文件是用C 编写的 其中一些数据包含日期时间数据 当 DateTime 数据写入文件 以二进制形式 时 它使用DateTime ToBinary on C 为了读取 DateTime 数据 它将首
  • 打破 ReadFile() 阻塞 - 命名管道 (Windows API)

    为了简化 这是一种命名管道服务器正在等待命名管道客户端写入管道的情况 使用 WriteFile 阻塞的 Windows API 是 ReadFile 服务器已创建启用阻塞的同步管道 无重叠 I O 客户端已连接 现在服务器正在等待一些数据
  • 如何在 C 中安全地声明 16 位字符串文字?

    我知道已经有一个标准方法 前缀为L wchar t test literal L Test 问题是wchar t不保证是16位 但是对于我的项目 我需要16位wchar t 我还想避免通过的要求 fshort wchar 那么 C 不是 C
  • 为什么我的单选按钮不起作用?

    我正在 Visual C 2005 中开发 MFC 对话框应用程序 我的单选按钮是 m Small m Medium 和 m Large 它们都没有在我的 m Summary 编辑框中显示应有的内容 可能出什么问题了 这是我的代码 Pizz
  • 等待 IAsyncResult 函数直至完成

    我需要创建等待 IAsyncResult 方法完成的机制 我怎样才能做到这一点 IAsyncResult result contactGroupServices BeginDeleteContact contactToRemove Uri
  • 使 Guid 属性成为线程安全的

    我的一个类有一个 Guid 类型的属性 该属性可以由多个线程同时读写 我的印象是对 Guid 的读取和写入不是原子的 因此我应该锁定它们 我选择这样做 public Guid TestKey get lock testKeyLock ret
  • Unity:通过拦截将两个接口注册为一个单例

    我有一个实现两个接口的类 我想对该类的方法应用拦截 我正在遵循中的建议Unity 将两个接口注册为一个单例 https stackoverflow com questions 1394650 unity register two inter
  • C++ new * char 不为空

    我有一个问题 我在 ASIO 中开发服务器 数据包采用尖头字符 当我创建新字符时 例如char buffer new char 128 我必须手动将其清理为空 By for int i 0 i lt 128 i buffer i 0x00
  • 在 Windows Phone silverlight 8.1 上接收 WNS 推送通知

    我有 Windows Phone 8 1 silverlight 应用程序 我想使用新框架 WNS 接收通知 我在 package appxmanifest 中有
  • GCC 的“-Wl,option”和“-Xlinker option”语法之间有区别吗?

    我一直在查看一些配置文件 并且看到它们都被使用 尽管在不同的体系结构上 如果您在 Linux 机器上使用 GCC 将选项传递给链接器的两种语法之间有区别吗 据我所知 阅读 GCC 手册时 他们的解释几乎相同 From man gcc Xli
  • 为boost python编译的.so找不到模块

    我正在尝试将 C 代码包装到 python 中 只需一个类即可导出两个函数 我编译为map so 当我尝试时import map得到像噪音一样的错误 Traceback most recent call last File

随机推荐

  • 【Random库】

    文章目录 random库概述 random库解析 random库概述 随机数在计算机应用中十分常见 Python内置的random库主要用于产生各种分布的伪随机数序列 random库采用梅森旋转算法 Mersenne twister 生成伪
  • 电脑出现msvcp120.dll丢失的解决方法,教你三招快速解决

    msvcp120 dll丢失是一件很常见的问题 出现msvcp120 dll丢失会导致电脑无法在正常运行 那么应该怎么解决这个问题呢 有什么办法可以快速的解决呢 今天教你三招快速解决msvcp120 dll丢失的方法 一 msvcp120
  • 时序预测

    时序预测 MATLAB实现CNN SVM卷积支持向量机时间序列预测 目录 时序预测 MATLAB实现CNN SVM卷积支持向量机时间序列预测 预测效果 基本介绍 研究回顾 程序设计 参考资料 预测效果 基本介绍 CNN SVM预测模型将深度
  • iphone投屏ipad_教你手机投屏电脑

    最近有很多小伙伴一直留言需要投屏软件 今天果子就来讲解一下关于投屏的问题 如果大家家里或者身边有类似天猫盒子这种的设备都是可以直接利用苹果自带的投屏服务AirPlay 屏幕镜像 进行投屏至电视 而我们的电脑分为USB投屏和无线投屏 WIN1
  • Android获取手机信号强度汇总

    雪里香梅 先报春来早 宋 欧阳修 蝶恋花 如今的天气是越来略冷了 每每走在凛冽的寒风中 心里就一个想法 春 假 天 期 怎么还不到 不知道大家有没有同感 前两天要做一个获取手机信号的小程序 于是在网上搜索了很多 就找到两种方法 遗憾的是都没
  • 【编译】gcc make cmake Makefile CMakeList.txt 关系、使用

    文章目录 一 关系 二 gcc 2 1 编译过程 2 2 编译参数 2 3 静态库和动态库 1 后缀名 2 联系与区别 2 4 GDB 调试器 1 常用命令 三 make makefile 四 cmake cmakelist 4 1 语法特
  • Android常用的加密算法

    一 MD5 MD5可以说是最基本最常用的加密算法了 还依稀记得在校招面试的时候被问到过 MD5信息摘要算法 MD5 Message Digest Algorithm 算法能将任意大小 格式的文字或文件进行加密从而产生 128 bit 16
  • 提高企业开发效率的优质工具:快速开发平台

    现代企业管理软件的功能越来越复杂 随着新技术作为管理手段不断被引入到管理软件中 使得管理软件的开发的难度在逐年的增加 尤其是企业需要的很多的功能都是个性化的 这让企业管理软件的开发少则半年 多则1年以上 而且失败率非常高 即使采用敏捷开发方
  • 使用 django-bootstrap3 库

    使用 django bootstrap3 库 1 配置 下载 pip install django bootstrap3 settings配置 在install apps中加上 bootstrap3 2 使用 在html文件中使用 表单 写
  • 如何的keil试试调试中,看逻辑分析仪Logic viwer

    在调试过程中 可以使用keil自带的逻辑分析仪查看变量的试试信息 减少串口输出 提高部分cpu的效率 可以添加以下信息 1 gpio引脚 2 全局变量 全局静态变量 局部变量是不行的 然后 添加变量后 需要右键设置 如下 g u32tick
  • el-table表格可拖拽实现

    druggerTable js function global factory global BmTableDrag factory global window function global function BmTableDrag op
  • win10系统镜像下载及在VMware虚拟机上创建win10虚拟机

    文章目录 前言 一 下载win10系统 二 配置win10系统虚拟机 创建新的虚拟机 注意事项 前言 网上很多win10镜像资源都没法用 不是下载不了 就是用不了 尤其公众号还有一堆套路 浪费自己很多时间 无奈 干脆自己做一个镜像 肯定好用
  • 【华为OD机试】数字游戏(C++ Python Java)2023 B卷

    时间限制 C C 1秒 其他语言 2秒 空间限制 C C 262144K 其他语言524288K 64bit IO Format lld 题目描述 小明玩一个游戏 系统发1 n张牌 每张牌上有一个整数 第一张给小明 后n张按照发牌顺序排成连
  • 数字化转型系列主题:数字化建设总体规划蓝图

    本文转自 CIO之家 数字化转型应该是千人千面 因为每家企业的难点痛点不一样 所以每家企业的转型路径都不尽相同 数字化转型不是为了转型而转型 必须是围绕解决企业最大痛点 以它做切入点 回报才最快 投入产出比才最高 所以常想 数字化转型第一件
  • 于仕琪的人脸检测算法

    于仕琪的人脸检测算法 对Windows下的商业使用也免费 刚更新了一次算法 正面人脸检测的角度范围从 40 40 度提升到 60 60 度 检测角度变大但计算量不增加 多视角人脸检测速度提升2倍 速度对比 在同样的条件下OpenCV 47
  • // 计算出给定矩阵中主对角线元素的和

    一 题目 计算出给定矩阵中主对角线元素的和 二 代码 include
  • 数据结构与算法学习总结(六)——字符串的模式匹配算法

    基本概念 字符串是一种特殊的线性表 即元素都是 字符 的线性表 字符是组成字符串的基本单位 字符的取值依赖于字符集 例如二进制的字符集为0 1 则取值只能为 0 1 再比如英语语言 则包括26个字母外加标点符号 例如 abcde 就是一个字
  • python遍历指定目录并打印层级结构

    import os def func filepath n 获取路径 files os listdir filepath for file in files 拼接路径 f d os path join filepath file 判断路径是
  • STM32CubeMX安装与使用

    STM32CubeMX 是 ST 公司近几年来大力推荐的STM32 芯片图形化配置工具 允许用户使用图形化向导生成C 初始化代码 支持多种工具链 比如MDK IAR TrueStudio等 可以大大减轻开发工作时间 提高开发效率 STM32
  • C++ Primer Plus 书之--C++ 模板类深究2--模板类和友元

    模板类和友元 模板类声明也可以有友元 模板的友元分为3类 1 非模板友元 2 约束模板友元 即友元的类型取决于类被实例化时的类型 3 非约束模板友元 即友元的所有具体化都是类的每一个具体化的友元 1 模板类的非模板友元函数 在模板类中将一个