跟我学C++中级篇——模板友元的应用
一、友元
友元在以前分析过,而且一般编程是不推荐使用友元的,原因是友元破坏了类的封装性。但凡事总有例外,在某些情况下,用友元还是比较方便的,那么该用还得用,不能因噎废食。普通的友元,各种书籍资料和网上多得很。一般来说,可以把友元分为两大类:
1、普通的友元
这种友元的使用,不管是类还是函数,开发者都相对比较熟悉,此处就不再赘述,如果有不明白的可以 翻一下书籍。一般来说,即使在模板里,使用特化的或者实例化的模板类或者函数,也看做是普通友元。模板只要特化或者说实例化就和普通类或者函数没有什么区别了。
2、模板的友元
这里重点分析一下模板中使用模板函数或者模板类做为友元时的处理情况,这里面涉及到一些具体的编译器的不同处理方式,需要引起重视。
二、模板函数做为友元
老规矩行先看代码:
#include <iostream>//第一种情况
template <typename T> class FriendF {
public:T t_;public:FriendF() { t_ = T(1.9); }// VS OK// template <typename T> friend void Display(const FriendF<T> &f);template <typename U> friend void Display(const FriendF<U> &f);
};template <typename U> void Display(const FriendF<U> &f) {std::cout << "cur value is:" << f.t_ << std::endl;
}int friendtest() {FriendF<int> f;Display<int>(f);return 0;
}
//
//第二种情况
template <typename T> class FriendF1;
template <typename T> void Display(const FriendF1<T> &a);template <typename T> class FriendF1 {T t_;public:FriendF1() { t_ = T(1.6); }friend void Display<T>(const FriendF1<T> &f);
};template <typename T> void Display(const FriendF1<T> &f) {std::cout << "cur value is:" << f.t_ << std::endl;
}int friendtest1() {FriendF1<int> f1;Display<int>(f1);return 0;
}
///
//第三种情况template <typename T> class FriendF2 {T t_;public:FriendF2() { t_ = T(2.0f); }friend void Display(const FriendF2<T> &f2) {std::cout << f2.t_ << std::endl;}
};int friendtest2() {FriendF2<int> f2;Display(f2);return 0;
}///
//第四种情况
template <typename T> class NData;
template <typename T> void swap1(NData<T> &n1, NData<T> &n2);
template <typename T> void Display1(NData<T> &n1, NData<T> &n2);
template <typename T> void swap(NData<T> &n1, NData<T> &n2);template <typename T> class NData {
public:NData() {}NData(T t) : t_(t) {}public:NData<T> *left_;NData<T> *right_;T t_;public:friend void swap1<>(NData<T> &, NData<T> &);friend void swap<>(NData<T> &, NData<T> &);friend void Display1<>(NData<T> &, NData<T> &);
};
template <typename T> void Display1(NData<T> &n1, NData<T> &n2) {std::cout << n1.t_ << std::endl;
}
template <typename T> void swap1(NData<T> &n1, NData<T> &n2) {std::swap(n1.left_, n2.left_);std::swap(n1.right_, n2.right_);std::swap(n1.t_, n2.t_);std::cout << "vlaue is:" << n1.t_ << std::endl;
}
template <typename T> void swap(NData<T> &n1, NData<T> &n2) {// // std::swap(n1.left_, n2.left_);// // std::swap(n1.right_, n2.right_);// std::swap(n1.t_, n2.t_);std::cout << "n1,b" << n1.t_ << std::endl;
}int friendtest3() {NData<int> nd1;NData<int> nd2;swap(nd1, nd2);swap1(nd1, nd2);Display1(nd1, nd2);return 0;
}
int main()
{friendtest();friendtest1();friendtest2();friendtest3();
}
在模板函数做为友元的情况下,分成了三种情况两大类:
1、模板类内声明,模板外实现
第一种情况就是这种,在类声明了模板函数为友元,但是在类外实现函数体。
2、模板类内声明,类内实现
第三种就是在类内直接实现模板函数友元的函数体。
3、模板类外声明
第二种情况就是把友元模板函数在类外进行声明,有点类似于头文件的作用,然后在类中声明友元,类外进行函数体的实现。第四种情况中,其实和第二种情况基本没有区别。只是用<>来表明这是一种模板函数的具现化。
*这里需要说明一下"friend void swap1<>(NData &, NData &)"这种<>尖括号声明,用侯捷老师的书中的原话是“使用空的template argument list,这种形式告诉编译器,只从template具现体中挑选合适的呼叫对象,所有template parameters 都自 call parameters 推导而得”。所以才在下面说第四种情况视情况而定的原因。
其实它的意思就是说,这个是要从具体的调用参数推导出来。也就是说,常规的函数是允许参数自动类型转换,但模板参数推断时不允许,这就等于在实际推导时要根据已经生成的挑选(推导)最匹配的。
两大类是从另外一种角度看:
1、可以直接在类内声明限定约束(bound)模板友元的参数类型
也就是说,友元模板参数要和应用 其类的模板参数保持一致。第一种情况的注释版第二种及第三种情况都是约束的情况。这种也容易为开发者理解和应用。
2、模板未对友元模板进行约束(unbound)
这种情况就是第一种情况,第一种情况注释的部分在vs上可以 编译应用 ,但在Gcc和Clang上编译会出现“Declaration of ‘T’ shadows template parameter”,这个在前面也分析过(“模板的模板参数的匹配”)。
第四种情况视情况而定吧。
三、模板类做为友元
而模板类做为友元可以 分为两种情况:
//第一种情况
template <typename T> class FriendB;template <typename T> class FriendA {
public:T t_;public:FriendA() { t_ = T(3.6); }friend class FriendB<T>;
};
//第二种情况
template <typename T> class FriendAA {
public:T t_;public:FriendAA() { t_ = T(100); }template <class U> friend class FriendBB;
};
template <typename U> class FriendBB {
public:static void Display(const FriendAA<U> &faa) {std::cout << "cur value is:" << faa.t_ << std::endl;}
};
template <typename T> class FriendB {
public:static void Display(const FriendA<T> &fa) {std::cout << "cur value is::" << fa.t_ << std::endl;}
};int friendclass() {FriendA<int> aa1;FriendAA<double> aa2;FriendB<int>::Display(aa1);FriendBB<double>::Display(aa2);return 0;
}
int main()
{
friendclass();
}
它们两种情况都是在类声明为友元,但是第一种情况中在前声明友元前进行了友元模板类的前向声明;第二种情况则直接在类内声明。前者更类似于一种实例化的类,在前面的学习中知道,在模板类中,声明的模板形参可以在内部认为已经实例化,直接使用。而第二种则和前面函数模板类似,属于不受约束的方式,是一种声明形式。
也就是说,第一种是码元模板参数受约束的形式,而第二种则为不受约束的形式。
四、问题
在这次的例程编写中,遇到了一个基础问题,觉得对初学者甚至中等水平开发者还是有一定意义的,这里展示出来。
......template <typename T> class NData {
public:NData() {}NData(T t) : t_(t) {}public:NData<T> *left_;NData<T> *right_;T t_;public:friend void swap1<>(NData<T> &, NData<T> &);friend void swap<>(NData<T> &, NData<T> &);
......
};template <typename T> void swap1(NData<T> &n1, NData<T> &n2) {std::swap(n1.left_, n2.left_);std::swap(n1.right_, n2.right_);std::swap(n1.t_, n2.t_);std::cout << "vlaue is:" << n1.t_ << std::endl;
}
template <typename T> void swap(NData<T> &n1, NData<T> &n2) {// // std::swap(n1.left_, n2.left_);// // std::swap(n1.right_, n2.right_);// std::swap(n1.t_, n2.t_);std::cout << "n1,b" << n1.t_ << std::endl;
}
也就是函数模板做为友元的第四种情况中,使用swap做函数名时,总是报"assertion failed: template argument must be a complete class or an unbounded array"。有点摸不着头脑,类NData是一个完全定义好的啊。后来突然想到会不会是名空间污染的问题(std::swap())。于是又写了一个swap1,结果没问题。验证与想的完全一致,回头查看一下代码,在工程中被包含的cpp文件中声明了using namespae std,所以在实际工程中,尽量增加自定义的名字空间,并且不要使用类似“using namespae std”这种偷懒的方式来编程。
五、总结
C++语言更需要多实践,多干活自然就会有各种情况遇到,和所学的知识不断的验证、巩固。查遗补缺,技术的增长就会越来越快,光死记理论,时间长了要么忘记了,要么记混了,写起代码来还是有无法驾驭的情况。
相关文章:
跟我学C++中级篇——模板友元的应用
一、友元 友元在以前分析过,而且一般编程是不推荐使用友元的,原因是友元破坏了类的封装性。但凡事总有例外,在某些情况下,用友元还是比较方便的,那么该用还得用,不能因噎废食。普通的友元,各种…...
软件测试基础篇——MySQL
MySQL 1、数据库技术概述 数据库database:存放和管理各种数据的仓库,操作的对象主要是【数据data】,科学的组织和存储数据,高效的获取和处理数据SQL:结构化查询语言,专为**关系型数据库而建立的操作语言&…...
FreeRTOS(二值信号量)
资料来源于硬件家园:资料汇总 - FreeRTOS实时操作系统课程(多任务管理) 目录 一、信号量的概念 1、信号量的基本概念 2、信号量的分类 二、二值信号量的定义与应用 1、二值信号量的定义 2、二值信号量的应用 三、二值信号量的运作机制 1、FreeRTOS任务间二值…...
leetcode面试题:动物收容所(考查对队列的理解和运用)
题目: 有家动物收容所只收容狗与猫,且严格遵守“先进先出”的原则。在收养该收容所的动物时,收养人只能收养所有动物中“最老”(由其进入收容所的时间长短而定)的动物,或者可以挑选猫或狗(同时…...
【Linux命令行与Shell脚本编程】第十八章 文本处理与编辑器基础
Linux命令行与Shell脚本编程 第十八章 文本处理与编辑器基础 文章目录 Linux命令行与Shell脚本编程第十八章 文本处理与编辑器基础 文本处理与编辑器基础8.1.文本处理8.1.1.sed编辑器8.1.1.1.在命令行中定义编辑器命令8.1.1.2.在命令行中使用多个编辑器命令8.1.1.3.从文件中读…...
2023牛客暑期多校训练营7
Beautiful Sequence 贪心,二进制,构造 Cyperation 模拟 ,数学 We Love Strings 分块,二进制枚举,二进制容斥dp Writing Books 签到 根据相邻两个异或值B,因为前小于等于后,故从高到低遍历B的每一…...
centos7升级glibc2.28
1 概述 centos7自带的glibc对于某些软件是太旧的,决定将glibc升级至2.28。 2 安装过程 2.1 下载glibc源码 mkdir -p /opt/third-party && cd /opt/third-party wget http://ftp.gnu.org/gnu/glibc/glibc-2.28.tar.gz tar -xf glibc-2.28.tar.gz cd glibc…...
腾讯云香港服务器租用_2核2G20M_2核4G30M
腾讯云香港服务器租用费用表,目前中国香港地域轻量应用服务器可选配置2核2G20M、2核2G30M、2核4G30M,操作系统可选Windows和Linux,不只是香港云服务器,新加坡、硅谷、法兰克福和东京服务器均有活动,腾讯云服务器网分享…...
十三、ESP32PS2摇杆(ADC)
1. 运行效果 在上下左右操作PS2摇杆的时候,会检测到数据 2. 滑动电阻...
网络安全的相关知识点
网络安全威胁类型: 1.窃听:广播式网络系统。 2.假冒 3.重放:重复一份报文或者报文的一部分,以便产生一个被授权的效果。 4.流量分析 5.数据完整性破坏 6.拒绝服务 7.资源的非授权使用 8.陷门和特洛伊木马:木马病毒有客…...
算法练习(6):牛客在线编程06 递归/回溯
package jz.bm;import java.io.PushbackInputStream; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays;public class bm6 {/*** BM55 没有重复项数字的全排列*/ArrayList<ArrayList<Integer>> res new ArrayList<>()…...
C#使用OpenCv(OpenCVSharp)图像局部二值化处理实例
本文实例演示C#语言中如何使用OpenCv(OpenCVSharp)对图像进行局部二值化处理。 目录 图像二值化原理 局部二值化 自适应阈值 实例 效果...
MySQL多表关联查询
目录 1. inner join: 2. left join: 3. right join: 4.自连接 5.交叉连接: 6、联合查询 7、子查询 1. inner join: 代表选择的是两个表的交差部分。 内连接就是表间的主键与外键相连,只取得键值一致…...
flutter开发实战-CustomClipper裁剪长图帧动画效果
flutter开发实战-CustomClipper裁剪长图帧动画效果 在开发过程中,经常遇到帧动画的每一帧图显示在超长图上,需要处理这种帧动画效果。我这里使用的是CustomClipper 一、CustomClipper CustomClipper继承于Listenable abstract class CustomClipper e…...
CSS 中的优先级规则是怎样的?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐内联样式(Inline Styles)⭐ID 选择器(ID Selectors)⭐类选择器、属性选择器和伪类选择器(Class, Attribute, and Pseudo-class Selectors)⭐元素选择器和伪元素选择器…...
概率图模型(Probabilistic Graphical Model,PGM)
概率图模型(Probabilistic Graphical Model,PGM),是一种用图结构来描述多元随机变量之间条件独立性的概率模型。它可以用来表示复杂的概率分布,进行有效的推理和学习,以及解决各种实际问题,如图…...
Oracle 知识篇+会话级全局临时表在不同连接模式中的表现
标签:会话级临时表、全局临时表、幻读释义:Oracle 全局临时表又叫GTT ★ 结论 ✔ 专用服务器模式:不同应用会话只能访问自己的数据 ✔ 共享服务器模式:不同应用会话只能访问自己的数据 ✔ 数据库驻留连接池模式:不同应…...
MySQL 数据库文件的导入导出
目录 数据库的导出 导出整个数据库 导出数据库中的数据表 导出数据库结构 导出数据库中表的表结构 导出多个数据库 导出所有数据库 数据库的导入 数据库的导出 mysqldump -h IP地址 -P 端口 -u 用户名 -p 数据库名 > 导出的文件名 用管理员权限打开cmd进入MySQL的bi…...
找不到资产文件project.assets.json
NuGet 在“obj”文件夹中写入名为 project.assets.json 的文件,.NET SDK 使用该文件来获取有关要传递到编译器的包的信息 。 如果在生成过程中找不到资产文件 project.assets.json,则会发生此错误。 1.执行命令的方式解决 点击工具,分别展开命…...
【python】python将json字符串导出excel | pandas处理json字符串保存为csv
如何将json转为csv 1、通过json直接转为csv 在Python中,你可以使用pandas库来处理DataFrame(数据帧)和将JSON数据转换为CSV格式。下面是一个简单的示例代码,展示了如何使用pandas库将JSON数据转换为CSV文件: import p…...
PyTorch模型调参踩坑实录:nn.Parameter、nn.Linear与nn.functional到底该怎么选?附性能对比
PyTorch模型调参实战:nn.Parameter、nn.Linear与函数式API的工程化选择指南 当你第一次在PyTorch中构建神经网络时,面对nn.Linear、nn.functional.linear和nn.Parameter这些看似相似却各有特点的组件,是否感到选择困难?这就像站在…...
告别玄学调试:用逻辑分析仪抓取STM32与MLX90614的SMBus波形,精准排查通信故障
STM32与MLX90614通信故障排查实战:逻辑分析仪波形诊断指南 当你的红外测温项目突然返回0℃或异常数据时,那种挫败感就像在黑暗中摸索开关。本文将以一个真实案例为线索,带你用逻辑分析仪揭开SMBus通信故障的真相——不是靠猜测,而…...
QMCDecode终极指南:如何轻松解锁QQ音乐加密文件
QMCDecode终极指南:如何轻松解锁QQ音乐加密文件 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac,qmc0,qmc3转mp3, mflac,mflac0等转flac),仅支持macOS,可自动识别到QQ音乐下载目录,默认转换结果…...
AI建站工具选型指南:五大模式横向对比与筛选标准
面对“AI建站工具”这个概念,很多人感到困惑:有的号称AI,但只是帮你改改文案;有的则能通过对话直接生成整个网站。到底哪些才是真正适合你的?本篇指南将先帮你建立一套客观的筛选标准,再用对比表格拆解五种…...
别再用STM32硬刚了!聊聊APM飞控那块神奇的8位单片机(ArduPilot Copter固件初探)
别再用STM32硬刚了!聊聊APM飞控那块神奇的8位单片机 在嵌入式开发领域,我们常常陷入一种思维定式——认为性能更强的32位MCU才是复杂应用的唯一选择。但APM飞控却用一块8位单片机颠覆了这个认知,它不仅稳定驱动着全球数以万计的无人机&#x…...
抖音下载器完整指南:从单视频到批量下载的高效解决方案
抖音下载器完整指南:从单视频到批量下载的高效解决方案 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback supp…...
如何在 WordPress AMP 站点中为特定模板禁用 AMP 渲染
本文介绍两种可靠方法,让 wordpress 官方 amp 插件跳过指定页面模板的 amp 转换,确保该模板始终以标准 html 模式加载,同时保持其余站点完全 amp 兼容。 本文介绍两种可靠方法,让 wordpress 官方 amp 插件跳过指定页面模板的…...
如何高效备份QQ空间历史说说的完整指南
如何高效备份QQ空间历史说说的完整指南 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 在数字信息时代,个人数据的安全备份变得日益重要。GetQzonehistory作为一款开源工具&…...
Mermaid Live Editor:实时可视化图表编辑的终极解决方案
Mermaid Live Editor:实时可视化图表编辑的终极解决方案 【免费下载链接】mermaid-live-editor Edit, preview and share mermaid charts/diagrams. New implementation of the live editor. 项目地址: https://gitcode.com/GitHub_Trending/me/mermaid-live-edit…...
ms-swift微调框架实战:10分钟搞定Qwen2.5-7B模型LoRA微调与合并
ms-swift微调框架实战:10分钟搞定Qwen2.5-7B模型LoRA微调与合并 1. 前言 在当今大模型技术快速发展的背景下,如何高效地对大型语言模型进行微调成为了许多开发者和研究者的关注焦点。本文将介绍如何使用ms-swift框架,在单卡环境下快速完成Q…...
