条款43:学习处理模板化基类内的名称

1.前言

假设我们需要编写一个程序,它能够传送信息到若干不同的公司去。信息要不编译称密码,要不就是未加工的文字。如果编译器间我们有足够的信息来决定哪一个信息传至哪一家公司,就可以采用基于template的解法

class Company{public:...void sendClearText(const std::string& msg);void sendEncrypted(const std::string& msg);...};
class CompanyB{public:...void sendCleartext(const std::string& msg);void sendEncrypted(const std::string& msg);...
};
...//针对其它公司设计的classes
class MsgInfo{....//这个class用来保存信息,以备将来产生信息
};template<typename Company>
class MsdSender{class MsgSender{public:...void sendClear(const MsgInfo& info){std::string msg;Company c;    c.sendCleartext(msg);}void sendSecret(const MsgInfo& info)//类似sendClear{....}}
};

2.实例分析

这个做法能够完成任务,但假设我们有时候想要在每次送出信息时log某些信息。derived class可轻易加上这样的功能:

template<typename Company>
class LoggingMsgSender:public MsgSender<Company>
{public:...//相关构造函数,析构函数等void sendClearMsg(const MsgInfo& info){将“传送前”的信息写至logsendClear(info);//调写base class函数;这段代码无法通过编译将“传送后”的信息写至log            }...
};

注意这里derived class的信息传送函数有一个不同的名称(sendClearMsg),与其base class内的名称(sendClear)不同。(能避免遮掩“继承而得”的名称,也避免重新定义一个继承而得得non-virtual函数)。然而不幸得时上述代码无法通过编译。编译器会抱怨sendClear不存在。我们能看到sendClear()确实在base class内,编译器却检测不到它们,为什么?

问题在于:当编译器遇到class template LoggingMsgSender定义式时,并不知道它要继承什么样的class。当然它继承的是MsgSender<Company>,但其中的Company是个template参数,不到loggingMsgSender被具现化,无法知道它是什么。而如果不知道Company是什么,就无法知道class MsgSender<Company>看起来是什么-更明确地说是没办法知道它是否有个sendClear函数。

为了让问题更具体化,假设我们有个class CompanyZ坚持使用加密通讯:

class CompanyZ{public:...void sendEncrypted(const std::string& msg);...
};

一般性的MsgSender template对CompanyZ并不合适,因为那个template提供了一个sendClear函数(其中针对其类型参数Company调用了sendCleartext函数),而这对CompanyZ对象并不合理,要矫正这个问题,我们可以针对CompanyZ产生一个MsgSender特化版:

template<>
class MsgSender<Company>//一个全特化的MsghSender,//它和一般template相同,差别在于它删除了sendClear
{public:...void sendSecret(const MsgInfo& info){...}};

注意class定义式最前头的“template”语法象征这即不是template,也不是标准的class,而是个特化版的MsgSender template,在template实参是CompanyZ时被使用。而这个所谓的模板全特化(total template specialization):template MsgSender针对类型CompanyZ特化了而且其特性也是全面性的,也就是说一旦类型参数被定义为CompanyZ,再没有其它template参数可供变化。

现在,MsgSender针对CompanyZ进行了全特化,让我们再次考虑derived class 中的LoggingMsgSender:

templateMsgSender:
template<typename Company>
class LoggingMsgSender:public MsgSender<Company>
{public:...void sendClearMsg(const MsgInfo& info){//将“传送前”的信号写至log;sendClear(info);//如果·Company==CompanyZ,这个函数将不存在//将“传送后”的信息写到log}....
};

正如注释所言,当base class被指定为MsgSender<Company>时,这段代码不合法,因为class并未提供sendClear函数,那就是为什么C++拒绝调用的原因:它知道base class template有可能被特化,而那个版本可能不提供和一般性template相同的接口。因此它会拒绝在template base classes(模板化基类,本例的MsgSender<Company>)内寻找继承而来的名称(本例的SendClear)。

为了重头来过,我们必须有某种办法令C++“不进入templatized base classes观察“的行为失效。有三个办法:

第一是在base class函数调用动作之前加上”->this“:

template<typename Company>
class LoggingMsg`Sender:public MsgSender<Company>
{public:...void sendClearMsg(const MsgInfo& info){//将”传送前“的休息写至Log;this->sendClear(info);//成立,假设sendClear被继承//将"传递后"的信息写至log;}
};

第二是使用using声明式。(条款33描述了using 声明式如何将”被掩盖的base class名称带入一个derived class作用域内“),我们可以写下sendClearMsg:

template<typename Company>
class LoggingMsgSender:public MsgSender<Company>
{public:using MsgSender<Company>::sendClear;//告诉编译器,请他假设sendClear位于base class内...void sendClearMsg(const MsgInfo& info){...sendClear(info);//ok,假设sendClear将被继承...}
};

虽然using声明式在这里或在条款33都可有效运作,但两处解决问题的本质其实不相同。这里的情况并不是base class名称被derived class名称遮掩,而是编译器不进入base class作用域查找,于是我们通过Using告诉它。

第三个方法是指出被调用的函数位于base class内:

template<typename Company>
class LoggingMsgSender:public MsgSender<Company>
{public:...void sendClearMsg(const MsgInfo& info){...MsgSender<Company>::sendClear(info);//ok,假设sendClear将被继承}....};

但这不是一种很满意的方法,因为如果被调用的是virtual函数,上述的明确资格修斯(explicit qualification)会关闭”virtual绑定行为“。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/631045.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++入门到精通】智能指针 auto_ptr、unique_ptr简介及C++模拟实现 [ C++入门 ]

阅读导航 引言一、std::auto_ptr1. 简介2. 使用示例3. C模拟实现 二、std::unique_ptr1. 简介2. 使用示例3. C模拟实现 温馨提示 引言 在 C 中&#xff0c;智能指针是一种非常重要的概念&#xff0c;它能够帮助我们自动管理动态分配的内存&#xff0c;避免出现内存泄漏等问题。…

vue3有了解过吗?能说说跟vue2的区别吗?

一、Vue3介绍 关于vue3的重构背景&#xff0c;尤大是这样说的&#xff1a; 「Vue 新版本的理念成型于 2018 年末&#xff0c;当时 Vue 2 的代码库已经有两岁半了。比起通用软件的生命周期来这好像也没那么久&#xff0c;但在这段时期&#xff0c;前端世界已经今昔非比了 在我…

【Mybatis】我抄袭了Mybatis,手写一套MyMybatis框架:初窥mybatis源码

在历经之前几章课程的深入学习之后&#xff0c;我想我们已经初步掌握了如何运用jdbc连接数据库的技术&#xff1b;同时&#xff0c;我们也实现了利用mybatis框架的能力&#xff0c;甚至尝试着手编写、实现了ORM的框架。我坚信大家对MyBatis的理解和应用已经达到了一定程度。然而…

昇思MindSpore技术公开课——第三课:GPT

1、学习总结 1.1Unsupervised Language Modelling GPT代表“生成预训练”&#xff08;Generative Pre-trained Transformer&#xff09;。GPT模型是由OpenAI公司开发的一种基于Transformer架构的人工智能语言模型。它在大规模文本数据上进行预训练&#xff0c;学习了丰富的语…

Nginx 简介

1、概念介绍 Nginx ("engine x") 是一个轻量级、高性能的 WEB 服务器软件和反向代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的&#xff0c;第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。其将源代码以类 BSD 许可证的形式发…

k8s---对外服务 ingress

目录 目录 目录 ingress与service ingress的组成 ingress-controller&#xff1a; ingress暴露服务的方式 2.方式二&#xff1a;DaemonSethostnetworknodeSelector DaemonSethostnetworknodeSelector如何实现 3.deploymentNodePort&#xff1a; 虚拟主机的方式实现http代…

Windows 下 PYQT开发环境的搭建:

(1)环境搭建&#xff1a; PYQT 安装包&#xff1a; Anaconda&#xff1a; Anaconda3-2023.09-0-Windows-x86_64 pycharm&#xff1a; pycharm 2019.3 下载包&#xff1a; Anaconda:下载成功 |蟒蛇 (anaconda.com) pycharm: pycharm安装包_pycharm用copilotchat资源-CSD…

gradle/maven排除配置

maven <!--打包去掉jar包内的配置文件--><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><configuration><excludes><exclude>application-gateway.yml</exclude&g…

鸿蒙开发之如何将相册中的图片读到Canvas画布

第一步&#xff1a;申请文件权限&#xff08;很重要&#xff09; 申请方法见上一篇博客 https://blog.csdn.net/qq_15509071/article/details/135659048 第二步&#xff1a;打开相册&#xff0c;选取图片 try {let PhotoSelectOptions new picker.PhotoSelectOptions();Pho…

Servlet 预览pdf

一、背景 上篇文章介绍了图片的预览&#xff0c;这篇我们介绍下 pdf 文件的预览&#xff0c;pdf 预览在实际开发中用的还是比较多的&#xff0c;比如很多文件协议、合同都是用pdf 格式&#xff0c;协议预览就需要我们做 pdf 预览了。 二、实操 其实在上篇文章最后已经说了常用…

git push/pull/clone超时解决

git push/pull/clone超时解决 git push/pull/clone超时解决问题描述:尝试修复 git push/pull/clone超时解决 问题描述: 之前都可以正常操作,突然远程仓库的操作都超时 Failed to connect to github.com port 443: Timed out尝试修复 切换请求方式:ssh/https换一种请求操作其…

Springboot+vue的智能家居系统(有报告),Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的智能家居系统&#xff08;有报告&#xff09;&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的智能家居系统&#xff0c;采用M&#xff08;model&a…

linux系统nginx工具的日志配置

日志配置 日志介绍log_format 指令error_log 指令配置段&#xff1a;main&#xff0c; http, mail, stream, server, location作用域 open_log_file_cache 指令配置段:http、server、location作用域中。 log_not_found 指令log_subrequest指令rewrite_log指令日志配置 日志介绍…

NVIDIA jetson编译opencv 源码 python版本

安装 jetson-stats 查看GPU的利用率 sudo apt-get install python3-pip sudo -H pip3 install jetson-stats 运行 jtop 进行查看 opencv 编译python版本 编译命令 cmake -D CMAKE_INSTALL_PREFIX/usr/local/opencv-4.6.0 -D CMAKE_BUILD_TYPERELEASE -D WITH_OPENGLON -D …

python爬虫如何写,有哪些成功爬取的案例

编写Python爬虫时&#xff0c;常用的库包括Requests、Beautiful Soup和Scrapy。以下是三个简单的Python爬虫案例&#xff0c;分别使用Requests和Beautiful Soup&#xff0c;以及Scrapy。 1. 使用Requests和Beautiful Soup爬取网页内容&#xff1a; import requests from bs4 …

24校招,江淮汽车软件测试工程师技术面+HR面

前言 记录一下楼主的面试经历&#xff0c;希望对后来者有用 时间&#xff1a;15min 平台&#xff1a;腾讯会议 过程 技术面试 自我介绍 为啥不考研 实习收获 你有做过软件开发的工作吗&#xff1f; 除了Java和Python&#xff0c;还会其他的语言吗&#xff1f; 学过C吗…

2.4 网络层01

2.4 网络层01 2.4.1 网络层概述 网络层的主要任务是实现网络互连&#xff0c;进而实现数据包在各网络之间的传输。 异构网络内部的计算机要想实现通信是不需要实现网络互联的&#xff0c;异构网络之间要想实现通信就必须实现网络互连。 路由器工作在五层协议体系结构的网络…

Kafka-消费者-KafkaConsumer分析

与KafkaProducer不同的是&#xff0c;KafkaConsumer不是一个线程安全的类。 为了便于分析&#xff0c;我们认为下面介绍的所有操作都是在同一线程中完成的&#xff0c;所以不需要考虑锁的问题。 这种设计将实现多线程处理消息的逻辑转移到了调用KafkaConsumer的代码中&#x…

美易官方:欧央行夏季降息预期市场反应

近日&#xff0c;欧洲央行行长拉加德在接受媒体采访时表示&#xff0c;欧洲央行官员可能已经达成在夏季降息的共识。这一消息在金融市场引起了广泛关注&#xff0c;投资者纷纷解读其对未来货币政策的影响。然而&#xff0c;拉加德同时指出激进降息押注无助于抗击通胀&#xff0…

目标检测YOLO实战应用案例100讲-橘子自动采摘机视觉识别

目录 前言 卷积神经网络相关理论基础 2.1传统神经网络模型 2.2卷积神经网络结构