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--模板类和友元 的相关文章

  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • 嵌套接口:将 IDictionary> 转换为 IDictionary>?

    我认为投射一个相当简单IDictionary
  • 类模板参数推导 - clang 和 gcc 不同

    下面的代码使用 gcc 编译 但不使用 clang 编译 https godbolt org z ttqGuL template
  • HTTPWebResponse 响应字符串被截断

    应用程序正在与 REST 服务通信 Fiddler 显示作为 Apps 响应传入的完整良好 XML 响应 该应用程序位于法属波利尼西亚 在新西兰也有一个相同的副本 因此主要嫌疑人似乎在编码 但我们已经检查过 但空手而归 查看流读取器的输出字
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • while 循环中的 scanf

    在这段代码中 scanf只工作一次 我究竟做错了什么 include
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 如何使用 C# / .Net 将文件列表从 AWS S3 下载到我的设备?

    我希望下载存储在 S3 中的多个图像 但目前如果我只能下载一个就足够了 我有对象路径的信息 当我运行以下代码时 出现此错误 遇到错误 消息 读取对象时 访问被拒绝 我首先做一个亚马逊S3客户端基于我的密钥和访问配置的对象连接到服务器 然后创
  • 为什么编译时浮点计算可能不会得到与运行时计算相同的结果?

    In the speaker mentioned Compile time floating point calculations might not have the same results as runtime calculation
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 测试用例执行完成后,无论是否通过,如何将测试用例结果保存在变量中?

    我正在使用 NUNIT 在 Visual Studio 中使用 Selenium WebDriver 测试用例的代码是 我想在执行测试用例后立即在变量中记录测试用例通过或失败的情况 我怎样才能实现这一点 NUnit 假设您使用 NUnit
  • IEnumreable 动态和 lambda

    我想在 a 上使用 lambda 表达式IEnumerable
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定
  • 如何将服务器服务连接到 Dynamics Online

    我正在修改内部管理应用程序以连接到我们的在线托管 Dynamics 2016 实例 根据一些在线教程 我一直在使用OrganizationServiceProxy out of Microsoft Xrm Sdk Client来自 SDK
  • 如何防止用户控件表单在 C# 中处理键盘输入(箭头键)

    我的用户控件包含其他可以选择的控件 我想实现使用箭头键导航子控件的方法 问题是家长控制拦截箭头键并使用它来滚动其视图什么是我想避免的事情 我想自己解决控制内容的导航问题 我如何控制由箭头键引起的标准行为 提前致谢 MTH 这通常是通过重写

随机推荐

  • 【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 模板类的非模板友元函数 在模板类中将一个