es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo borrar una clase derivada de una declaración de puntero de clasebase con CRTP?

Supongamos que tengo un ejemplo de libro de CRTP (patrón de plantilla de recurrencia curiosa) y quiero crear un contenedor de Base* sin especificar la información derivada para recorrer y llamar a interfaces de forma polimórfica.

template<typename T>
class Base
{
public:
    void f()
    {
        static_cast<T*>(this)->f();
    }
};

class Derived1 : public Base<Derived1> {
public:
    void f()
    {
        std::cout << "Derived1::f()\n";
    }
};

class Derived2 : public Base<Derived2> {
public:
    void f()
    {
        std::cout << "Derived2::f()\n";
    }
};

template<typename T>
void apply(Base<T>* ptr) {
    ptr->f();
}


int main() {
    Base<Derived1>* ptr1 = new Derived1;
    Base<Derived2>* ptr2 = new Derived2;
    ptr1->f();
    ptr2->f();
}

Ahora supongamos que quiero crear un std::vector (o cualquier otro contenedor, no relevante para la pregunta) de Base* y recorrer llamando a f, pero el compilador no lo permite ya que necesito especificar el argumento de plantilla de Base, lo que prácticamente hace que tenga un vector de Base<Derived1>* o Base<Derived2>*.

¿Existe alguna forma o truco para deshacerse de este argumento de plantilla y crear una colección de Base* con diferentes tipos dinámicos?
Gracias de antemano.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Una solución consiste en utilizar una clase base común para todas las clases derivadas, y hacer que la función apply tome un puntero a esa clase base en lugar de la clase Base<t>. Por ejemplo:

    class CommonBase {
    public:
        virtual void f() = 0;
    };
    
    template<typename t="">
    class Base : public CommonBase {
    public:
        void f()
        {
            static_cast<t*>(this)->f();
        }
    };
    
    class Derived1 : public Base<derived1> {
    public:
        void f()
        {
            std::cout << "Derived1::f()\n";
        }
    };
    
    class Derived2 : public Base<derived2> {
    public:
        void f()
        {
            std::cout << "Derived2::f()\n";
        }
    };
    
    void apply(CommonBase* ptr) {
        ptr->f();
    }
    
    int main() {
        std::vector<commonbase*> vec;
        vec.push_back(new Derived1);
        vec.push_back(new Derived2);
        for (auto ptr : vec) {
            apply(ptr);
        }
    }
    

    Aquí, introducimos una nueva clase CommonBase que tiene una función virtual f(). Esto nos permite crear un vector de CommonBase* que puede contener punteros a cualquier clase que herede de CommonBase. Modificamos la clase Base para que herede de CommonBase, y hacemos que la función apply tome un puntero a CommonBase en lugar de Base<t>. Ahora podemos recorrer el vector de CommonBase* y llamar a la función f() en cada elemento, lo que llamará a la función sobrescrita adecuada en la clase derivada.</commonbase></t>

Comments are closed.