2011-04-20 19 views
22

He estado luchando con este tipo de problema durante mucho tiempo, así que decidí preguntar aquí.Cómo copiar/crear una instancia de clase derivada desde un puntero a una clase base polimórfica?

class Base { 
    virtual ~Base(); 
}; 
class Derived1 : public Base { ... }; 
class Derived2 : public Base { ... }; 
... 

// Copies the instance of derived class pointed by the *base pointer 
Base* CreateCopy(Base* base); 

El método debe devolver una copia creada dinámicamente, o al menos almacenar el objeto en la pila de alguna estructura de datos para evitar "la dirección de vuelta de un temporal" problema.

El enfoque ingenuo para implementar el método anterior estaría utilizando múltiples typeid s o dynamic_cast s en una serie de sentencias if para comprobar para cada posible tipo derivado y luego utilizar el operador new. ¿Hay algún otro enfoque mejor?

P.S .: Sé que este problema se puede evitar utilizando punteros inteligentes, pero estoy interesado en el enfoque minimalista, sin un montón de bibliotecas.

+1

Esto parece un duplicado exacto de esta pregunta: http://stackoverflow.com/questions/5148706/copying-a-polymorphic-object-in-c. Ver la respuesta aceptada por Michael Anderson allí. – Darhuuk

+1

@Darhuuk: No estoy seguro de cuál es la política SO sobre duplicados, pero esta pregunta es un poco diferente. El OP aquí preguntó sobre la forma de resolver este problema, mientras que el OP de esa pregunta preguntó si la clonación es un buen enfoque de C++. Obviamente está relacionado, pero no estoy seguro si es un "duplicado exacto". – ltjax

+0

@Itjax Bastante justo, es solo que la respuesta dada allí es más o menos exactamente lo que el OP está buscando. Aunque supongo que tu respuesta a continuación es aún más conveniente :). – Darhuuk

Respuesta

34

Agregue un virtual Base* clone() const = 0; en su clase base e impleméntelo de forma adecuada en sus clases derivadas. Si su Base no es abstracto, puede llamar su copia-constructor, pero eso es un poco peligroso: si olvida implementarlo en una clase derivada, obtendrá (probablemente no deseado) un corte.

Si no desea duplicar ese código, se puede utilizar el CRTP idiom para implementar la función a través de una plantilla:

template <class Derived> 
class DerivationHelper : public Base 
{ 
public: 
    virtual Base* clone() const 
    { 
    return new Derived(static_cast<const Derived&>(*this)); // call the copy ctor. 
    } 
}; 

class Derived1 : public DerivationHelper <Derived1> { ... }; 
class Derived2 : public DerivationHelper <Derived2> { ... }; 
+4

+1: este es el enfoque canónico. –

1

Una alternativa es tener un puro CreateCopy() método virtual en la base común que se implementa en cada clase derivada.

+0

¿Quiso decir algo como esto: http://ideone.com/FlQ9LF? –

+0

@David Doria: Yeap, excepto que ese fragmento gotea la memoria a lo grande. – sharptooth

Cuestiones relacionadas