Effective C ++ Point 43: Modèles et programmation générique (les noms dans le processus d'apprentissage classe de base de modèle)

Tout d'abord, le modèle, la classe dérivée ne peut pas appeler le modèle de fonction membre de classe de base

  • Dans la classe de modèle, si une classe dérivée appelle la méthode de classe de base dans son approche, alors ce code pourrait ne pas compiler
  • Note (clé):
    • Ce phénomène est associé au compilateur, auteur de C ++ efficace erreur de compilation
    • Utiliser VS compilé sans erreur
    • Donc, le problème est lié avec le compilateur

spectacles de démonstration

  • Supposons maintenant qu'il existe un tel système de classe:
    • Nous avons un certain nombre d'entreprises, comprenant deux fonctions membres peuvent être utilisés à l' information de transmission à la société (transmission d'un message crypté, un message est envoyé sans cryptage)
    • MsgExpéditeur une classe, dans laquelle il y a deux fonctions membres, un certain nombre d'entreprises qui peuvent être définies, puis la société de l'organe d'appel de méthode à l' information de transmission à
    • MsgInfo une classe de messages encapsulent (ce n'est pas classe importante)
  • Code est la suivante:
//公司类
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);
    }
};
  • Maintenant , nous ajoutons une classe classe dérivée de msgExpéditeur, nous voulons regarder le journal enregistre chaque fois que l'envoi de messages. Par conséquent , défini comme suit:
template<typename Company>
class LoggingMsgSender:public MsgSender<Company>{
public:
    void sendClearMsg(const MsgInfo& info)
    {
        //记录一下日志
        sendClear(info); //调用基类的方法发送消息,这段代码可能无法编译通过
        //记录一下日志
    }

    void sendSecretMsg(const MsgInfo& info)
    {    
        //记录一下日志
        sendSecret(msg); //调用基类的方法发送消息,这段代码可能无法编译通过
        //记录一下日志
    }
};
  • Pour une raison quelconque le code ci-dessus que le compilateur va mal tourner:
    • erreur de compilation: Lorsque la classe a rencontré le type de définition de modèle de classe LoggingMsgSender, il ne sait pas quel type LoggingMsgSender Hériter de la classe, parce qu'il n'y a pas spécifique instancié
    • Par conséquent, lorsqu'il est compilé en fonction membre LoggingMsgSender, qui ne sait pas s'il y a une classe de base de la fonction sendClear ()

Pour les mauvaises raisons, nous faisons une affaire de démonstration

  • Décrit ci-dessus, appeler la fonction membre de la classe de base de la classe dérivée lors de la compilation de l'erreur du compilateur. Maintenant, nous regardons un cas de présentation, plus vous pouvez comprendre la raison de l'erreur
  • Par exemple:
    • Maintenant , nous avons une société Z, qui reçoit le cryptage des messages que des supports, de sorte que la société Z définit uniquement la fonction sendEncrypted ()
    • Z parce que la société n'envoyer des messages cryptés, donc pour msgExpéditeur modèle de classe précédemment défini ne convient pas à notre société Z, et Z parce que la société n'a pas besoin d'envoyer un message commun. Par conséquent, nous avons besoin d' un modèle de spécialisation complète de la classe Z msgExpéditeur pour l'entreprise
    • Code est la suivante:
//公司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);
    }
};
  • Au- dessus en ce qui concerne la spécialisation msgExpéditeur était pleine, maintenant, regardons les raisons pour lesquelles le modèle de classe LoggingMsgSender ci - dessus se plaindra:
    • Si le type de la classe de base msgExpéditeur LoggingMsgSender est CompanyZ, le code suivant est erroné le
    •  Parce que CompanyZ pas fonction sendClear
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);
    }
};
  • mauvaises raisons Résumé:
    • Nous dans la préparation de la classe non-modèle, lorsque vous appelez une fonction dans une classe dérivée, si la fonction ne se trouve pas dans cette classe, il ira à la portée de la fonction Recherche de la classe de base
    • Mais la classe de modèle est pas le même, lorsque vous appelez une fonction dans une classe dérivée, si la fonction ne se trouve pas dans cette classe, il ne continue pas à chercher la classe de base

En second lieu, la solution de ce qui précède trois méthodes erreur

La première méthode

  • Utilisez ce pointeur: utiliser ce pointeur pour appeler ces fonctions pour atteindre ces fonctions pour dire au compilateur luimême appartient à la classe (ils vont hériter de la classe de base aprèscompilation)
  • Par exemple:
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);
        //记录一下日志
    }
};

La seconde méthode

  • Utiliser l'aide déclarative

  • Notez que cette différence en utilisant la classe déclarative et non-modèle:

    • Dans la classe non-modèle, une classe dérivée pour empêcher l'utilisation Masquer les méthodes héritées, la méthode dans la classe de base peut être trouvée dans la classe dérivée

    • Dans la classe de modèle à l'aide de l'utiliser est de permettre au compilateur de trouver cette fonction dans la classe de base

  • Par exemple:

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);
        //记录一下日志
    }
};

La troisième méthode

  • Clair que la fonction appelée est situé dans la classe de base
  • Cette méthode est déconseillée, car: la fonction appelée peut être une fonction virtuelle, ce modificateur sera fermé « comportementliaison virtuelle »
  • Par exemple:
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);
        //记录一下日志
    }
};
  • Résumé:
    • Les trois méthodes ci-dessus décrit peuvent être résolus par le compilateur permet méthode de classe de modèle
    • Pour la version complète, il peut aussi être compilateur spécial, sera donnée jusqu'à ce que la méthode d'appel n'existe pas quand . Par exemplevous obtiendrez une erreur lorsappel deversion complète msgExpéditeur de spécialisation de la fonction de ceprécède CompanyZ. Par exemple:
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;
}

En troisième lieu, le résumé

  • Par dans les modèles de classe dérivée « ce » nom de membre référent dans les modèles de classe de base, écrire ou à comprendre par une « qualification de classe de base modificateur » complet
Publié 1525 articles originaux · louange won 1084 · Vues 450000 +

Je suppose que tu aimes

Origine blog.csdn.net/qq_41453285/article/details/104850617
conseillé
Classement