读书笔记_Effective_C++_条款四十三:学习处理模板化基类的名称
背景是这样的,有两个不同的公司,然后想设计一个MessageSender,为这两个公司发送不同的消息,既支持明文发送SendClearText,也支持密文发送SendEncryptedText。一种思路是采用动态绑定的方法,定义一个BasicMessageSender,里面有两个方法,分别是发送明文和密文的虚函数,然后定义它的子类MessageSenderForCompanyA,以及MessageSenderForCompanyB,在这两个子类里面覆盖发送明文和密文的虚函数,从而达到根据不同公司发送不同消息的目的。
但这里我们想换一种思路,使用静态多态的方法来实现,静态多态就是模板的技术了,代码如下:
class CompanyA
{
public:
void SendClearText(){}
void SendEncryptedText(){}
}; class CompanyB
{
public:
void SendClearText(){}
void SendEncrypedText(){}
}; template <class T>
class MsgSender
{
public:
void SendClearText(){}
}; template <class T>
class MsgSenderWithLog: public MsgSender<T>
{
public:
void SendClearTextWithLog()
{
// Logs
SendClearText(); // 有的编译器会编不过这段代码
}
}; int main()
{
MsgSenderWithLog<CompanyA> MsgSender;
MsgSender.SendClearTextWithLog();
}
CompanyA与CompanyB有各自的发送函数,然后有一个模板类MsgSender,这个模板待确定的参数是T,可以是CompanyA或者CompanyB,这样就可以在定义MsgSender时,比如MsgSender<CompanyA>或者MsgSender<CompanyB>,指定到底调用的哪个公司的发送函数了,这是在编译期就可以确定下来的事情。
但现在有一个新问题,那就是我们希望在执行发送函数之前,还是加上日志比较好,这样我们就继承了MsgSender,定义了一个新类MsgSenderWithLog,在这里定义了一个新的函数SendClearTextWithLog,在这个函数里面调用了父类的SendClearText。
对于这段代码,其实思路还是挺清晰的,但问题是有的编译器会编不过这行代码(VS2008以后的版本的都是可以的,之前的版本没试),为什么?
这是因为在模板技术中存在全特化的概念,比如C公司,这个公司根本不想发送明文,也就是说它只有SendEncryptedText()接口,没有SendClearText()。为了使我们的静态多态仍然可用,我们这样定义只适用于C公司的MsgSender:
class CompanyC
{
public:
void SendEncryptedText(){}
}; template <>
class MsgSender<CompanyC>
{
public:
void SendEncryptedText(){}
};
这时候如果去调用:
MsgSenderWithLog<CompanyC> MsgSenderC;
MsgSenderC.SendClearTextWithLog(); //编译器无法通过编译
这样编译器会报找到SendClearText()的错。正是因为有的编译器考虑到了全特化模板版本可以与普通版本不同,所以在有继承关系存在时,对直接调用父类的函数给出了不支持的error。但这个error是与编译器相关的,不是必然出现的。
为了让更多的编译器放弃这种全特化的忧虑,书上提供了三种解决方法:
方法一: 将
void SendClearTextWithLog()
{
// Logs
SendClearText(); // 有的编译器会编不过这段代码
}
改成
void SendClearTextWithLog()
{
// Logs
this->SendClearText(); // 这下能编译通过了
}
方法二:
在子类中声明using MsgSender<T>::SendClearText;
编译器报error本质是不进行模板父类域的查找,所以这里using了父类的一个函数名,强制编译器对之进行查找。
方法三:
将SendClearText()指明为MsgSender<T>::SendClearText()。
最后总结一下:
可在derived class template内通过“this->”指涉base class templates内的成员名称,或藉由一个明白写出的“base class资格修饰符”完成。
读书笔记_Effective_C++_条款四十三:学习处理模板化基类的名称的更多相关文章
- 读书笔记_Effective_C++_条款三十三:避免遮掩继承而来的名称
名称的遮掩可以分成变量的遮掩与函数的遮掩两类,本质都是名字的查找方式导致的,当编译器要去查找一个名字时,它一旦找到一个相符的名字,就不会再往下去找了,因此遮掩本质上是优先查找哪个名字的问题. 而查找是 ...
- 读书笔记 effective c++ Item 43 了解如何访问模板化基类中的名字
1. 问题的引入——派生类不会发现模板基类中的名字 假设我们需要写一个应用,使用它可以为不同的公司发送消息.消息可以以加密或者明文(未加密)的方式被发送.如果在编译阶段我们有足够的信息来确定哪个信息会 ...
- 读书笔记_Effective_C++_条款四十七:请使用trait classes来表示类型信息
这一条款主要来讨论模板中迭代器的属性iterator_category,它可以通过类似于vector<int>::iterator::iterator_category的方式来取得. 到这 ...
- 读书笔记_Effective_C++_条款四十一:了解隐式接口和编译期多态
从本条款开始,就进入了全书的第七部分:模板与泛型编程.模板与泛型在C++中是非常重要的部分,还记得本书第一章时,把C++视为一个联邦,它由四个州政府组成,其中一个政府就是模板与泛型了. 本条款是一个介 ...
- 读书笔记_Effective_C++_条款四十九:了解new_handler的行为
本章开始讨论内存分配的一些用法,C/C++内存分配采用new和delete.在new申请内存时,可能会遇到的一种情况就是,内存不够了,这时候会抛出out of memory的异常.有的时候,我们希望能 ...
- 读书笔记_Effective_C++_条款四十八:了解模板元编程
作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...
- 读书笔记_Effective_C++_条款四十六:需要类型转换时请为模板定义非成员函数
这个条款可以看成是条款24的续集,我们先简单回顾一下条款24,它说了为什么类似于operator *这样的重载运算符要定义成非成员函数(是为了保证混合乘法2*SomeRational或者SomeRat ...
- 读书笔记_Effective_C++_条款四十五:运用成员函数模板接受所有兼容类型
比如有一个Base类和一个Derived类,像下面这样: class BaseClass {…}; class DerivedClass : public BaseClass {…}; 因为是父类与子 ...
- 读书笔记_Effective_C++_条款四十四:将与参数无关的代码抽离template
标题上说“将与参数无关的代码抽离template”,这里的参数既可以指类型,也可以是非类型,我们先来看看非类型的情况. 假定我们要为矩阵写一个类,这个矩阵的行列元素个数相等,是一个方阵,因而我们可以对 ...
随机推荐
- 无线客户端框架设计(3):基类的设计(iOS篇)
本文代码:YoungHeart-Chapter-03.zip 没有基类的App都不是好App. 因为iOS使用的是mvc模式的开发模式,所以,业务逻辑基本都在每个页面相应的ViewController ...
- Nodejs学习笔记(八)--- Node.js + Express 实现上传文件功能(felixge/node-formidable)
目录 前言 formidable简介 创建项目并安装formidable 实现上传功能 运行结果 部分疑惑解析 写在之后 前言 前面讲了一个构建网站的示例,这次在此基础上再说说web的常规功能---- ...
- Atitit.mvc的趋势与未来attilax总结
Atitit.mvc的趋势与未来attilax总结 1. Mvc的分类 (服务端mvc vs客户端mvc)1 2. Mvc的趋势,从服务端mvc正在转向客户端mvc1 2.1. 更加完善的分离..h ...
- 将外卖O2O广告一棍子打成竞价排名,秤把平了吗?
近日,诸多媒体报道称美团外卖.饿了么等外卖O2O将竞价排名引入外卖平台当中进行广告运营一事闹得沸沸扬扬.那么,美团外卖.饿了么真的都是竞价排名吗? 其实,美团外卖的付费推广仅仅只是针对列表的固定位置, ...
- JavaWeb学习总结(十七)——JSP中的九个内置对象
一.JSP运行原理 每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理.JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet ...
- SAP大数据为"海上F1"提供技术支持
“海上F1”的2014极限帆船赛在青岛开赛,这场大赛是技术与体育高度融合的盛会.比赛中,每一个船员将使用各种高新技术,应尽所能,战胜对手.很多人之所以喜欢这样的比赛,是因为帆船比赛是世界上最复杂的一项 ...
- echart.js的使用与API
---恢复内容开始--- echart.js的使用与API 1.echart.js的使用: 第一步:在head标签或body下创建一个script标签去引用echart.js,(该文件可以在echar ...
- 解决安卓SDK更新连不通问题
http://wenku.baidu.com/link?url=d7t81OFF4_o2YF9iBne-azyovROGPGOozMgWKNyAIQK8vtI0mIjvzpfdOXg7KOobu202 ...
- hdu 1385 Minimum Transport Cost (floyd算法)
貌似···················· 这个算法深的东西还是很不熟悉!继续学习!!!! ++++++++++++++++++++++++++++ ======================== ...
- 使用Android Studio打Andorid apk包的流程
启动Android studio 1.点击菜单栏Build -> Generate Signed APK...,打开如下窗口 2.这里是类似eclipse中Android的签名,假设这里没有 ...