读书笔记_Effective_C++_条款四十三:学习处理模板化基类的名称

背景是这样的,有两个不一样的公司,而后想设计一个MessageSender,为这两个公司发送不一样的消息,既支持明文发送SendClearText,也支持密文发送SendEncryptedText。一种思路是采用动态绑定的方法,定义一个BasicMessageSender,里面有两个方法,分别是发送明文和密文的虚函数,而后定义它的子类MessageSenderForCompanyA,以及MessageSenderForCompanyB,在这两个子类里面覆盖发送明文和密文的虚函数,从而达到根据不一样公司发送不一样消息的目的。函数

但这里咱们想换一种思路,使用静态多态的方法来实现,静态多态就是模板的技术了,代码以下:this

 1 class CompanyA
 2 {
 3 public:
 4     void SendClearText(){}
 5     void SendEncryptedText(){}
 6 };
 7 
 8 
 9 class CompanyB
10 {
11 public:
12     void SendClearText(){}
13     void SendEncrypedText(){}
14 };
15 
16 template <class T>
17 class MsgSender
18 {
19 public:
20     void SendClearText(){}
21 };
22 
23 template <class T>
24 class MsgSenderWithLog: public MsgSender<T>
25 {
26 public:
27     void SendClearTextWithLog()
28     {
29         // Logs
30         SendClearText(); // 有的编译器会编不过这段代码
31     }
32 };
33 
34 int main()
35 {
36     MsgSenderWithLog<CompanyA> MsgSender;
37     MsgSender.SendClearTextWithLog();
38 }

CompanyA与CompanyB有各自的发送函数,而后有一个模板类MsgSender,这个模板待肯定的参数是T,能够是CompanyA或者CompanyB,这样就能够在定义MsgSender时,好比MsgSender<CompanyA>或者MsgSender<CompanyB>,指定到底调用的哪一个公司的发送函数了,这是在编译期就能够肯定下来的事情。spa

但如今有一个新问题,那就是咱们但愿在执行发送函数以前,仍是加上日志比较好,这样咱们就继承了MsgSender,定义了一个新类MsgSenderWithLog,在这里定义了一个新的函数SendClearTextWithLog,在这个函数里面调用了父类的SendClearText。设计

对于这段代码,其实思路仍是挺清晰的,但问题是有的编译器会编不过这行代码(VS2008之后的版本的都是能够的,以前的版本没试),为何?日志

 

这是由于在模板技术中存在全特化的概念,好比C公司,这个公司根本不想发送明文,也就是说它只有SendEncryptedText()接口,没有SendClearText()。为了使咱们的静态多态仍然可用,咱们这样定义只适用于C公司的MsgSender:code

 1 class CompanyC
 2 {
 3 public:
 4     void SendEncryptedText(){}
 5 };
 6 
 7 template <>
 8 class MsgSender<CompanyC>
 9 {
10 public:
11     void SendEncryptedText(){}
12 };

这时候若是去调用:blog

1 MsgSenderWithLog<CompanyC> MsgSenderC;
2 MsgSenderC.SendClearTextWithLog(); //编译器没法经过编译

这样编译器会报找到SendClearText()的错。正是由于有的编译器考虑到了全特化模板版本能够与普通版本不一样,因此在有继承关系存在时,对直接调用父类的函数给出了不支持的error。但这个error是与编译器相关的,不是必然出现的。继承

为了让更多的编译器放弃这种全特化的忧虑,书上提供了三种解决方法:接口

方法一: 将编译器

 1 void SendClearTextWithLog()
 2 {
 3     // Logs
 4     SendClearText(); // 有的编译器会编不过这段代码
 5 }
 6 改为
 7 void SendClearTextWithLog()
 8 {
 9     // Logs
10     this->SendClearText(); // 这下能编译经过了
11 }

方法二:

在子类中声明using MsgSender<T>::SendClearText;

编译器报error本质是不进行模板父类域的查找,因此这里using了父类的一个函数名,强制编译器对之进行查找。

 

方法三:

将SendClearText()指明为MsgSender<T>::SendClearText()。

 

最后总结一下:

可在derived class template内经过“this->”指涉base class templates内的成员名称,或藉由一个明白写出的“base class资格修饰符”完成。

相关文章
相关标签/搜索