Effective C++:条款43:学习处理模板化基类内的名称
来源:互联网 发布:js foreach 跳出循环 编辑:程序博客网 时间:2024/05/10 10:23
(一)
注意从 “面向对象的C++” 转向 “模板C++” 时继承可能遭遇问题 :由于基类模板可能被特化,而该特化版本可能会改变成员,因此C++拒绝在模板化基类中寻找继承而来的名称。
(二)
看下面的例子:
假设将信息传送到不同的公司去,传送方式包括明文传送和密文传送,采用模板类的设计方法:
class CompanyA {public:...void sendClearText(const string& msg);void sendEncrypted(const string& msg);...};class CompanyB {public:...void sendClearText(const string& msg);void sendEncrypted(const string& msg);};...//其他公司的classesclass MsgInfo {...}; //这个class为将来生产保存信息template<typename Company>class MsgSender {public:...void sendClear(const MsgInfo& info) {string msg;...//根据info产生信息Company c;c.sendClearText(msg);}void sendSecret(const MsgInfo& info) {...}//这里调用的是c.sendEncrypted};如果想要添加发送信息时记录信息的功能,采用继承的方式:
template<typename Company>class LoggingMsgSender : public MsgSender<company> {public:...void sendClearMsg(const MsgInfo& info) {...//将传送前的信息写至记录信息sendClear(info);//试图调用基类成员函数完成发送,但是不能通过编译。这是因为在派生类没有具体化时,不知道Company是什么类型,也就不知道基类中是否存在该函数...//将传送后的信息写至记录信息}...};编译器不让其通过编译.此时的编译器抛出了"sendClear不存在"的抱怨.可sendClear明显就在base class内部啊?郁闷,这是为什么倪?别急,我来解释一下:当编译器遇到LoggingMsgSender定义式时,由于Company是一个template参数,不到LoggingMsgSender被具现化的时候,编译器是无法知道Company是什么的.由于无法知道Company是什么,那么它就无法确定MsgSender是什么,也就无法获知其否有个sendClear函数. 停一下,你可能现在对我的解释会有一个问题:为什么根据template Company就不能确定Company是什么了呢?template Company不是有声明式嘛!在这里我提出:我们不能根据一般性模板类的声明式来确定具现化类具有的操作,因为模板类有个特化声明版本的问题.
(三)
改进方法:
(1)在基类函数调用动作之前加上this指针:
template <typename Company> void LoggingMsgSender<Company>::sendClearMsg(const MsgInfo& info){ ... this->sendClear(info); //ok ... }
(2)使用using声明式在类内使用基类命名空间:
template <typename Company> class LoggingMsgSender:public MsgSender<Company>{ public: //这里的情况不是base class名称被derived class名称遮掩,而是编译器不进入base base //作用域查找,于是我们通过using声明式告诉它,请它这么做 using MsgSender<Company>::sendClear;//告诉编译器,请它假设sendClear位于base class内 ... void sendClearMsg(const MsgInfo& info){ ... sendClear(info);//ok ... } };
(3)明确限定函数是基类中的函数:
template <typename Company> class LoggingMsgSender:public MsgSender<Company>{ public: ... void sendClearMsg(const MsgInfo& info){ ... MsgSender<Company>::sendClear(info); //ok ... } ... };不过此方法有一个很明显的暇疵:如果被调用的是virtual函数,上述的明确资格修饰会关闭"virtual绑定行为".
所以还是尽量选择前两种方法吧。
请记住:
(1)可在derived class template内通过“this->”指涉base class template内的成员名称,或藉由一个明白写出的“base class资格修饰符”完成。
0 0
- 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++ 43条 处理模板化基类内的名称
- 条款43、学习处理模版化基类内的名称
- 《Effective C++》学习笔记条款33 避免遮掩继承而来的名称
- Effective C++:条款33:避免遮掩继承而来的名称
- CLOSE_WAIT生成的原因
- POJ 3579 Median
- 14.9.20 Noip总结?反思
- Ubuntu14.04 学习笔记
- JSP认识简介以及基础语法
- Effective C++:条款43:学习处理模板化基类内的名称
- 【九度OJ】1484【模拟】【C实现】【北大2012】
- 编程题目OJ1326《超级教主》总结
- 牛散沈付兴
- android中LayoutInflater累的作用
- 读javascript高级程序设计17-在线检测,cookie,子cookie
- C语言_深入函数
- UVa 1346 - Songs
- Window 7&&VS 13学习笔记