Effective C ++ Item 43: Templates and Generic Programming (The names in the learning process template base class)

First, the template, the derived class can not call the base class member function template

  • In the template class, if a derived class calls the base class method in its approach, then this code might not compile
  • Note (Key):
    • This phenomenon is associated with the compiler, author of Effective C ++ compile time error
    • Use VS compiled without error
    • So the problem is related with the compiler

Demonstration shows

  • Suppose now that there is such a class system:
    • We have a number of corporate, comprising two members function may be used to transmit information to the company (transmission of a encrypted message, a message is sent without encryption)
    • MsgSender a class, wherein there are two member functions, a number of companies that can be defined, then the method call member's company to transmit information to
    • MsgInfo a class to encapsulate messages (this is not important class)
  • code show as below:
//公司类
class CompanyA {
public:
    void sendCleartext(const std::string& msg); //向公司发送未加密信息
    void sendEncrypted(const std::string& msg); //向公司发送加密信息
};

class MsgInfo {}; //封装信息的类

//发送信息类
template<typename Company>
class MsgSender {
public:
    //在其中定义公司A,并调用公司A的sendCleartext()函数向公司A发送信息
    void sendClear(const MsgInfo& info)
    {
        std::string msg;
        CompanyA a;
        a.sendCleartext(msg);
    }

    //同上,只是发送加密信息
    void sendSecret(const MsgInfo& info)
    {
        std::string msg;
        CompanyA a;
        a.sendEncrypted(msg);
    }
};
  • Now we add a derived class MsgSender class, we want to look at the log records every time when sending messages. Therefore defined as follows:
template<typename Company>
class LoggingMsgSender:public MsgSender<Company>{
public:
    void sendClearMsg(const MsgInfo& info)
    {
        //记录一下日志
        sendClear(info); //调用基类的方法发送消息,这段代码可能无法编译通过
        //记录一下日志
    }

    void sendSecretMsg(const MsgInfo& info)
    {    
        //记录一下日志
        sendSecret(msg); //调用基类的方法发送消息,这段代码可能无法编译通过
        //记录一下日志
    }
};
  • For some reason the above code that the compiler will go wrong:
    • Compile-time error: When the class met LoggingMsgSender class template definition type, it does not know LoggingMsgSender inherit what type of class, because there is no specific instantiated
    • Therefore, when compiled into LoggingMsgSender member function, which does not know whether there is a base class sendClear () function

For in the wrong reasons, we do a demo case

  • Described above, call the base class member function of the derived class at compile time the compiler error. Now we look at a presentation case, more so you can understand the reason for the error
  • E.g:
    • Now we have a company Z, which receives messages only supports encryption, so the company Z only defines sendEncrypted () function
    • Z because the company only send encrypted messages, so for MsgSender previously defined class template is not suitable for our company Z, and Z because the company does not need to send a common message. Therefore, we need a full specialization Z MsgSender class template for the company
    • code show as below:
//公司Z,只接收加密消息
class CompanyZ {
public:
    void sendEncrypted(const std::string& msg);
};

//针对于公司Z的全特化版本,发送加密消息
template<>
class MsgSender<CompanyZ> {
public:
    void sendSecret(const MsgInfo& info)
    {
        std::string msg;
        CompanyZ z;
        z.sendEncrypted(msg);
    }
};
  • Above with respect to MsgSender were full specialization, now let's look at why the above LoggingMsgSender class template will complain:
    • If the type of the base class MsgSender LoggingMsgSender is CompanyZ, then the following code is wrong the
    •  Because CompanyZ not have sendClear function
template<typename Company>
class LoggingMsgSender:public MsgSender<Company>{
public:
    //如果Company的类型为CompanyZ,,那么此处会出错,因为CompanyZ不拥有sendClear函数
    void sendClearMsg(const MsgInfo& info)
    {
        sendClear(info);
    }
    void sendSecretMsg(const MsgInfo& info)
    {
        sendSecret(info);
    }
};
  • Wrong reasons Summary:
    • We in the preparation of non-template class, when you call a function in a derived class, if the function is not found in this class, it will go to the Find function scope of the base class
    • But the template class is not the same, when you call a function in a derived class, if the function is not found in this class, so it does not continue to look for the base class

Second, the solution of the above three methods error

the first method

  • Use this pointer: use this pointer to call these functions to achieve these functions to tell the compiler itself belongs to the class (they will inherit from the base class after compilation)
  • E.g:
template<typename Company>
class LoggingMsgSender:public MsgSender<Company>{
public:
    void sendClearMsg(const MsgInfo& info)
    {
        //记录一下日志
        this->sendClear(info);
        //记录一下日志
    }
    void sendSecretMsg(const MsgInfo& info)
    {    
        //记录一下日志
        this->sendSecret(info);
        //记录一下日志
    }
};

The second method

  • Use using declarative

  • Note that this difference using declarative and non-template class:

    • In the non-template class, a derived class to prevent using Hide inherited methods, the method in the base class can be found in the derived class

    • In the template class using using it is to allow the compiler to find this function in the base class

  • E.g:

template<typename Company>
class LoggingMsgSender:public MsgSender<Company>{
public:
    using MsgSender<Company>::sendClearMsg;
    using MsgSender<Company>::sendSecretMsg;

    void sendClearMsg(const MsgInfo& info)
    {
        //记录一下日志
        sendClear(info);
        //记录一下日志
    }
    void sendSecretMsg(const MsgInfo& info)
    {    
        //记录一下日志
        sendSecret(info);
        //记录一下日志
    }
};

The third method

  • Clear that the called function is located in the base class
  • This method is not recommended, because: the called function may be a virtual function, this modifier will be closed "virtual binding behavior"
  • E.g:
template<typename Company>
class LoggingMsgSender:public MsgSender<Company>{
public:
    void sendClearMsg(const MsgInfo& info)
    {
        //记录一下日志
        sgSender<Company>::sendClear(info);
        //记录一下日志
    }
    void sendSecretMsg(const MsgInfo& info)
    {    
        //记录一下日志
        sgSender<Company>::sendSecret(info);
        //记录一下日志
    }
};
  • to sum up:
    • The above describes three methods can be solved by the compiler allows template class method
    • For the full version, it can also be special compiler, will be given until the call method does not exist when . For example you'll get an error when calling the function sendClearMsg full specialization MsgSender version of the above CompanyZ. E.g:
class CompanyZ { };
class MsgInfo {};
template<typename Company>
class MsgSender { };

//全特化版本
template<>
class MsgSender<CompanyZ> {
public:
    void sendSecret(const MsgInfo& info)
    {
        std::string msg;
        CompanyZ z;
        z.sendEncrypted(msg);
    }
};

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

int main()
{
    //此段代码仍然可以编译通过,即使CompanyZ不支持sendClearMsg
    LoggingMsgSender<CompanyZ> zMsgSender;
    
    MsgInfo msgData;
    zMsgSender.sendSecretMsg(msgData);
    //zMsgSender.sendClearMsg(msgData); //不能调用这一句,否则报错
	return 0;
}

Third, the summary

  • By in the derived class templates "this" referent member name in the base class templates, write or understand by a "base class qualifications modifier" complete
Released 1525 original articles · won praise 1084 · Views 450,000 +

Guess you like

Origin blog.csdn.net/qq_41453285/article/details/104850617