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.

Convirtiendo un puntero a puntero a Downcasting

Estoy aprendiendo polimorfismo en C++ y no puedo convertir un puntero a un puntero. Tengo una clase Base y una clase Derived que extiende Base. Y quiero crear un conjunto de objetos Derived usando una función Base **derivedFactory(size_t size). Intenté hacer Base** array = new Derived*[size]; pero el compilador dice que no puede convertir de Derived* a Base*. Así que intenté lo siguiente:

“`c++
Base *derivedFactory(size_t size)
{
Base *array = new Derived[size];

for (size_t idx = 0; idx < size; ++idx)
{
    Derived derived = Derived();
    array[idx] = derived;
}

Base** arrayBase = &array;

return arrayBase;

}


Y compila. Pero luego, cuando quiero acceder a todos los objetos Derived, el main.cc lanza un `Segmentation fault (core dumped)`. Ejecuta `hello(cout)` pero luego lanza antes de terminar la primera iteración del bucle. ¿Podrías ayudarme, por favor? Main.cc ```c++ #include "main.ih" int main() { Base **bp = derivedFactory(10); for (size_t idx = 0; idx <= 10; ++idx) { bp[idx]->hello(cout); cout << "No imprime\n"; } } </code></pre> Clase Base: ```c++ class Base { private: virtual void vHello(std::ostream &out) { out << "Hola desde Base\n"; } public: void hello(std::ostream &out) { vHello(out); } };

Clase Derived: ```c++ class Derived : public Base { std::string d_text; private: void vHello(std::ostream &out) override { out << d_text << '\n'; } public: Derived() { d_text = "hola desde Derived"; } virtual ~Derived() {} };

¡Gracias!

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    El problema en el código está relacionado con la gestión de memoria de los objetos asignados dinámicamente. Al crear el objeto array, se crea un puntero a un objeto Derived, pero el puntero es de tipo Base*, lo cual es válido ya que Derived es una subclase de Base.

    Sin embargo, cuando el bucle inicializa los objetos Derived, crea una copia de un objeto Derived y lo asigna al puntero Base. Esto crea un problema de “object slicing” donde los valores y el comportamiento específicos de Derived se pierden, y solo queda la parte Base.

    Además, al usar Base** arrayBase = &array;, se crea un puntero a un puntero donde el valor es la dirección de array. Dado que array es una variable local de la función, cuando sale del ámbito al finalizar la función, arrayBase se convierte en un puntero colgante y acceder a su valor resultará en un comportamiento indefinido como fallas de segmentación y cierres inesperados.

    Un enfoque mejor para crear un array de objetos Derived que se pueda acceder de forma polimórfica como punteros Base es utilizar un std::vector en lugar de arrays de estilo C. Aquí hay un ejemplo de implementación:

    “`c++
    #include

    std::vector<base> derivedFactory(size_t size)
    {
    std::vector<base
    > vec;

    for (size_t idx = 0; idx < size; ++idx)
    {
        vec.push_back(new Derived());
    }
    
    return vec;
    

    }


    Esta implementación crea un objeto `std::vector` que contiene punteros `Base*`, y luego inicializa cada elemento con un objeto `new Derived()`. De esta manera, los objetos `Derived` se crean de forma dinámica y no se cortan, y el `std::vector` se encarga de la gestión de memoria. La función `main` puede utilizar el `std::vector` devuelto para acceder a cada objeto `Base` de forma polimórfica: ```c++ int main() { std::vector<base*> vec = derivedFactory(10); for (Base* ptr : vec) { ptr->hello(cout); } for (Base* ptr : vec) { delete ptr; } return 0; }

    Ten en cuenta que después de acceder a los objetos, debes eliminarlos explícitamente para evitar fugas de memoria, ya que fueron creados de forma dinámica con new.

    Con estos cambios, el código debería funcionar correctamente sin ningún tipo de fallos de segmentación o cierres inesperados.</base></base></base*>

Comments are closed.