2009-04-16 10 views
14

Sé que si deja a un miembro fuera de una lista de inicialización en un constructor sin argumentos, se llamará al constructor predeterminado de ese miembro.Copiar listas de inicialización de constructor

¿Los constructores de copia también llaman al constructor de copia de los miembros, o también llaman al constructor predeterminado?

class myClass { 
    private: 
    someClass a; 
    someOtherClass b; 
    public: 
    myClass() : a(DEFAULT_A) {} //implied is b() 
    myClass(const myClass& mc) : a(mc.a) {} //implied is b(mc.b)??? or is it b()? 
} 
+2

Ver: http://stackoverflow.com/questions/563221/is-there-an-implicit-default-constructor-in-c/563320#563320 –

Respuesta

23

Los constructores de copia explícitamente definidos no llaman a los constructores de copia para los miembros.

Cuando ingresa el cuerpo de un constructor, cada miembro de esa clase se inicializará. Es decir, una vez que llegue al {, se le garantiza que todos sus miembros se hayan inicializado.

A menos que se especifique, los miembros se inicializan por defecto en el orden en que aparecen en la clase. (Y si no pueden serlo, el programa está mal formado). Por lo tanto, si define su propio constructor de copia, ahora depende de usted llamar a cualquier constructor de copia miembro como lo desee.

Aquí es un pequeño programa que puede copiar y pegar en algún lugar y perder el tiempo con:

#include <iostream> 

class Foo { 
public: 
    Foo() { 
     std::cout << "In Foo::Foo()" << std::endl; 
    } 

    Foo(const Foo& rhs) { 
     std::cout << "In Foo::Foo(const Foo&)" << std::endl; 
    } 
}; 

class Bar { 
public: 
    Bar() { 
     std::cout << "In Bar::Bar()" << std::endl; 
    } 

    Bar(const Bar& rhs) { 
     std::cout << "In Bar::Bar(const Bar&)" << std::endl; 
    } 
}; 

class Baz { 
public: 
    Foo foo; 
    Bar bar; 

    Baz() { 
     std::cout << "In Baz::Baz()" << std::endl; 
    } 

    Baz(const Baz& rhs) { 
     std::cout << "In Baz::Baz(const Baz&)" << std::endl; 
    } 
}; 

int main() { 
    Baz baz1; 
    std::cout << "Copying..." << std::endl; 
    Baz baz2(baz1); 
} 

que está, en este grabados:

 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz() 
Copying... 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz(const Baz&) 

Nota que está predeterminado-inicialización de los miembros de Baz.

comentando las constructor de copia explícita, como:

/* 
Baz(const Baz& rhs) { 
    std::cout << "In Baz::Baz(const Baz&)" << std::endl; 
} 
*/ 

La salida será el siguiente:

 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz() 
Copying... 
In Foo::Foo(const Foo&) 
In Bar::Bar(const Bar&) 

llama al constructor de copia en ambos.

Y si reintroducimos Baz 's constructor de copia y copiar explícitamente un solo miembro:

Baz(const Baz& rhs) : 
    foo(rhs.foo) 
{ 
    std::cout << "In Baz::Baz(const Baz&)" << std::endl; 
} 

Obtenemos:

 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz() 
Copying... 
In Foo::Foo(const Foo&) 
In Bar::Bar() 
In Baz::Baz(const Baz&) 

Como se puede ver, una vez que se declara explícitamente un constructor de copia usted son responsables de la copia de todos los miembros de la clase; es tu constructor ahora.

Esto se aplica a todos los constructores, incluidos los constructores de movimiento.

+0

¿Qué sucede si un miembro es un puntero sin formato (por ejemplo, vacío *) o int, doble, etc.? ¿El constructor de copia definido por el usuario asignará 0 a antes de ingresar {si el usuario no asigna nada a estos miembros en la lista de inicialización del constructor de copia? –

+0

@SergeRogatch: si no lo inicializa explícitamente, el valor no se especifica como una variable no inicializada normal, y leerlo es un comportamiento indefinido. Debe inicializar explícitamente los punteros a nulo, ints a 0, etc. – GManNickG

2

Sí. Ctors son ctors.

+0

+1, me ganaste por 2 segundos. :) –

+1

-1: ¿Qué significa "Sí" como respuesta a una pregunta que contiene un "o"? – mmmmmmmm

+1

rstevens, la pregunta fue editada poco después de que Charlie respondiera. Charlie respondió la pregunta original a la perfección. Dicho esto, he editado mi respuesta a continuación y creo que es lo suficientemente buena :) – GManNickG

2

Para cualquier variable miembro que tenga un constructor predeterminado, se invoca el constructor predeterminado si no ha agregado explícitamente ninguna otra llamada de constructor para esa variable miembro en la lista de inicialización.

0

Cuando el compilador proporciona el cctor predeterminado, ¿qué crees que hace el compilador para las variables miembro? Es copia construye él.

En la misma línea, si elctor está definido por el usuario, y si se excluyen algunos miembros, no se pueden dejar sin inicializar. Las invariantes de clase se establecen durante la construcción y deben mantenerse constantemente. Entonces, el compilador hace eso por ti.

+0

-1 lo siento. Una copia predeterminada * proporcionada por el compilador * copiará * cada miembro utilizando el propio copiador de ese miembro (que es una copia bit a bit en el caso de los tipos primitivos). –

+0

Sí, ¡pero estoy diciendo lo mismo! * Default Initilalizes * significa copiar a través del miembro de la tarjeta. – Abhay

+0

Veo lo que dices, pero de hecho el término "inicialización predeterminada" tiene un significado específico y bien definido en el estándar C++, que es inicializar un objeto con el valor predeterminado del tipo (bueno, es un poco más complicado pero de todos modos ...) Entonces su descripción es un poco engañosa. –

1

No hay nada de mágico en un constructor de copia, aparte de que el compilador lo agregará si es necesario. Pero en la forma en que realmente se ejecuta, no hay nada especial: si no dice explícitamente "usar tal y tal constructor", usará el valor predeterminado.

1

No en VC9. No estoy seguro acerca de los demás.

// compiled as: cl /EHsc contest.cpp 
// 
// Output was: 
// Child1() 
// ----- 
// Child1() 
// Child2() 
// Parent() 
// ----- 
// Child1(Child1&) 
// Child2() 
// Parent(Parent&) 

#include <cstdio> 

class Child1 { 
    int x; 
public: 
    static Child1 DEFAULT; 

    Child1(){ 
     x = 0; 
     printf("Child1()\n"); 
    } 

    Child1(Child1 &other){ 
     x = other.x; 
     printf("Child1(Child1&)\n"); 
    } 
}; 

Child1 Child1::DEFAULT; 

class Child2 { 
    int x; 
public: 
    Child2(){ 
     x = 0; 
     printf("Child2()\n"); 
    } 

    Child2(Child2 &other){ 
     x = other.x; 
     printf("Child2(Child2&)\n"); 
    } 
}; 

class Parent { 
    int x; 
    Child1 c1; 
    Child2 c2; 

public: 
    Parent(){ 
     printf("Parent()\n"); 
    } 

    Parent(Parent &other) : c1(Child1::DEFAULT) { 
     printf("Parent(Parent&)\n"); 
    } 
}; 

int main(){ 
    printf("-----\n"); 
    Parent p1; 
    printf("-----\n"); 
    Parent p2(p1); 

    return 0; 
} 
+0

Y la stdout fue? –

2

Para más detalles ver: Is there an implicit default constructor in C++?

corta:

  • compilador generado "por defecto Constructor": utiliza el constructor por defecto de cada miembro.
  • Compilador generado "Copy Constructor": utiliza el constructor de copia de cada miembro.
  • Compilador generado "Operador de asignación": utiliza el operador de asignación de cada miembro.
1

Dependiendo de cómo se inicie el constructor de llamada base, los constructores del miembro se llamarán de la misma manera. Por ejemplo, vamos a empezar con:

struct ABC{ 
    int a; 
    ABC() : a(0) { printf("Default Constructor Called %d\n", a); }; 

    ABC(ABC & other) 
    { 
     a=other.a; 
     printf("Copy constructor Called %d \n" , a) ; 
    }; 
}; 

struct ABCDaddy{ 
    ABC abcchild; 
}; 

Usted puede hacer estas pruebas:

printf("\n\nTest two, where ABC is a member of another structure\n"); 
ABCDaddy aD; 
aD.abcchild.a=2; 

printf("\n Test: ABCDaddy bD=aD; \n"); 
ABCDaddy bD=aD; // Does call the copy constructor of the members of the structure ABCDaddy (ie. the copy constructor of ABC is called) 

printf("\n Test: ABCDaddy cD(aD); \n"); 
ABCDaddy cD(aD); // Does call the copy constructor of the members of the structure ABCDaddy (ie. the copy constructor of ABC is called) 

printf("\n Test: ABCDaddy eD; eD=aD; \n"); 
ABCDaddy eD; 
eD=aD;   // Does NOT call the copy constructor of the members of the structure ABCDaddy (ie. the copy constructor of ABC is not called) 

Salida:

Default Constructor Called 0 

Test: ABCDaddy bD=aD; 
Copy constructor Called 2 

Test: ABCDaddy cD(aD); 
Copy constructor Called 2 

Test: ABCDaddy eD; eD=aD; 
Default Constructor Called 0 

disfrutar.

Cuestiones relacionadas