Efectiva C ++ Artículo 43: Modelos y programación genérica (Los nombres en la clase de aprendizaje proceso de base de la plantilla)

En primer lugar, la plantilla, la clase derivada no puede llamar a la plantilla de función miembro de la clase de base

  • En la clase de plantilla, si una clase derivada llama al método de la clase base en su enfoque, a continuación, este código podría no recopilar
  • Nota (Key):
    • Este fenómeno está asociado con el compilador, autor de efectivo C ++ error de tiempo de compilación
    • Uso VS compilado sin errores
    • Por lo que el problema está relacionado con el compilador

espectáculos de demostración

  • Supongamos ahora que existe tal sistema de una clase:
    • Tenemos un número de empresas, que comprende la función de dos miembros puede utilizarse a la información de transmisión a la empresa (transmisión de un mensaje cifrado, un mensaje es enviado sin cifrado)
    • MsgSender una clase, en la que hay dos funciones miembro, un número de empresas que se pueden definir, a continuación, la compañía del miembro de llamada a un método de transmisión a la información a
    • MsgInfo una clase de mensajes encapsular (esto no es importante clase)
  • Código es el siguiente:
//公司类
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);
    }
};
  • Ahora añadimos una clase MsgSender clase derivada, queremos mirar el registro de registros cada vez que al enviar mensajes. Por lo tanto se define como sigue:
template<typename Company>
class LoggingMsgSender:public MsgSender<Company>{
public:
    void sendClearMsg(const MsgInfo& info)
    {
        //记录一下日志
        sendClear(info); //调用基类的方法发送消息,这段代码可能无法编译通过
        //记录一下日志
    }

    void sendSecretMsg(const MsgInfo& info)
    {    
        //记录一下日志
        sendSecret(msg); //调用基类的方法发送消息,这段代码可能无法编译通过
        //记录一下日志
    }
};
  • Por alguna razón, el código anterior que el compilador va a salir mal:
    • error de tiempo de compilación: Cuando la clase se reunió LoggingMsgSender plantilla de clase definición de tipo, que no sabe LoggingMsgSender hereda qué tipo de clase, porque no hay una instancia específica
    • Por lo tanto, cuando se compila en función miembro LoggingMsgSender, que no sabe si existe una función sendClear () de la clase base

Porque en las razones equivocadas, hacemos un caso de demostración

  • Descrito anteriormente, llamar a la función miembro de la clase base de la clase derivada en tiempo de compilación el error del compilador. Ahora nos centraremos en un caso de presentación, más para que pueda entender el motivo del error
  • Por ejemplo:
    • Ahora tenemos una empresa Z, que recibe el cifrado sólo los mensajes de apoyo, por lo que la empresa Z sólo define la función sendEncrypted ()
    • Z debido a que la empresa sólo enviar mensajes cifrados, por lo que para MsgSender plantilla de clase previamente definida no es adecuado para nuestra empresa Z, y Z porque la empresa no tiene que enviar un mensaje común. Por lo tanto, necesitamos una plantilla de clase Z MsgSender completa especialización para la empresa
    • Código es el siguiente:
//公司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);
    }
};
  • Anteriormente con respecto a MsgSender eran especialización completa, ahora vamos a ver por qué la plantilla de clase LoggingMsgSender anterior se quejará:
    • Si el tipo de la clase base MsgSender LoggingMsgSender es CompanyZ, a continuación, el siguiente código es el mal
    •  Debido CompanyZ no tiene función 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);
    }
};
  • Resumen razones equivocadas:
    • Nosotros, en la preparación de la clase no molde, cuando se llama a una función en una clase derivada, si la función no se encuentra en esta clase, irá al alcance función de búsqueda de la clase base
    • Pero la clase de plantilla no es lo mismo, cuando se llama a una función en una clase derivada, si la función no se encuentra en esta clase, por lo que no continúa en busca de la clase base

En segundo lugar, la solución de los anteriores error tres métodos

El primer método

  • Utilice este puntero: utilizar este puntero para llamar a estas funciones para lograr estas funciones para indicar al compilador en sí pertenece a la clase (que van a heredar de la clase base después de la compilación)
  • Por ejemplo:
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);
        //记录一下日志
    }
};

El segundo método

  • Utilice usando declarativa

  • Tenga en cuenta que esta diferencia usando la clase declarativa y no molde:

    • En la clase no molde, una clase derivada para evitar el uso de Ocultar heredado métodos, el método en la clase base se puede encontrar en la clase derivada

    • En la clase de plantilla mediante el uso es para permitir que el compilador para encontrar esta función en la clase base

  • Por ejemplo:

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

El tercer método

  • Claro que la función llamada se encuentra en la clase base
  • No se recomienda este método, debido a que: la función llamada puede ser una función virtual, este modificador se cerrará "comportamiento de enlace virtual"
  • Por ejemplo:
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);
        //记录一下日志
    }
};
  • resumen:
    • Los tres métodos más arriba describe pueden ser resueltos por el compilador permite método clase de plantilla
    • Para la versión completa, también puede ser compilador especial, será entregado hasta que el método llamado no existe cuando . Por ejemplo, usted obtendrá un error cuando se llama a la función sendClearMsg versión completa especialización MsgSender de lo anterior CompanyZ. Por ejemplo:
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 tercer lugar, el resumen

  • Por las plantillas de clase derivados "este" nombre de usuario referente en la base de plantillas de clase, escribir o entender por una "cualificación clase base modificador" completos
Liberadas 1525 artículos originales · ganado elogios 1084 · Vistas de 450.000 +

Supongo que te gusta

Origin blog.csdn.net/qq_41453285/article/details/104850617
Recomendado
Clasificación