2009-06-20 6 views
6

considerar:C++: ¿Podrían los constructores de copias polimórficas funcionar?

class A 
{ 
public: 
    A(int val) : m_ValA(val) {} 
    A(const A& rhs) {} 
    int m_ValA; 
}; 

class B : public A 
{ 
public: 
    B(int val4A, int val4B) : A(val4A), m_ValB(val4B) {} 
    B(const B& rhs) : A(rhs), m_ValB(rhs.m_ValB) {} 
    int m_ValB; 
}; 

int main() 
{ 
    A* b1 = new B(1, 2); 
    A* b2 = new A(*b1); // ERROR...but what if it could work? 
    return 0; 
} 

Would C++ romperse si "nueva A (b1)" fue capaz de resolver a la creación de una nueva copia B y devolver una A?

¿Esto podría ser útil?

Respuesta

19

¿Necesita esta funcionalidad, o es solo un experimento mental?

Si necesita hacer esto, el idioma común es tener un método Clone:

class A 
{ 
public: 
    A(int val) : m_ValA(val) {} 
    A(const A& rhs) {} 
    virtual A *Clone() = 0; 
    int m_ValA; 
}; 

class B : public A 
{ 
public: 
    B(int val4A, int val4B) : A(val4A), m_ValB(val4B) {} 
    B(const B& rhs) : A(rhs), m_ValB(rhs.m_ValB) {} 
    A *Clone() { return new B(*this); } 
    int m_ValB; 
}; 

int main() 
{ 
    A* b1 = new B(1, 2); 
    A* b2 = b1->Clone(); 
    return 0; 
} 
+5

1, pero también me gustaría añadir un destructor virtual a la clase;) –

+0

Fue realmente un experimento mental. Y aunque esta es la forma estándar de implementar constructores de copia virtuales, tenía curiosidad por saber por qué el lenguaje no proporciona una forma estandarizada de hacerlo. – 0xC0DEFACE

+0

El retorno covariante es mejor: B * B :: Clon() –

0

Sí. No.

Hay varias formas de implementar la clonación (por ejemplo, el método clone() más o menos estándar, variaciones parametrizadas de fábricas de objetos, con o sin inyección de dependencia configurable) sin cambiar el significado de los programas existentes, o es imposible crear instancias de clases base cuando se conoce una clase derivada dentro de una unidad de compilación.

Los constructores y los destructores son lo suficientemente complejos como para ser entendidos por los principiantes. Inyectar aún más complejidad en ellos sería imprudente.

1

La expresión

new A(*b1) 

ya tiene un significado, suponiendo que tenía la sobrecarga apropiada.

Si se le dio un significado diferente, tendría que proporcionar otra forma de obtener el otro significado. Esta es una especie de sentido dado que ya hay una manera de conseguir el significado que desea:

new B(*b1) 

Y supongo que es más fáciles de interpretar.

+1

Pero el segundo ejemplo supone que usted sabe a priori que 'b1' es de hecho una' B'. – user470379

+0

@ user470379 - absolutamente; mi punto no era que 'nuevo B (* b1)' es la respuesta, era que 'nuevo A (* b1)' no puede ser la respuesta. –

0

Como se señaló anteriormente, hay varias maneras de implementar esto.

Para responder a su pregunta si new A(*b1) devolvió una nueva instancia de B, esto no funcionaría.

int main() 
{ 
    A* b1 = new B(1, 2); 
    A a(*b1); // What size would 'a' be if it was polymorphicly constructed? 
    return 0; 
} 
2

Sólo una pequeña adición a la respuesta por eduffy: En lugar de

class B : public A { 
    ... 
    A *Clone() { return new B(*this); } 
    ... 

};

se puede declarar así:

class B : public A { 
    ... 
    B *Clone() { return new B(*this); } // note: returning B * 
    ... 

};

Todavía es considerado un primordial válida de lo virtual A::Clone(); y es mejor si es llamado directamente a través B *

+0

Impresionante, pero no entiendo por qué es válido? ^^ – Thecheeselover

+0

Porque esos son tipos de retorno covariantes. § 10.3.7 –

Cuestiones relacionadas