El constructor es una función miembro no estática especial de una clase que se utiliza para inicializar objetos de su tipo de clase.

En la definición de un constructor de una clase, lista de inicializadores de miembros especifica los inicializadores para subobjetos base directos y virtuales y miembros de datos no estáticos. (No confundir con std :: initializer_list).

Sintaxis

Los constructores se declaran utilizando declaradores de función miembro de la siguiente forma:

nombre de la clase(lista de parámetros(Opcional))excepto especificaciones(Opcional)attr(Opcional) (1)

Dónde nombre de la clase debe nombrar la clase actual (o instanciación actual de una plantilla de clase) o, cuando se declara en el ámbito del espacio de nombres o en una declaración de amigos, debe ser un nombre de clase calificado.

Los únicos especificadores permitidos en el decl-specifier-seq de una declaración de constructor son amigos, en línea, explicit y constexpr (en particular, no se permite ningún tipo de devolución). Tenga en cuenta que los calificadores cv y ref tampoco están permitidos; La semántica constante y volátil de un objeto en construcción no se activa hasta que se completa el constructor más derivado.

El cuerpo de una definición de función de cualquier constructor, antes de la llave de apertura de la declaración compuesta, puede incluir el lista de inicializadores de miembros, cuya sintaxis es el carácter de dos puntos :, seguido de la lista separada por comas de uno o más inicializadores de miembros, cada uno de los cuales tiene la siguiente sintaxis.

clase-o-identificador(lista-de-expresiones(Opcional)) (1)
clase-o-identificadorbrace-init-list (2) (desde C ++ 11)
paquete de parámetros... (3) (desde C ++ 11)

1) Inicializa la base o miembro nombrado por clase-o-identificador utilizando inicialización directa o, si lista-de-expresiones está vacío, inicialización de valor2) Inicializa la base o miembro nombrado por clase-o-identificador usando la inicialización de lista (que se convierte en inicialización de valor si la lista está vacía y la inicialización de agregado al inicializar un agregado)3) Inicializa múltiples bases usando una expansión de paquete

clase-o-identificador cualquier identificador, nombre de clase o decltype expresión que nombra un miembro de datos no estático, una base directa o virtual, o (para delegar constructores) la clase misma
lista-de-expresiones posiblemente una lista vacía, separada por comas, de los parámetros para pasar al constructor de la base o miembro
lista-inicial-reforzada lista entre llaves de inicializadores separados por comas y listas de inicialización con llaves anidadas
paquete de parámetros nombre de un paquete de parámetros de plantilla variadic
structSint n;S(int);// constructor declarationS():n(7)// constructor definition.// ": n(7)" is the initializer list// ": n(7) " is the function body;S::S(int x): nx// constructor definition. ": nx" is the initializer listintmain()
    S s;// calls S::S()
    S s2(10);// calls S::S(int)

Explicación

Los constructores no tienen nombre y no se pueden llamar directamente. Se invocan cuando tiene lugar la inicialización y se seleccionan de acuerdo con las reglas de inicialización. Los constructores sin explicit especificador son constructores de conversión. Los constructores con un constexpr especificador haga que su tipo sea LiteralType. Los constructores que se pueden llamar sin ningún argumento son constructores predeterminados. Los constructores que toman otro objeto del mismo tipo que el argumento son constructores de copia y constructores de movimiento.

Antes de que comience a ejecutarse la instrucción compuesta que forma el cuerpo de función del constructor, finaliza la inicialización de todas las bases directas, bases virtuales y miembros de datos no estáticos. La lista de inicializadores de miembros es el lugar donde se puede especificar la inicialización no predeterminada de estos objetos. Para los miembros que no se pueden inicializar de forma predeterminada, como los miembros de tipos de referencia y calificados const, se deben especificar los inicializadores de miembros. No se realiza ninguna inicialización para uniones anónimas o miembros variantes que no tienen un inicializador de miembros.

Los inicializadores donde clase-o-identificador Los nombres de una clase base virtual se ignoran durante la ejecución de constructores de cualquier clase que no sea la clase más derivada del objeto que se está construyendo.

Nombres que aparecen en lista-de-expresiones o brace-init-list se evalúan en el ámbito del constructor:

classXint a, b, i, j;public:constint& r;X(int i):r(a)// initializes X::r to refer to X::a, bi// initializes X::b to the value of the parameter i,i(i)// initializes X::i to the value of the parameter i,j(this->i)// initializes X::j to the value of X::i;

Las excepciones que se lanzan desde los inicializadores de miembros pueden ser manejadas por function-try-block.

Las funciones miembro (incluidas las funciones miembro virtuales) se pueden llamar desde inicializadores de miembros, pero el comportamiento no está definido si no todas las bases directas se inicializan en ese punto.

Para las llamadas virtuales (si las bases están inicializadas), se aplican las mismas reglas que las reglas para las llamadas virtuales de constructores y destructores: las funciones miembro virtuales se comportan como si el tipo dinámico de *this es la clase que se está construyendo (el envío dinámico no se propaga hacia abajo en la jerarquía de herencia) y las llamadas virtuales (pero no las llamadas estáticas) a funciones miembro virtuales puras son un comportamiento indefinido.

Si un miembro de datos no estáticos tiene un inicializador de miembro predeterminado y también aparece en una lista de inicializador de miembro, entonces se ejecuta la lista de inicializador de miembro y se ignora el inicializador de miembro predeterminado:

structSint n =42;// default member initializerS():n(7)// will set n to 7, not 42;
(desde C ++ 11)

Los miembros de referencia no se pueden vincular a temporales en una lista de inicializador de miembros:

structAA():v(42)// Errorconstint& v;;

Nota: lo mismo se aplica al inicializador de miembros predeterminado.

(desde C ++ 14)

Constructor delegante

Si el nombre de la clase en sí aparece como clase-o-identificador en la lista de inicializadores de miembros, la lista debe constar únicamente de ese inicializador de miembros; tal constructor se conoce como el delegar constructor, y el constructor seleccionado por el único miembro de la lista de inicializadores es el constructor de destino.

En este caso, el constructor de destino se selecciona mediante la resolución de sobrecarga y se ejecuta primero, luego el control vuelve al constructor que delega y se ejecuta su cuerpo.

La delegación de constructores no puede ser recursiva.

classFoopublic:Foo(char x,int y)Foo(int y):Foo('a', y)// Foo(int) delegates to Foo(char,int);

Heredar constructores

Ver declaración de uso.

(desde C ++ 11)

Orden de inicialización

El orden de los inicializadores de miembros en la lista es irrelevante: el orden real de inicialización es el siguiente:

1) Si el constructor es para la clase más derivada, las clases base virtuales se inicializan en el orden en el que aparecen en profundidad: primero de izquierda a derecha de las declaraciones de clase base (de izquierda a derecha se refiere a la apariencia en base -listas de especificadores)2) Luego, las clases base directas se inicializan en orden de izquierda a derecha tal como aparecen en la lista de especificadores de base de esta clase.3) Luego, los miembros de datos no estáticos se inicializan en el orden de declaración en la definición de clase.4) Finalmente, se ejecuta el cuerpo del constructor.

(Nota: si el orden de inicialización fue controlado por la aparición en las listas de inicializadores de miembros de diferentes constructores, entonces el destructor no podría garantizar que el orden de destrucción sea el inverso del orden de construcción).

Ejemplo

#include#include#includestructBaseint n;;structClass:publicBaseunsignedchar x;unsignedchar y;
    std::mutex m;
    std::lock_guard<std::mutex> lg;
    std::fstream f;
    std::string s;Class(int x ): Base 123,// initialize base classx( x ),// x (member) is initialized with x (parameter)
        y 0,// y initialized to 0
        f"test.cc", std::ios::app,// this takes place after m and lg are initializeds(__func__),//__func__ is available because init-list is a part of constructorlg( m ),// lg uses m, which is already initialized
        m// m is initialized before lg even though it appears last here// empty compound statementClass(double a ):y( a+1),x( y ),// x will be initialized before y, its value here is indeterminatelg( m )// base class constructor does not appear in the list, it is// default-initialized (not the same as if Base() were used, which is value-init)Class()try// function-try block begins before the function body, which includes init list:Class(0.0)//delegate constructor// ...catch(...)// exception occurred on initialization;intmain()
    Class c;
    Class c1(1);
    Class c2(0.1);

Informes de defectos

Los siguientes informes de defectos que cambian el comportamiento se aplicaron retroactivamente a los estándares C ++ publicados anteriormente.

DR Aplicado a Comportamiento según lo publicado Comportamiento correcto
CWG 1696 C ++ 14 los miembros de referencia podrían inicializarse a temporales (cuya vida útil terminaría al final de ctor) tal init está mal formado

Referencias

  • Estándar C ++ 11 (ISO / IEC 14882: 2011):
    • 12.1 Constructores [class.ctor]
    • 12.6.2 Inicializar bases y miembros [class.base.init]
  • Estándar C ++ 98 (ISO / IEC 14882: 1998):
    • 12.1 Constructores [class.ctor]
    • 12.6.2 Inicializar bases y miembros [class.base.init]