模板化基类内寻找继承而来的名称的问题

template<typename Company>
class MsgSender
{
public:
	void sendClear(const MsgInfo& info)
	{
		...
	}
	void sendSecret(const MsgInfo& info)
	{
		...
	}
};


template<typename Company>
class LoggingMsgSender:public MsgSender<Company>
{
public:
	void sendClearMsg(const MsgInfo& info)
	{
		sendClear(info);
	}
	
};

上述代码无法通过编译,编译器会抱怨sendClear不存在,但是我们明明看到sendClear的确在base class内,编译器却看不到它,为什么?

问题在于,当编译器遭遇class template LoggingMsgSender定义式时,并不知道它继承什么样的class。当然它继承的是MsgSender<Company>,但其中Company是个template参数,不到LoggingMsgSender被具现化无法确定它是什么。而如果不知道Company是什么,就无法知道class  MsgSender<Company>看起来像什么——更明确地说没办法知道它是否有个sendClear函数。

为了更清楚说明问题,假设我们有个class CompanyZ:

class CompanyZ
{
public:
	void sendEncrypted(const std::string& msg);
}
一般的MsgSender template对CompanyZ不合适,因为CompanyZ不需要sendClear函数,所以针对CompanyZ产生一个MsgSender特化版:

template<>
class MsgSender<CompanyZ>
{
public:
	void sendSecret(const MsgInfo& info)
	{
		...
	}
}
class定义式前面的template<>语法象征这既不是template也不是标准class而是个特化版的MsgSender template,在template实参是CompanyZ时被使用。这是所谓的模板全特化,也就是说,一旦类型参数被定义为CompanyZ,再没有其他template参数可供变化。

现在,MsgSender针对CompanyZ进行全特化,让我们再次考虑derived class LoggingMsgSender:

template<typename Company>
class LoggingMsgSender:public MsgSender<Company>
{
public:
	void sendClearMsg(const MsgInfo& info)
	{
		sendClear(info); //如果Company==CompanyZ,这个函数不存在
	}
	
};

正如注释所言,当baseclass 被指定为MsgSender<CompanyZ>时,这段代码不合法,因为那个class并未提供sendClear函数。那就是为什么C++拒绝这个调用的原因:它知道base class template有可能被特化,而那个特化版本可能不提供和一般性template相同的接口。因此它往往拒绝在模板化的基类(MsgSender<Company>)内寻找继承而来的名称(sendClear)。

解决办法有三种:

(1)使用this->

template<typename Company>
class LoggingMsgSender:public MsgSender<Company>
{
public:
	void sendClearMsg(const MsgInfo& info)
	{
		this->sendClear(info); //成立,假设sendClear被继承
	}
	
};

(2)使用using

template<typename Company>
class LoggingMsgSender:public MsgSender<Company>
{
public:
	using MsgSender<Company>::sendClear;//告诉编译器,假设sendClear位于base class内
	void sendClearMsg(const MsgInfo& info)
	{
		sendClear(info); 
	}
	
};
(3)明白指出被调用函数位于base class内
template<typename Company>
class LoggingMsgSender:public MsgSender<Company>
{
public:
	void sendClearMsg(const MsgInfo& info)
	{
		MsgSender<Company>::sendClear(info); 
	}
	
};
但这往往是最不让人满意的一个解法,因为如果被调用的是virtual函数,上述的明确资格修饰会关闭“virtual绑定行为”。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值