本文为senlie原创。转载请保留此地址:http://blog.csdn.net/zhengsenlie
经验:可在derived class templates 内通过 "this->" 指涉 base class templates 内的成员名称,或藉由一个明确写出的 "base class 资格修饰符"完毕。
演示样例:
class CompanyA{ 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); //... }; class CompanyZ{ //这个 class 不提供 sendCleartext 函数 public: //... void sendEncrypted(const std::string &msg); //... }; class MsgInfo {...}; template<typename Company> class MsgSender{ public: //... void sendClear(const MsgInfo &info){ std::string msg; Company c; c.sendCleartext(msg); } void sendSecret(const MsgInfo &info){ //... } }; template<> //一个全特化的 MsgSender;它和一般 template 同样。区别仅仅在于它删掉了 sendClear class MsgSender<CompanyZ>{ public: //... void sendSecret(const MsgInfo &info){...} }; template<typename Company> class LoggingMsgSender: public MsgSender<Company>{ //... void sendClearMsg(const MsgInfo &info){ 将”传送前“的信息写到 log sendClear(info); //调用 base class 函数,这段码无法通过编译。由于全特化的版本号里没有 sendClear 这个函数 将”传阅后”的信息写到 log } //... };
解析:C++知道 base class templates 有可能被特化。而那个特化版本号可能不提供和一般性 template 同样的接口,
因此它往往拒绝在 templatized base classes内寻找继承而来的名称
纠正1:在 base class 函数调用动作之前加上 this->
template<typename Company> class LoggingMsgSender: public MsgSender<Company>{ //... void sendClearMsg(const MsgInfo &info){ 将”传送前“的信息写到 log this->sendClear(info); // 将”传阅后”的信息写到 log } //... };
纠正2:使用 using 声明式
template<typename Company> class LoggingMsgSender: public MsgSender<Company>{ //... using MsgSender<Company>::sendClear; void sendClearMsg(const MsgInfo &info){ 将”传送前“的信息写到 log sendClear(info); // 将”传阅后”的信息写到 log } //... };
纠正3:指出被调用的函数位于 base class 内
template<typename Company> class LoggingMsgSender: public MsgSender<Company>{ //... void sendClearMsg(const MsgInfo &info){ 将”传送前“的信息写到 log MsgSender<Company>::sendClear(info); //不太好。关闭了 "virtual 绑定行为" 将”传阅后”的信息写到 log } //... };
解析:上面的每一解法做的事情都同样:对编译器承诺"base class template"的不论什么特化版本号都将支持其一般版本号所提供的接口。
但假设这个承诺未能被实践出来,编译器还是会报错的。
演示样例:
LoggingMsgSender<CompanyZ> zMsgSender; MsgInfo msgData; zMsgSender.sendClearMsg(msgData); //error