Effective C++笔记_条款43 学习处理模板化基类内的名称
来源:互联网 发布:软件项目经理管理办法 编辑:程序博客网 时间:2024/05/21 11:34
Effective C++笔记_条款43 学习处理模板化基类内的名称
开篇就来了一个示例代码,整个这个小节就围绕这个示例代码来描述模板化基类内的名称(函数)。主要是因为C++知道base class templates有可能被特化,而那个特化版本肯呢个不提供和一般性template相同的接口。因此它往往拒绝在templatized base classes(模板化基类)内寻找继承而来的名称。
1 class CompanyA { 2 public: 3 //... 4 void sendCleartext(const std::string& msg); 5 void sendEncrypted(const std::string& msg); 6 //... 7 }; 8 9 class CompanyB {10 public:11 //...12 void sendCleartext(const std::string& msg);13 void sendEncrypted(const std::string& msg);14 //...15 };16 17 //... 针对其他公司设计的类18 19 /*用来保存信息,以备将来产生信息*/20 class MsgInfo {21 //...22 };23 24 template<typename Company>25 class MsgSender {26 public:27 //... 构造函数、析构函数等28 void sendClear(const MsgInfo& info) 29 {30 std::string msg;31 // 根据info产生信息32 Company c;33 c.sendCleartext(msg);34 }35 36 void sendSecret(const MsgInfo& info)37 {38 std::string msg;39 // 根据info产生信息40 Company c;41 c.sendEncryptedtext(msg);42 }43 };44 45 /* 日志:记录每个信息发送相关记录 */46 template<typename Company>47 class LoggingMsgSender:public MsgSender<Company> {48 //... 构造函数、析构函数等49 void sendClearMsg(const MsgInfo& info) 50 {51 52 // 将“传送前”的信息写到log53 sendClear(info); // 调用base class函数 (error:不同通过编译)54 // 将“传送后”的信息写到log55 }56 57 };58 59 /*调用base class函数 (error:不同通过编译)的原因:60 模板类型在编译前不知道Company是否有sendClear函数,比如下面这个 CompanyZ class61 */62 class CompanyZ {63 // 不提供sendClearText函数64 //...65 void sendEncrypted(const std::string& msg);66 //...67 };
为了解决上述问题:可以使用为 CompanyZ,搞个绿色通道:
1.class 定义式前面加 template<> 表明:它既不是template也不是标准的class,而是一个特化版的MsgSender template,在template实参是CompanyZ时被使用。
2.模板全特化(total template specialization):template MsgSender针对类型CompanyZ特化了,而且其特化是全面性的,也就说一旦类型参数被指定为CompanyZ,再没有其他template参数可供变化。
1 template<> // 一个全特化的MsgSender,与一般template相同,差别只在于它删掉了sendClear2 class MsgSender<CompanyZ> {3 //...4 void sendSecret(const MsgInfo& info)5 {6 sendEncryptedtext(info);7 }8 };
1 /* 再来看,日志:记录每个信息发送相关记录 */ 2 template<typename Company> 3 class LoggingMsgSender:public MsgSender<Company> { 4 //... 构造函数、析构函数等 5 void sendClearMsg(const MsgInfo& info) 6 { 7 8 // 将“传送前”的信息写到log 9 sendClear(info); 10 /*11 如果Company == CompanyZ, CompanyZ不存在sendClear函数,报错。12 原因:编译器知道base class templates有可能被特化,而那个特化版本肯呢个不提供13 和一般性template相同的接口。因此它往往拒绝在templatized base classes(模板化基类)内寻找继承而来的名称。14 */15 // 将“传送后”的信息写到log16 }17 18 };
让C++“不进入templatized base classes观察”的行为失效的解决方法如下:
1. 在 base class 函数调用动作之前加上 “this->”:
1 /* 日志:记录每个信息发送相关记录 */ 2 template<typename Company> 3 class LoggingMsgSender:public MsgSender<Company> { 4 //... 构造函数、析构函数等 5 void sendClearMsg(const MsgInfo& info) 6 { 7 8 // 将“传送前”的信息写到log 9 this->sendClear(info); 10 // 将“传送后”的信息写到log11 }12 //...13 };
2.使用using声明式
这里并不是base class名称被derived class名称遮掩,而是编译器不进入base class作用域内查找,于是通过using告诉它,请它那么做。
1 /* 日志:记录每个信息发送相关记录 */ 2 template<typename Company> 3 class LoggingMsgSender:public MsgSender<Company> { 4 using MsgSender<Company>::sendClear; // 告诉编译器,清它假设sendClear位于base class内 5 //... 构造函数、析构函数等 6 void sendClearMsg(const MsgInfo& info) 7 { 8 9 // 将“传送前”的信息写到log10 sendClear(info); 11 // 将“传送后”的信息写到log12 }13 //...14 };
3.明确指出被调用的函数位于base class内
缺点:如果被调用的是virtual函数,明确自个修饰(explicit qualification) 会关闭"virtual绑定行为"
1 /* 日志:记录每个信息发送相关记录 */ 2 template<typename Company> 3 class LoggingMsgSender:public MsgSender<Company> { 4 //... 构造函数、析构函数等 5 void sendClearMsg(const MsgInfo& info) 6 { 7 8 // 将“传送前”的信息写到log 9 MsgSender<Company>::sendClear(info); 10 // 将“传送后”的信息写到log11 }12 //...13 };
总结:
1. 三种方法都是从名称可视点(visibility point)的角度出发:
对编译器承诺“base class template”的任何特化版本都将支持其一般(泛化)版本所提供的接口。[编译器的早期诊断时间:当解析derived class template的定义式时];如果这个承诺没有被实践,往后的编译器最终会给事实一个公道。[在编译器晚期诊断时间:当那些templates被特定的template具体化时]。如下面的示例:
1 LoggingMsgSender<CompanyZ> zMsgSender;2 MsgInfo msgData;3 //...4 zMsgSender.sendClearMsg(msgData); // error
2.可在derived class templates内通过"this->"指涉base class templates内的成员名称,或藉由一个明白写出的“base class资格修饰符”完成。
声明:全文文字都是来源《Effective C++》 3th。这里所写都是自己的读书的时候梳理做的笔记罢了。希望对他人有用,那是我的荣幸。
- Effective C++学习笔记_条款43:学习处理模板化基类内的名称
- Effective C++:条款43:学习处理模板化基类内的名称
- 《Effective C++》:条款43:学习处理模板化基类内的名称
- Effective C++笔记_条款43 学习处理模板化基类内的名称
- 读书笔记《Effective C++》条款43:学习处理模板化基类内的名称
- 条款43:学习处理模板化基类内的名称
- 条款43:学习处理模板化基类内的名称
- 条款43:学习处理模板化基类内的名称
- 条款43:学习处理模板化基类内的名称
- 条款43:学习处理模板化基类内的名称
- Effective C++ Item 43 学习处理模板化基类内的名称
- C++之学习处理模板化基类内的名称(43)---《Effective C++》
- 条款43:学习处理模板化基类的名称
- 《Effective C++》读书笔记之item43:学习处理模板化基类内的名称
- 《Effective C++》学习笔记条款33 避免遮掩继承而来的名称
- Effective C++ 43条 处理模板化基类内的名称
- 条款43、学习处理模版化基类内的名称
- 《Effective C++》学习笔记——条款43
- 剑指offer--第一个只出现一次的字符
- C/C++常用头文件及函数汇总
- 组件主流程
- JAVA监听器添加的四种方式(自身、外部类、内部类、匿名类)
- TCO 2015 Round 1A DIV 1 1000
- Effective C++笔记_条款43 学习处理模板化基类内的名称
- Android-SharedPreference
- secureCRT和secureFX真的太方面了!!!
- [授权发表]开源书籍:《C语言编程透视》
- MPI、PThread笔记
- 分而治之策略
- java反射
- 最快最简单的排序---(初级)桶排序
- java编程思想学习