Pregunta

Almacenamiento de objetos en un vector heterogéneo con objetos asignados por pila

Hola,

Digamos que tengo una clase abstracta CA, derivada en CA1, CA2 y quizás otras.

Quiero poner objetos de estos tipos derivados en un vector, que incorporé en una clase CB. Para obtener el polimorfismo correcto, necesito almacenar un vector de punteros:

class CB
{
    std::vector <CA*> v;
};

Ahora, digamos que tengo la siguiente función principal:

int main()
{
    CB b;
    CA1 a1;
    CA2 a2;
    b.Store( a1 );
    b.Store( a2 );
}

¿Cómo escribo el método void CB :: Store (const CA & amp;) de una manera simple, para que los objetos almacenados sobrevivan cuando los objetos originales se destruyen (lo que no ocurre en el ejemplo simple arriba).

Mi problema es que primero necesito copiar objetos en el montón antes de copiar su dirección en el vector, pero ¿cómo puedo crear un objeto de un tipo derivado? Claro, podría usar RTTI y buscar todos los tipos posibles, crear y asignar un puntero y copiar (con la conversión adecuada) el objeto en el espacio asignado antes de insertarlo en el vector. Pero esto parece bastante complicado, ¿no?

¿Hay alguna manera más simple?

(¡Y sin usar la asignación dinámica en el principal!)

¿Fue útil?

Solución

Comúnmente, proporcionará una función de clonación:

struct CA
{
    virtual CA *clone(void) const = 0;
    virtual ~CA() {} // And so on for base classes.
}

struct CA1 : public CA
{
    virtual CA *clone(void) const
    {
        return new CA1(*this);
    }
}

struct CA2 : public CA
{
    virtual CA *clone(void) const
    {
        return new CA2(*this);
    }
}

Esto se llama constructor virtual , puede construir copias de objetos en tiempo de ejecución:

void CB::Store(const CA& pObject)
{
    CA *cloned = pObject.clone();
}

Debería considerar usar el Boost.Pointer Container biblioteca. Su código sería:

boost::ptr_vector<CA> objects;

void CB::Store(const CA& pObject)
{
    objects.push_back(pObject->clone());
}

Y ahora no tiene necesidad de administrar la memoria usted mismo. La biblioteca también respeta las funciones de clonación y lo llamará al hacer copias de sus objetos. Tutorial aquí .

Otros consejos

Parece que necesita una función clone () en su clase abstracta que implementarán sus clases derivadas.

class CA
{
   public:
   virtual ~CA() {}
   virtual CA* clone() const = 0;
}

class CA1 : public CA
{ 
    public:
    virtual CA *clone() const
    {
       return new CA1(*this);
    }
};

Una posibilidad sería crear plantillas en el tipo de argumento:

class CB
{
public:
    template<class T>
    void Store(const T& t)
    {
         v.push_back(new T(t));
    }

private:
    std::vector <CA*> v;
};

Sin embargo, una advertencia: a diferencia del " clone () " solución publicada por otros, esto es propenso a rebanar. Por ejemplo, esto funciona bien:

CB b;
CA1 a1;
CA2 a2;
b.Store(a1);
b.Store(a2);

Pero esto no:

CA1 a1;
CA* a = &a1;
b.Store(*a); //Ouch! this creates a new CA, not a CA1

Dar un copiador protegido a CA evita dicho uso indebido. Sin embargo, si subclasificamos más la CA1, el problema vuelve.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top