2009-05-29 9 views

Respuesta

202

Para miembros de la clase POD, no hace ninguna diferencia, es solo una cuestión de estilo. Para los miembros de la clase que son clases, entonces evita una llamada innecesaria a un constructor predeterminado. Considere lo siguiente:

class A 
{ 
public: 
    A() { x = 0; } 
    A(int x_) { x = x_; } 
    int x; 
}; 

class B 
{ 
public: 
    B() 
    { 
     a.x = 3; 
    } 
private: 
    A a; 
}; 

En este caso, el constructor de B se llama al constructor por defecto para A, y luego inicializar a.x a 3. Una mejor manera sería que B 's constructor para llamar directamente A' s constructor de la lista de inicialización:

B() 
    : a(3) 
{ 
} 

Esto sólo sería llamar A 's A(int) constructor y no su constructor por defecto. En este ejemplo, la diferencia es insignificante, pero imagine que si el constructor predeterminado de A hiciera más, como asignar memoria o abrir archivos. No querrás hacer eso innecesariamente.

Por otra parte, si una clase no tiene un constructor por defecto, o si tiene una variable const miembro, usted debe utilizar una lista de inicialización:

class A 
{ 
public: 
    A(int x_) { x = x_; } 
    int x; 
} 

class B 
{ 
public: 
    B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list; 
    {     // it is an error not to do so 
    } 
private: 
    A a; 
    const int y; 
}; 
+0

miembros de la clase, es decir clases puede ser POD, también –

+1

una necesidad también para el caso de una referencia importante – 4pie0

+1

Por qué no usar "a (3);" o "a = A (3);" en el cuerpo del constructor por defecto de B? – Sergey

34

Aparte de las razones de cumplimiento mencionadas anteriormente, si su clase almacena referencias a objetos pasados ​​como parámetros de constructor o su clase tiene variables const, entonces no tiene otra opción que usar listas de inicializadores.

+6

Lo mismo vale para los miembros de const yo creo. –

6

Junto a los problemas de rendimiento, hay otro muy importante que llamaría mantenibilidad de código y extensibilidad.

Si una T es POD y comienza a preferir la lista de inicialización, si una vez T cambiará a un tipo que no sea POD, no necesitará cambiar nada en la inicialización para evitar llamadas innecesarias al constructor porque ya está optimizado .

Si el tipo T tiene un constructor predeterminado y uno o más constructores definidos por el usuario y una vez que decide eliminar u ocultar el predeterminado, entonces si se utilizó la lista de inicialización, no necesita actualizar el código si su usuario constructores definidos porque ya están implementados correctamente.

Lo mismo con los miembros o miembros de referencia constante, digamos que inicialmente T se define de la siguiente manera:

struct T 
{ 
    T() { a = 5; } 
private: 
    int a; 
}; 

A continuación, decidir para calificar a una como const, si desea utilizar la lista de inicialización desde el principio, entonces este era un solo cambio de línea, pero después de la T define como anteriormente, sino que también requiere que cavar la definición del constructor para quitar la asignación:

struct T 
{ 
    T() : a(5) {} // 2. that requires changes here too 
private: 
    const int a; // 1. one line change 
}; 

no es un secreto que el mantenimiento es mucho más fácil y menos propenso a errores si el código fue escrito no por un "código monje" y "pero por un ingeniero que toma decisiones basadas en una consideración más profunda sobre lo que está haciendo.

+2

+1 para "código mono" – Invictus

4

Antes de que se ejecute el cuerpo del constructor, se invocan todos los constructores para su clase principal y luego para sus campos. Por defecto, los constructores sin argumento son invocados. Las listas de inicialización le permiten elegir a qué constructor se llama y qué argumentos recibe ese constructor.

Si tiene una referencia o un campo const, o si una de las clases utilizadas no tiene un constructor predeterminado, debe usar una lista de inicialización.

2
// Without Initializer List 
class MyClass { 
    Type variable; 
public: 
    MyClass(Type a) { // Assume that Type is an already 
        // declared class and it has appropriate 
        // constructors and operators 
     variable = a; 
    } 
}; 

Aquí sigue compilador siguientes pasos para crear un objeto de tipo MiClase constructor
1. El tipo se llama primero para “a”.
2. El operador de asignación de “Tipo” se llama el interior del cuerpo de MiClase() constructor para asignar

variable = a; 
  1. Y, por último destructor de “Tipo” se llama para "a" ya que sale del alcance.

    Consideremos ahora el mismo código con MiClase() constructor inicializador Lista

    // With Initializer List 
    class MyClass { 
    Type variable; 
    public: 
    MyClass(Type a):variable(a) { // Assume that Type is an already 
           // declared class and it has appropriate 
           // constructors and operators 
    } 
    }; 
    

    Con la lista de inicialización, los siguientes pasos son seguidos por el compilador:

    1. Copia constructor de la clase “tipo” es llamado a inicializar: variable (a). Los argumentos en la lista de inicializadores se utilizan para copiar constructo "variable" directamente.
    2. Destructor de "Tipo" se llama para "a" ya que sale del alcance.
+2

Si bien este fragmento de código puede resolver la pregunta, incluir una explicación del código realmente ayuda a mejorar la calidad de su publicación. Recuerde que usted está respondiendo la pregunta a los lectores en el futuro, y es posible que esas personas no sepan los motivos de su sugerencia de código. Por favor, intente no saturar su código con comentarios explicativos, ¡esto reduce la legibilidad tanto del código como de las explicaciones! http://meta.stackexchange.com/q/114762/308249 – davejal

+2

Por favor, escriba su propio entendimiento o simplemente comparta el enlace a la fuente original (aquí, geeksforgeeks.com) en lugar de simplemente copiar y pegar. – yuvi

10
  1. inicialización de clase base

Una razón importante para el uso de lista de inicialización del constructor que no se menciona en las respuestas aquí es la inicialización de la clase base.

Según el orden de construcción, la clase base debe construirse antes de la clase infantil. Sin lista de inicializadores de constructor, esto es posible si su clase base tiene un constructor predeterminado que se llamará justo antes de ingresar al constructor de la clase secundaria.

Pero, si su clase base tiene solo un constructor parametrizado, entonces debe usar la lista de inicializadores del constructor para asegurarse de que su clase base se inicialice antes de la clase secundaria.

  1. inicialización de subobjetos que sólo tienen constructores parametrizados

  2. Eficiencia

Uso de lista de inicialización del constructor, inicializar miembros de datos a el estado exacto que necesita en su código en lugar de inicializarlo primero en su estado predeterminado & y luego cambiar su estado al que necesita en tu codigo.

  1. miembros de datos estáticos const no Inicialización

Si los miembros de datos const no estáticos en su clase tienen constructores por defecto & que no utiliza la lista de inicialización del constructor , no podrá inicializarlos en el estado deseado, ya que se inicializarán en su estado predeterminado.

  1. inicialización de los miembros de datos de referencia

miembros de datos de referencia debe ser inicializado cuando entra compilador constructor como referencias no pueden ser simplemente declararon & inicializado después. Esto solo es posible con la lista de inicializadores del constructor.

0

Sintaxis:

class Sample 
    { 
    public: 
     int Sam_x; 
     int Sam_y; 

    Sample(): Sam_x(1), Sam_y(2)  /* Classname: Initialization List */ 
    { 
      // Constructor body 
    } 
    }; 

Necesidad de la lista de inicialización:

class Sample 
{ 
    public: 
     int Sam_x; 
     int Sam_y; 

    Sample()  */* Object and variables are created - i.e.:declaration of variables */* 
    { // Constructor body starts 

     Sam_x = 1;  */* Defining a value to the variable */* 
     Sam_y = 2; 

    } // Constructor body ends 
    }; 

en el programa anterior, Cuando se ejecuta el constructor de la clase, Sam_x y Sam_y se crean. Luego, en el cuerpo del constructor, se definen las variables de datos de los miembros.

Los casos de uso:

  1. Const y de referencia variables en una Clase

En C, las variables deben ser definidos durante la creación. de la misma manera en C++, debemos inicializar la variable Const y Reference durante la creación del objeto usando la lista de Inicialización. si hacemos la inicialización después de la creación del objeto (cuerpo constructor interno), obtendremos un error de tiempo de compilación.

  1. objetos miembro de Sample1 (bases) de clase que no tiene constructor por defecto

    class Sample1 
    { 
        int i; 
        public: 
        Sample1 (int temp) 
        { 
         i = temp; 
        } 
    }; 
    
        // Class Sample2 contains object of Sample1 
    class Sample2 
    { 
        Sample1 a; 
        public: 
        Sample2 (int x): a(x)  /* Initializer list must be used */ 
        { 
    
        } 
    }; 
    

al crear el objeto de clase derivada que internamente llamadas clase derivada constructor y convoca al constructor de la clase base (predeterminado). si la clase base no tiene un constructor predeterminado, el usuario obtendrá un error de tiempo de compilación.Para evitar, debemos tener bien

1. Default constructor of Sample1 class 
2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program) 
  1. nombre del parámetro y datos de los miembros

    del constructor de la clase de una clase son iguales:

    class Sample3 { 
        int i;   /* Member variable name : i */ 
        public: 
        Sample3 (int i) /* Local variable name : i */ 
        { 
         i = i; 
         print(i); /* Local variable: Prints the correct value which we passed in constructor */ 
        } 
        int getI() const 
        { 
         print(i); /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/ 
         return i; 
        } 
    }; 
    

Como todos saber, la variable local tiene la prioridad más alta que la variable global si ambas variables tienen el mismo nombre. En este caso, el programa considera el valor "i" {variable izquierda y derecha. es decir: i = i} como variable local en el constructor Sample3() y la variable miembro de la clase (i) tiene anulación. Para evitar, debemos utilizar cualquiera

1. Initialization list 
    2. this operator. 
Cuestiones relacionadas