Proceso de creación en C++ con respecto a las variables miembro y la llamada al constructor.

Me encuentro con un error extraño cuando se llama a un constructor para una de mis clases. Esencialmente, lo que estoy haciendo es esto:

Tengo una clase "A", que tiene dos variables miembro de tipo "B", "C". "C" tiene para ser iniciado con un miembro de tipo "B". Entonces el constructor tiene que ser:

A::A():
c(b)
{}

Esto funciona bien si la clase se presenta como:

class A
{
   B b;
   C c;
}

Pero falla si la clase se presenta como:

class A
{
   C c;
   B b;
}

Lo primero que supuse fue que, por supuesto, b debe crearse antes que c si voy a inicializar c(b) en el constructor. Aunque no sé si esto es correcto. se llama el constructor antes se asigna alguna variable miembro? ¿O las variables miembro a las que se hace referencia en el constructor se asignan primero y luego las variables miembro restantes sin referencia se asignan al final del constructor (como, por ejemplo, si hubiera otra variable miembro "C c2" que no tiene referencia en el constructor)?

Estoy en Visual Studio 2010.

preguntado el 03 de mayo de 12 a las 22:05

5 Respuestas

Entonces, la forma en que esto funciona es que:

  1. Comienza la construcción de su objeto.
  2. Las clases base no virtuales se construyen en orden de declaración.
  3. Las clases base virtuales se construyen en orden de declaración.
  4. Se crea la parte de la clase actual (inicializando cualquier vtable y tal).
  5. Las variables miembro se construyen en orden de aparición en la declaración de clase, no en la lista de inicializadores.
  6. Se ejecuta el cuerpo de su constructor.
  7. La construcción de su objeto está completa.

Podría estar equivocado acerca de la ubicación del n. ° 3, rara vez uso bases virtuales y rara vez escribo código que dependa de estas cosas. ¿Por qué? Porque es complicado y dicho código es extremadamente frágil.

La destrucción ocurre exactamente en el orden opuesto.

contestado el 03 de mayo de 12 a las 22:05

Sus miembros se inicializan en el orden en que aparecen en la definición de su clase. En su segundo ejemplo, b no se ha inicializado cuando inicializa c.

Mi compilador me advierte si los pongo fuera de servicio en los inicializadores de miembros.

contestado el 03 de mayo de 12 a las 22:05

Está bien. Entonces, ¿se hace referencia a todas las variables miembro en la parte superior de la llamada del constructor (incluso si no se inicializa explícitamente) exactamente en el orden en que aparecen en la definición de clase? Como por ejemplo, el constructor es esencialmente A::A():b(),c(b){} en el primer ejemplo, incluso si no pongo explícitamente "b()" allí. - programador

La respuesta es correcta, sin embargo, probablemente debería hacer una distinción entre la construcción de objetos y la inicialización de objetos. - Jesse bueno

@chris: Por curiosidad, ¿qué compilador estás usando? Estoy en VS2010 y no obtuve uno que me hubiera ayudado a localizar mi problema más rápido. - programador

@JesseGood, buen punto. No tengo una explicación particularmente efectiva en este momento. - Chris

@coderunner, CCG 4.6.2. Estoy bastante seguro de que hace esto. Sé que lo hace si cambio el orden. También creo que esto es con -WeffC++ o cualquiera que sea la bandera. - Chris

Los miembros siempre se construyen en el orden de declaración dentro de la clase.

Así:

class A
{
   B b;
   C c;
}

Funciona bien cuando pasa b después de que se haya construido por completo.
Mientras que si haces esto:

class A
{
   C c;
   B b;
}

Entonces estás construyendo C usando una B que no ha sido construida. Si está pasando por valor, esto probablemente romperá el constructor de copia. Si pasa por referencia, entonces si se usa dentro del constructor C, entonces está usando un objeto no inicializado de tipo 'B'

contestado el 03 de mayo de 12 a las 22:05

El orden de la clase constructora depende del orden dentro de la definición de su clase. El segundo ejemplo no funciona porque aún no se llamó al constructor de clase B.

contestado el 03 de mayo de 12 a las 22:05

Solo para aclarar, dijiste:

Tengo una clase "A", que tiene dos variables miembro de tipo "B", "C". "C" debe iniciarse con un miembro de tipo "B". Entonces el constructor tiene que ser:

Pero tu código:

A::A()
: c(b) 
{
} 

Dice inicializar c con la variable miembro b, no la tipo of B como dice su redacción.

Quizás quieras:

A::A()
: c(B()) 
{
} 

¿en lugar?

contestado el 03 de mayo de 12 a las 22:05

No "miembro de tipo B" significan lo mismo (a diferencia de "tipo B")? ¿Quieres asegurarte de que no me falta algo semánticamente aquí? - programador

Acabo de ver tu edición. No, por la forma en que está configurado el programa, necesito b y c como variables miembro. - programador

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.