2012-05-23 14 views
22

considere la siguiente situación (simplificado):¿Se pueden usar variables miembro para inicializar otros miembros en una lista de inicialización?

class Foo 
{ 
private: 
    int evenA; 
    int evenB; 
    int evenSum; 
public: 
    Foo(int a, int b) : evenA(a-(a%2)), evenB(b-(b%2)), evenSum(evenA+evenB) 
    { 
    } 
}; 

Cuando i instanciate Foo así:

Foo foo(1,3); 

continuación evena es 0, evenB es 2, pero se evenSum ser inicializado a 2?

Intenté esto en mi plataforma actual (iOS) y parece funcionar, pero no estoy seguro de si este código es portátil.

Gracias por su ayuda!

+0

Esta es una de las esquinas peligrosas en C++. – iammilind

+0

Codepad es un gran lugar para comprobar tales cosas: http://codepad.org/uFgZpkwN –

+0

@Agent_L: Eso no le dirá si el código es portátil. –

Respuesta

27

Este es bien definido y portátil, pero es potencialmente propenso a errores.

Los miembros se inicializan en el orden en que se declaran en el cuerpo de la clase, no en el orden en que se enumeran en la lista de inicialización. Entonces, si cambia el cuerpo de la clase, este código puede fallar silenciosamente (aunque muchos compiladores detectarán esto y emitirán una advertencia).


1. Desde [class.base.init] en la norma C++ (s):

En un constructor no delegar, el producto de inicialización en el siguiente orden:

  • Primero, y solo para el constructor de la clase más derivada (1.8), las clases base virtuales se inicializan en el orden en que aparecen en un cruce de profundidad de izquierda a derecha del gráfico acíclico dirigido de clases base, donde de izquierda a derecha”es el orden de aparición de las clases base en la base especificador-lista de la clase derivada.
  • A continuación, las clases de base directas se inicializan en orden de declaración tal como aparecen en la base-especificador-list (independientemente del orden de los mem-initializers).
  • A continuación, los miembros de datos no estáticos se inicializan en el orden en que se declararon en la definición de clase (nuevamente, independientemente del orden de los iniciadores de memoria).
  • Finalmente, se ejecuta la instrucción compuesta del cuerpo del constructor.

(resaltado es mío.)

Esta sección de la norma pasa luego a dar un ejemplo de la utilización de variables miembro para inicializar otras variables miembro.

+0

ok entonces si Foo tiene una barra de clase base (herencia pública no virtual) y pongo el constructor Bars en la lista de inicialización, siempre se ejecutará antes de todos los inicializadores de miembros, incluso si lo coloco al final de la lista de inicialización? – Pontomedon

+0

@Pontomedon: Sí. Los constructores de la clase base siempre se invocan primero (incluso si no están en la lista). –

6

Los miembros se inicializan en el orden en que se declaran en la definición de la clase. Siempre que su lista de inicializadores siga este orden, debería estar bien.

0

Esto también se compiló sin error en g ++ 4.0.3 (6 años ahora).

Estoy seguro de que esto compilará bien en cualquier compilador razonablemente reciente.

8

Sí, indique que ya se han construido. Simplemente no olvide que el orden de construcción es el orden de las declaraciones en la definición de clase , no el orden de los inicializadores en el constructor . Y que el compilador generalmente no le dirá si usa una variable antes de que se haya construido. En su caso, por ejemplo, si se mueve evenSum a la parte superior de la clase, que ha indefinido comportamiento (porque su inicializador utiliza miembros sin inicializar), incluso aunque en su constructor, inicializar evenA y evenB léxico antes evenSum.

Cuestiones relacionadas