enclosed - initialize vector c++ 11
¿Cuál es esta extraña sintaxis de miembros de colon(":") en el constructor? (12)
Recientemente he visto un ejemplo como el siguiente:
#include <iostream>
class Foo {
public:
int bar;
Foo(int num): bar(num) {};
};
int main(void) {
std::cout << Foo(42).bar << std::endl;
return 0;
}
¿Qué significa esto extraño : bar(num)
? De alguna manera parece inicializar la variable miembro, pero nunca antes había visto esta sintaxis. Parece una función / llamada de constructor pero para un int
? No tiene sentido para mí. Tal vez alguien me pueda iluminar. Y, por cierto, ¿existen otras características de lenguaje esotérico como esta, que nunca encontrarás en un libro normal de C ++?
Aún no se menciona en este hilo: desde C ++ 11, la lista de inicialización de miembros puede usar la inicialización de lista (también conocida como "inicialización uniforme", "inicialización reforzada"):
Foo(int num): bar{num} {}
que tiene la misma semántica que la inicialización de listas en otros contextos.
El otro ya le explicó que la sintaxis que observa se llama "lista de inicializadores de constructores". Esta sintaxis le permite inicializar subobjetos base y subobjetos miembros de la clase (en lugar de permitirles inicializar por defecto o permanecer sin inicializar).
Solo quiero señalar que la sintaxis de que, como dijiste, "parece una llamada del constructor", no es necesariamente una llamada del constructor. En el lenguaje C ++, la sintaxis ()
es solo una forma estándar de sintaxis de inicialización . Se interpreta de manera diferente para los diferentes tipos. Para los tipos de clase con constructor definido por el usuario significa una cosa (es una llamada del constructor), para los tipos de clase sin constructor definido por el usuario significa otra cosa (llamada inicialización de valor ) para empty ()
) y para los tipos que no son de clase nuevamente significa algo diferente (ya que los tipos que no son de clase no tienen constructores).
En su caso el miembro de datos tiene tipo int
. int
no es un tipo de clase, por lo que no tiene constructor. Para el tipo int
esta sintaxis significa simplemente "inicializar bar
con el valor de num
" y eso es todo. Se hace así, directamente, sin constructores involucrados, ya que, una vez más, int
no es un tipo de clase por lo que no puede tener ningún constructor.
Es una lista de inicialización de miembros . Debe encontrar información al respecto en cualquier buen libro de C ++ .
En la mayoría de los casos, debe inicializar todos los objetos miembros en la lista de inicialización de miembros (sin embargo, tenga en cuenta las excepciones enumeradas al final de la entrada de Preguntas frecuentes).
El punto para llevar de la entrada de preguntas frecuentes es que,
En igualdad de condiciones, su código se ejecutará más rápido si utiliza las listas de inicialización en lugar de la asignación.
Es una lista de inicialización para el constructor. En lugar de construir de forma predeterminada x
, y
, y
luego asignarles los valores recibidos en los parámetros, esos miembros se inicializarán con esos valores de inmediato. Esto puede no parecer terriblemente útil para los float
, pero puede ser un gran ahorro de tiempo con clases personalizadas que son caras de construir.
Esa es la inicialización del constructor. Es la forma correcta de inicializar miembros en un constructor de clase, ya que evita que se invoque el constructor predeterminado.
Considere estos dos ejemplos:
// Example 1
Foo(Bar b)
{
bar = b;
}
// Example 2
Foo(Bar b)
: bar(b)
{
}
En el ejemplo 1:
Bar bar(); // default constructor
bar = b; // assignment
En el ejemplo 2:
Bar bar(b) // copy constructor
Se trata de eficiencia.
Esta es una lista de inicialización. Se inicializarán los miembros antes de que se ejecute el cuerpo del constructor. Considerar
class Foo {
public:
string str;
Foo(string &p)
{
str = p;
};
};
vs
class Foo {
public:
string str;
Foo(string &p): str(p) {};
};
En el primer ejemplo, str se inicializará por su constructor sin argumentos
string();
Ante el cuerpo del constructor foo. Dentro del constructor foo, el
string& operator=( const string& s );
se llamará en ''str'' como haces str = p;
Wheras en el segundo ejemplo, str se inicializará directamente llamando a su constructor
string( const string& s );
con ''p'' como argumento.
Esto no es oscuro, es la sintaxis de la lista de inicialización de C ++
Básicamente, en tu caso, x
se inicializará con _x
, y
con _y
, z
con _z
.
Esto se llama una lista de inicialización. Es una forma alternativa de inicializar los miembros de la clase. Hay ventajas al usar esto en lugar de simplemente asignar nuevos valores a los miembros en el cuerpo del constructor, pero si tiene miembros de clase que son constantes o referencias , deben inicializarse.
No sé cómo podrías perderte esto, es bastante básico. Esa es la sintaxis para inicializar variables de miembros o constructores de clases base. Funciona para tipos de datos antiguos y sencillos, así como para objetos de clase.
Usted es correcto, esta es de hecho una manera de inicializar las variables miembro. No estoy seguro de que esto sea beneficioso, aparte de expresar claramente que se trata de una inicialización. Tener una "barra = num" dentro del código podría moverse, borrarse o malinterpretarse mucho más fácilmente.
hay otro ''beneficio''
Si el tipo de variable miembro no admite la inicialización nula o si es una referencia (que no se puede inicializar nulo), no tiene más remedio que proporcionar una lista de inicialización.
Foo(int num): bar(num)
Esta construcción se denomina Lista de inicialización de miembros en C ++.
Simplemente dicho, inicializa su bar
miembros a un valor num
.
¿Cuál es la diferencia entre la inicialización y la asignación dentro de un constructor?
Inicialización de miembros:
Foo(int num): bar(num) {};
Asignación de miembros:
Foo(int num)
{
bar = num;
}
Hay una diferencia significativa entre inicializar un miembro utilizando la lista de inicializadores de miembro y asignarle un valor dentro del cuerpo del constructor.
Cuando inicializa los campos a través de la lista de inicializadores de miembro, se llamará a los constructores una vez y el objeto se construirá e inicializará en una operación.
Si utiliza la asignación , los campos se inicializarán primero con los constructores predeterminados y luego se reasignarán (a través del operador de asignación) con los valores reales.
Como ve, hay una sobrecarga adicional de creación y asignación en este último, que podría ser considerable para las clases definidas por el usuario.
Cost of Member Initialization = Object Construction
Cost of Member Assignment = Object Construction + Assignment
Este último es en realidad equivalente a:
Foo(int num) : bar() {bar = num;}
Mientras que el primero es equivalente a solo:
Foo(int num): bar(num){}
Para un integrante (su ejemplo de código) o miembros de clase POD no hay una sobrecarga práctica.
¿Cuándo TIENE QUE usar la lista de inicializador de miembros?
Tendrá (más que forzado) usar una lista de inicializador de miembros si:
- Tu clase tiene un miembro de referencia.
- Tu clase tiene un miembro const no estático o
- El miembro de tu clase no tiene un constructor predeterminado o
- Para la inicialización de los miembros de la clase base o
- Cuando el nombre del parámetro del constructor es el mismo que el miembro de datos (esto no es realmente DEBE)
Un ejemplo de código:
class MyClass
{
public:
//Reference member, has to be Initialized in Member Initializer List
int &i;
int b;
//Non static const member, must be Initialized in Member Initializer List
const int k;
//Constructor’s parameter name b is same as class data member
//Other way is to use this->b to refer to data member
MyClass(int a, int b, int c):i(a),b(b),k(c)
{
//Without Member Initializer
//this->b = b;
}
};
class MyClass2:public MyClass
{
public:
int p;
int q;
MyClass2(int x,int y,int z,int l,int m):MyClass(x,y,z),p(l),q(m)
{
}
};
int main()
{
int x = 10;
int y = 20;
int z = 30;
MyClass obj(x,y,z);
int l = 40;
int m = 50;
MyClass2 obj2(x,y,z,l,m);
return 0;
}
-
MyClass2
no tiene un constructor predeterminado, por lo que debe inicializarse a través de la lista de inicializadores de miembros. - La clase base
MyClass
no tiene un constructor predeterminado, por lo tanto, para inicializar su miembro, será necesario usar la Lista de inicialización de miembros.
Puntos importantes a tener en cuenta al utilizar las listas de inicialización de miembros:
Las variables de miembro de clase siempre se inicializan en el orden en que se declaran en la clase.
No se inicializan en el orden en que se especifican en la Lista de inicializadores de miembros.
En resumen, la lista de inicialización de miembros no determina el orden de inicialización.
Dado lo anterior, siempre es una buena práctica mantener el mismo orden de miembros para la inicialización del Miembro que el orden en el que se declaran en la definición de clase. Esto se debe a que los compiladores no advierten si las dos órdenes son diferentes, pero un usuario relativamente nuevo podría confundir la lista de Inicializadores de miembros como el orden de inicialización y escribir algo de código dependiendo de eso.