2012-01-07 13 views
16

Esto podría ser una pregunta con una respuesta obvia o un duplicado. Si es así, lo siento, lo eliminaré.¿Por qué los constructores de copia no están "encadenados" como constructores o destructores predeterminados?

¿Por qué los constructores de copia no están encadenados (como los ctors o dtors predeterminados) para que se llame al constructor de copia de la clase base antes de llamar al constructor de copia de la clase derivada? Con los constructores de copia y los destructores, se llaman en una cadena de base a derivada y derivada a base, respectivamente. ¿Por qué no es este el caso para los constructores de copia? Por ejemplo, este código:

class Base { 
public: 
    Base() : basedata(rand()) { } 

    Base(const Base& src) : basedata(src.basedata) { 
     cout << "Base::Base(const Base&)" << endl; 
    } 

    void printdata() { 
     cout << basedata << endl; 
    } 

private: 
    int basedata; 
}; 

class Derived : public Base { 
public: 
    Derived() { } 

    Derived(const Derived& d) { 
     cout << "Derived::Derived(const Derived&)" << endl; 
    } 
}; 


srand(time(0)); 


Derived d1;  // basedata is initialised to rand() thanks to Base::Base() 

d1.printdata(); // prints the random number 

Derived d2 = d1; // basedata is initialised to rand() again from Base::Base() 
       // Derived::Derived(const Derived&) is called but not 
       // Base::Base(const Base&) 

d2.printdata(); // prints a different random number 

El constructor de copia no (no puede) realmente hacer una copia del objeto, porque no pueden acceder a Derived::Derived(const Derived&)basedata para cambiarlo.

¿Hay algo fundamental que me falta acerca de los constructores de copia para que mi modelo mental sea incorrecto, o hay algún motivo arcano (o no misterioso) para este diseño?

+0

@ybungalobill ha demostrado que es posible, y bastante fácil. Creo que su pregunta es "¿por qué no están encadenados *** automáticamente?" –

+0

@ AaronMcDaid Sí, esa es mi pregunta, pero también se ha respondido a continuación –

+0

@BenVoigt Sí, me preguntaba por qué no se escribe explícitamente, como un constructor explícitamente escrito. Pero esta pregunta ya fue respondida hace un tiempo –

Respuesta

17

El constructor de copia no (no) realmente hacer una copia del objeto, porque no pueden acceder a Derived::Derived(const Derived&)pdata para cambiarlo.

seguro de que puede:

Derived(const Derived& d) 
    : Base(d) 
{ 
    cout << "Derived::Derived(const B&)" << endl; 
} 

Si no se especifica un constructor de la clase base en la lista de inicialización, el constructor por defecto se llama. Si desea llamar a un constructor que no sea el constructor predeterminado, debe especificar qué constructor (y con qué argumentos) desea llamar.

En cuanto a por qué este es el caso: ¿por qué debería un constructor de copia ser diferente de cualquier otro constructor? Como un ejemplo de un problema práctico:

struct Base 
{ 
    Base() { } 
    Base(Base volatile&) { } // (1) 
    Base(Base const&) { } // (2) 
}; 

struct Derived : Base 
{ 
    Derived(Derived&) { } 
}; 

¿Cuál de los constructores de copia Base le esperaría la llamada al constructor Derived copia?

+0

Parece que es el diferente. ¿Por qué el constructor predeterminado debe ser diferente de cualquier otro constructor? –

+1

Porque solo puede haber un constructor predeterminado. –

+2

El constructor predeterminado no es diferente de los otros. Para todos los constructores, a menos que una clase base se especifique explícitamente en la lista de inicializadores, se construirá por defecto, al igual que todos los miembros que no están especificados en la lista de inicializadores se construirán por defecto. – DRH

3

Puede:

Derived(const Derived& d) : Base(d) { 
    cout << "Derived::Derived(const B&)" << endl; 
} 

Esto llama al constructor de copia en el BaseBase subobjeto de d.

La respuesta a "por qué" no lo sé. Pero generalmente no hay respuesta. El comité simplemente tuvo que elegir una opción o la otra. Esto parece más consistente con el resto del idioma, donde, por ejemplo, Derived(int x) no llamará automáticamente al Base(x).

+0

Ah, me olvidé de esta característica, pero ¿por qué no es ésta la predeterminada? –

+3

@Seth: el constructor de copias predeterminado SÍ copia todos los subobjetos, incluidas las clases base, llamando a sus constructores de copia –

+0

@BenVoigt lo siento , Quise decir por qué no es el comportamiento predeterminado de las copiadoras auto escritas, no por qué no es lo que hace la copiadora predeterminada. –

2

Eso es porque cada constructor llama al constructor por defecto base por defecto:

Derived(const Derived& d) { 
    cout << "Derived::Derived(const B&)" << endl; 
} 

llamarán Base().

Esto está definido por la norma. Por mi parte, lo prefiero así en lugar de llamar al constructor de copias en la clase. Por supuesto, puede llamarlo de manera explícita.

Cuestiones relacionadas