Cómo anular el método estático de la clase de plantilla en la clase derivada

3 minutos de lectura

Tengo un pequeño problema con la anulación de los métodos estáticos de las clases base, pero toda la pregunta es muy complicada y demasiado larga (generalización de la gestión de recursos en el motor del juego), así que aquí hay una versión simplificada:

template<class T>
class base
{
    static void bar()
    { printf("bar"); }
public:
    static void foo()
    { bar(); }
};

class derived : public base<int>
{
    static void bar()
    { printf("baz"); }
};

int main() { derived::foo(); }

El código anterior genera “barra” en mi caso, en lugar de eso, quiero que genere “baz”. ¿Cómo puedo hacer eso? Parece que no importa lo que intente, base::foo() siempre llama a base::bar(). Podría tener un problema con el diseño. Nunca me he encontrado con este problema, ¿cómo puedo resolverlo?

  • No puede anular los métodos estáticos. Puede sobrecargarlos (que es lo que está haciendo aquí), pero solo está recibiendo un despacho estático. Supongo que podrías usar el CRTP.

    – TartánLlama

    11 de diciembre de 2015 a las 11:41

  • Posible duplicado de métodos virtuales estáticos alternativos a c ++

    – jww

    11 de junio de 2017 a las 16:08

Avatar de usuario de YSC
YSC

Lo que está tratando de hacer no se puede lograr con la herencia de clase simple; un método no puede ser ambos static y virtual.

Tu necesitas un static método para poder llamar a una función sin un objeto (una instancia); y tu necesitas bar ser – estar virtual de modo que bar<int>::foo() llamadas derived::bar() cuando se llama desde un derived instancia.

Esos dos rasgos son mutuamente excluyentes. Pero el Patrón de plantilla curiosamente recursivo (CRTP) puede ser una solución aquí:

#include <iostream>

template<class T>
struct base
{
    static void foo()
    {
        T::bar();
    }
};

struct derived : public base<derived>
{
    static void bar()
    {
        std::cout << "derived" << std::endl;
    }
};

int main()
{
    derived::foo();
}

ejemplo en vivo

  • ¡Muchos gracias! me ayudo tu respuesta!

    – ryo

    2 de febrero de 2017 a las 12:06

  • Esta respuesta me voló la cabeza. ¿Cómo sabe el compilador que habrá una barra de método () en la clase T? ¿Comprueba estáticamente cada instancia de base para asegurarse de que se ajuste al uso?

    – mayacoda

    27 de marzo de 2018 a las 15:05

  • @MayaNedeljkovich No es así. Cada vez que una especialización de base<T>::foo se hace (en el programa de ejemplo, la hora exacta base<derived>::foo se llama), se lo hace Mira esto base<T>::foo dar sentido a lo dado T. Esta es la llamada compilación de segundo paso de plantilla (también conocida como “en contexto deducido”). Si no fuera el caso, => error de compilación. Pruébelo usted mismo.

    – YSC

    27 de marzo de 2018 a las 15:08


  • @YSC: ¡+1 por proporcionar ejemplos en vivo dos veces!

    – Trapicki

    11 de julio de 2020 a las 13:30

  • @MayaNedeljkovich Por lo general, en rust podemos usar el rasgo vinculado a los argumentos de la plantilla. En cpp20, parece que hay un concepto similar llamado “concepto”, no soy un maestro de la plantilla de C++, pero creo que stdlib podría ayudar antes de cpp20.

    – Jurado

    13 de octubre a las 1:56

¿Ha sido útil esta solución?