2012-03-27 5 views
18

¿Podemos hacer que un constructor de copia de clase sea virtual en C++? ¿Cómo utilizar?¿Podemos hacer un constructor de copia de clase virtual en C++

+4

Suponiendo que se pudiera ... ¿a qué tipo debe enviarse la llamada del constructor? –

+1

Duplicado de http://stackoverflow.com/questions/733360/why-do-we-not-have-a-virtual-constructor-in-c –

+0

@ DavidRodríguez-dribeas: Ese es un buen punto. Creo que debería ser una respuesta, ya que también explica la razón de ser – Nawaz

Respuesta

18

No, los constructores no pueden ser virtuales.

C++ 03 - 12,1 Constructors

4) Un constructor no será virtual (10.3) o static (9.4). [...]

Si necesita algo como esto, puede buscar el idioma del constructor virtual here.

+0

su enlace está prohibido – Arne

+0

@Arne gracias por señalarlo. He actualizado el enlace. –

+0

gracias por actualizarlo. – Arne

0

Nunca, no será posible en C++.

1

No. C++ al ser un lenguaje estático, no tiene sentido para el compilador de C++ crear un objeto polimórficamente. El compilador debe conocer el tipo de clase para crear el objeto. En otras palabras, qué tipo de objeto crearse es una decisión de tiempo de compilación desde la perspectiva del compilador de C++. Si hacemos el constructor virtual, el compilador marca un error.

+1

No del todo cierto, vea el patrón abstracto de fábrica. –

5

No, no puedes.

Además, todo el concepto no tiene sentido. Las funciones virtuales son funciones que se envían en función del valor de un objeto (el tipo dinámico del objeto). Cuando se llama a un constructor, el objeto aún no tiene un valor (porque aún no se ha construido). Por lo tanto, posiblemente no se produzca ningún despacho virtual.

Piénselo. ¿Qué semántica tendría tal constructor?

1

No se puede porque la memoria está asignada antes de llamar al constructor en función del tamaño del nuevo tipo, no del operando de copia. Y si funcionara, sería un caso especial que el polimorfismo invertido para una serie de construcciones de lenguaje.

Pero eso no significa que no se pueda hacer con un poco de magia C++. :)

Hay un par de casos en los que es increíblemente útil, la serialización de clases que no son POD, por ejemplo. Este ejemplo crea un constructor de copia virtual que funciona con la colocación nueva.

Advertencia: este es un ejemplo que puede ayudar a algunos usuarios con problemas específicos. No hagas esto en código de propósito general. Se bloqueará si la memoria asignada para la nueva clase es más pequeña que la clase derivada. La mejor (y única) forma segura de utilizar esto es si está administrando su propia memoria de clase y utilizando la ubicación nueva.

class VirtualBase 
{ 
public: 
    VirtualBase() {} 
    virtual ~VirtualBase() {} 

    VirtualBase(const VirtualBase& copy) 
    { 
     copy.VirtualPlacementCopyConstructor(this); 
    } 

    virtual void VirtualPlacementCopyConstructor(void*) const {} 
}; 

class Derived :: public VirtualBase 
{ 
public: 
    ... 

    Derived(const Derived& copy) : ... don't call baseclass and make an infinite loop 
    { 
    } 

protected: 
    void VirtualPlacementCopyConstructor(void* place) const 
    { 
     new (place) Derived(*this); 
    } 
}; 
+0

Esto no se compilará, incluso si lo arregla para compilarlo, la implementación está completamente rota. Todos los miembros de 'Derived' sufrirán una doble inicialización. Esto podría funcionar con algunos tipos simples, pero claramente resulta en un comportamiento indefinido. El "constructor" necesitaría ser 'void VirtualPlacementCopyConstructor (VirtualBase * place) const {auto d = dynamic_cast (place); if (d) {d-> ~ Derived(); nuevo (d) Derivado (* esto); }} ' –

+0

Ahora debería ser obvio cuál es el problema: el' VirtualPlacementCopyConstructor' se invoca demasiado pronto, cuando el tipo de la clase copiada en -tarea no es 'Derived' aún. Por lo tanto, el destructor tampoco hará lo correcto, y obtendrá un comportamiento indefinido en abundancia. Si reemplaza 'dynamic_cast' con' static_cast', las cosas funcionarán para los tipos de POD, y eso es todo. Tan pronto como añada, p. un miembro de 'std :: string', las cosas se romperán (peor aún: no siempre se romperá, por lo que te sacarás el pelo). –

Cuestiones relacionadas