[TOC]
When a templated class is used as a base class, there are areas to be aware of. As an example, suppose you now write a program that sends information to a different company, the information is either translated into a password, or it is the original text, during compilation to determine which company to send to which company, using the template method:
classcompanya{ Public:voidSendcleartext (Const STD::string& msg);voidSendencryted (Const STD::string& msg); ...... };classcompanyb{ Public:voidSendcleartext (Const STD::string& msg);voidSendencryted (Const STD::string& msg); ...... }; ......//There are some companies classMsginfo{...};//used to hold information for future generation of information Template<TypeNameCompany>classmsgsender{ Public: ......//structural destructors and other functions voidSendclear (Constmsginfo& info) {STD::stringMsg//Generate information based on infoCompany C; C.sendcleartext (msg); }voidSendsecart (Constmsginfo& info) {...} };
This is a good practice, but if you want to log every time you send out the information, you can derive the derived class, plus the logged log
template<typename Company> classpublic MsgSender<Company> { public: ……//析构构造等 void SendClearMsg(const MsgInfo& info) { //发送前的信息写到log sendClear(info);//调用base class函数,这段代码无法通过编译 //传送后信息写到log } };
In a derived class, sendclearmsg differs from the Sendclear in base class, which is a good design to avoid hiding the inherited name, and also avoids redefining an inherited non-virtual function. However, compilation cannot pass because the compiler does not see the Sendclear function.
Because when the compiler encounters the class template Loggingmsgsender definition, it does not know what class it inherits from, because company in Msgsender is a parameter, and before Loggingmsgsender is materialized, You don't know exactly what it is, and you don't know what class Msgsender is, and you don't know if it has a sendclear function. (Note that you can use the parameter-fpermissive parameter in g++ to compile, but not recommended)
To make the problem more specific, suppose there's a class companyz that insists on using encrypted communication
classCompanyZ{ pubic: void sendEncryted(const std::sting& msg); …… };
Companyz There is no sendclear function, General Msgsender template is not suitable for companyz, then we can produce a Companyz special version for Msgsender
template<> class MsgSender<CompanyZ>{ public: voidsendSecret(const MsgInfo& infof) {……} …… };
The initial template<>
representation is the Msgsender template for the special version, which is used when the template argument is Companyz. This is the so-called template full-specification (total templates specialization): Msgsender is specific to the type Companyz, and is a comprehensive special, that is, once the type parameter is Companyz, No other template parameters are available to change.
And take a look at the Loggingmsgsender just now.
template<typename Company> classpublic MsgSender<Company> { public: ……//析构构造等 void SendClearMsg(const MsgInfo& info) { //发送前的信息写到log sendClear(info);//如实Company是CompanyZ,那么这个函数不存在 //传送后信息写到log } };
If Company=companyz, then the Sendclear function does not exist. C + + refuses to call this function because it knows that the base class template may be special, and that the specific version may not provide the same interface as the generic template. So it tends to refuse to look for inherited names in the Templatized base classes (templated base class). When we step from Object oriented C + + to template C + +, inheritance is not as unimpeded as it used to be.
Now it's time to discuss how to solve the problem that cannot be compiled. We must have some way to invalidate C + + "Do not enter templatized base class watch" behavior. There are three ways
1. Add "this->" before the base class function calls the action
template<typename Company> classpublic MsgSender<Company> { public: ……//析构构造等 void SendClearMsg(const MsgInfo& info) { //发送前的信息写到log this->sendClear(info); //传送后信息写到log } };
2, using the use of declarative, somewhat similar to * * clause **33.
template<typename Company> classpublic MsgSender<Company> { public: ……//析构构造等 uinsg MsgSender<Company>::sendClear;//告诉编译器,假设sendClear位于base class内 void SendClearMsg(const MsgInfo& info) { //发送前的信息写到log sendClear(info);//可以编译通过,假设sendClear将被继承 //传送后信息写到log } };
To add, the situation here is different from the * * clause **33, where the hidden base class name is not brought into a derived class scope, but the compiler does not enter the base class scope for the lookup, and through the using tells the compiler, ask it to find it.
3. Understand that the function being called is within the base class
template<typename Company> classpublic MsgSender<Company> { public: ……//析构构造等 void SendClearMsg(const MsgInfo& info) { //发送前的信息写到log MsgSender<Company>::sendClear(info);//可以编译通过,假设sendClear被继承 //传送后信息写到log } };
This practice uses the explicit qualifier modifier (explicit qualification), which turns off the virtual binding behavior.
Look back at the above three practices, the same principle: to the compiler promised that "any special version of the base class template will support its general (generalization) version of the interface provided". Such a commitment is required when the compiler parses a derived class template such as Loggingmsgsender. But if the promise is not fulfilled later, the compiler will give the truth a fair bit. For example, later in the source code:
LoggingMsgSender<CompanyZ> zMsgSender; MsgInfo msgData; zMsgSender.sendClearMsg(msgData);//错误,无法编译通过
At the point where the sendclearmsg is called, the compiler is until the base class is a template-specific version, and it does not provide the SENDCLEARMSG function until this special version.
To summarize, this article discusses that the compiler's diagnostic time may occur early in the face of invalid references referring to the base class member (when parsing the derived class template definition), may also occur in the late (when the template is materialized by a specific value template argument). C + + prefers to diagnose earlier, which is why when base classes is materialized from the template, it assumes that there is no reason for the content of base classes.
Summarize
- The name of the member within the base class templates can be referred to within the derived class templates by this->, or by a clear write base class qualifier modifier.
"Effective C + +": Clause 43: Learning to handle names within a templated base class