C 箴言:如何访问模板化基类中的名字

2008-02-23 05:27:14来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

 假设我们要写一个应用程式,他能够把消息传送到几个不同的公司去。消息既能够以加密方式也能够以明文(不加密)的方式传送。假如我们有足够的信息在编译期间确定哪个消息将要发送给哪个公司,我们就能够用一个 template-based(模板基)来解决问题:

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);
 ...
};
... // classes for other companies

class MsgInfo { ... }; // class for holding information
// used to create a message
template<typename Company>
class MsgSender {
public:
 ... // ctors, dtor, etc.

 void sendClear(const MsgInfo& info)
 {
  std::string msg;
  create msg from info;

  Company c;
  c.sendCleartext(msg);
 }
 void sendSecret(const MsgInfo& info) // similar to sendClear, except
 { ... } // calls c.sendEncrypted
};

  这个能够很好地工作,但是假设我们有时需要在每次发送消息的时候把一些信息记录到日志中。通过一个 derived class(派生类)能够很简单地增加这个功能,下面这个似乎是个合理的方法:

template<typename Company>
class LoggingMsgSender: public MsgSender<Company> {
public:
 ... // ctors, dtor, etc.
 void sendClearMsg(const MsgInfo& info)
 {
  write "before sending" info to the log;
  sendClear(info); // call base class function;
  // this code will not compile!
  write "after sending" info to the log;
 }
 ...
};

  注意 derived class(派生类)中的 message-sending function(消息发送函数)的名字 (sendClearMsg) 和他的 base class(基类)中的那个(在那里,他被称为 sendClear)不同。这是个好的设计,因为他避开了 hiding inherited names(隐藏继承来的名字)的问题(参见《C 箴言:避免覆盖通过继承得到的名字》)和重定义一个 inherited non-virtual function(继承来的非虚拟函数)的和生俱来的问题(参见《C 箴言:绝不重定义继承的非虚拟函数》)。但是上面的代码不能通过编译,至少在符合标准的编译器上不能。这样的编译器会抱怨 sendClear 不存在。我们能够看见 sendClear 就在 base class(基类)中,但编译器不会到那里去寻找他。我们有必要理解这是为什么。

  问题在于当编译器碰到 class template(类模板)LoggingMsgSender 的 definition(定义)时,他们不知道他从哪个 class(类)继承。当然,他是 MsgSender<Company>,但是 Company 是个 template parameter(模板参数),这个直到更迟一些才能被确定(当 LoggingMsgSender 被实例化的时候)。不知道 Company 是什么,就没有办法知道 class(类)MsgSender<Company> 是什么样子的。特别是,没有办法知道他是否有一个 sendClear function(函数)。

  为了使问题具体化,假设我们有一个需要加密通讯的 class(类)CompanyZ:

class CompanyZ { // this class offers no
 public: // sendCleartext function
 ...
 void sendEncrypted(const std::string& msg);
 ...
};

  一般的 MsgSender template(模板)不适用于 CompanyZ,因为那个模板提供一个 sendClear function(函数)对于 CompanyZ objects(对象)没有意义。为了纠正这个问题,我们能够创建一个 MsgSender 针对 CompanyZ 的特化版本:

template<> // a total specialization of
class MsgSender<CompanyZ> { // MsgSender; the same as the
public: // general template, except
... // sendCleartext is omitted
void sendSecret(const MsgInfo& info)
{ ... }
};

  注意这个 class definition(类定义)开始处的 "template <>" 语法。他表示这既不是个 template(模板),也不是个 standalone class(单独类)。正确的说法是,他是个用于 template argument(模板参数)为 CompanyZ 时的 MsgSender template(模板)的 specialized version(特化版本)。这以 total template specialization(完全模板特化)闻名:template(模板)MsgSender 针对类型 CompanyZ 被特化,而且这个 specialization(特化)是 total(完全)的——只要 type parameter(类型参数)被定义成了 CompanyZ,就没有剩下能被改变的其他 template's parameters(模板参数)。

  已知 MsgSender 针对 CompanyZ 被特化,再次考虑 derived class(派生类)LoggingMsgSender:

template<typename Company>
class LoggingMsgSender: public MsgSender<Company> {
 public:
 ...
 void sendClearMsg(const MsgInfo& info)
 {
  write "before sending" info to the log;
  sendClear(info); // if Company == CompanyZ,
  // this function doesn't exist!
  write "after sending" info to the log;
 }
 ...
};

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇: C 箴言:理解typename的两个含义

下一篇: C 对象布局及多态探索之菱形结构虚继承