首页 > 代码库 > Effective C++ Item 43 学习处理模板化基类内的名称

Effective C++ Item 43 学习处理模板化基类内的名称

本文为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