读书笔记_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”,这里的参数既可以指类型,也可以是非类型,我们先来看看非类型的情况. 假定我们要为矩阵写一个类,这个矩阵的行列元素个数相等,是一个方阵,因而我们可以对 ...
随机推荐
- AngularJS快速入门指南08:表格
ng-repeat指令非常适合用来显示表格. 在表格中显示数据 在AngularJS中显示表格非常容易: <div ng-app="myApp" ng-controller= ...
- windows装了双系统设置默认启动系统
我们装了双系统后,在开机设置时会自动启动其中一个系统,有时提示时间会很短,以至于不能判断自己是否装了双系统,以下,当电脑打开后,我们可以观察是否装了双系统 1.按组合键<Win+R>,打开 ...
- 使用Swift代码演示Cocoa框架
通过使用简单的代码学习Cocoa框架,每一个例子都通过代码和StoryBoard实现,并且总结他们的各自特点 所有完整代码将会托管到github库,https://github.com/land-pa ...
- Java band [Cite]
SampleModel 取样模型Databuffer 数据缓冲区 Raster 光栅Sample 样本band 带 SampleModel是java awt中的一个抽象类,它定义了一个接口,用于提 ...
- WebView上实现Java与JavaScript交互
在安卓开发上,考虑到开发效率和界面更新,有时使用WebView结合web页面技术,可以快速迭代地开发移动应用.WebView加载资源的速度并不慢,但是如果资源多了,就很慢.图片.css.js.html ...
- 南京都昌信息科技有限公司招聘C#程序员
南京都昌信息科技有限公司招聘全职C#程序员 本公司核心产品为DCWriter电子病历文本编辑器,DCTimeLine时间轴软件等自研产品,现招聘全职C#程序员. 职位描述: 1.使用C#进行软件开发, ...
- 一個小技巧讓ipad或iphone的瀏覽器也能開啟firebug
首先複製這一段代碼 javascript:(function(F,i,r,e,b,u,g,L,I,T,E){if(F.getElementById(b))return;E=F[i+'NS']& ...
- 转:SDL2源代码分析
1:初始化(SDL_Init()) SDL简介 有关SDL的简介在<最简单的视音频播放示例7:SDL2播放RGB/YUV>以及<最简单的视音频播放示例9:SDL2播放PCM>中 ...
- 架设证书服务器 及 让IIS启用HTTPS服务(转)
无废话图文教程,教你一步一步搭建CA服务器,以及让IIS启用HTTPS服务. 一.架设证书服务器(CA服务) 1.在系统控制面板中,找到“添加/删除程序”,点击左侧的“添加/删除windows组件”, ...
- 在Flex (Flash)中嵌入HTML 代码或页面—Flex IFrame
在flex组件中嵌入html代码,可以利用flex iframe.这个在很多时候会用到的,有时候flex必须得这样做,如果你不这样做还真不行-- flex而且可以和html进行JavaScript交互 ...