Constructores por defecto
Un constructor por defecto es un constructor que se puede llamar sin argumentos (ya sea definido con una lista de parámetros vacía, o con argumentos por defecto proporcionados para cada parámetro). Un tipo con un constructor público por defecto es DefaultConstructible.
[editar] Sintaxis
nombre_de_clase ( ) ;
|
(1) | ||||||||
nombre_de_clase :: nombre_de_clase ( ) cuerpo
|
(2) | ||||||||
nombre_de_clase() = delete ;
|
(3) | (desde C++11) | |||||||
nombre_de_clase() = default ;
|
(4) | (desde C++11) | |||||||
nombre_de_clase :: nombre_de_clase ( ) = default ;
|
(5) | (desde C++11) | |||||||
Donde nombre_de_clase debe denominar la clase actual (o la instanciación actual de una plantilla de clase), o, cuando se declara en un ámbito de espacio de nombres o en una declaración friend
, debe ser un nombre de clase calificado.
[editar] Explicación
Los constructores por defecto se llaman durante las inicializaciones por defecto y las inicializaciones por valor.
[editar] Constructor por defecto implícitamente declarado
Si no se proporcionan constructores de cualquier tipo declarados por el usuario para un tipo clase (struct, class, o union), el compilador siempre declarará un constructor por defecto como un miembro inline public
de su clase.
Si se encuentran presentes algunos constructores declarados por el usuario, el usuario aún puede forzar la generación automática de un constructor por defecto por el compilador que de lo contrario sería declarado implícitamente con la palabra clave |
(desde C++11) |
El constructor por defecto declarado implícitamente (o predeterminado en su primera decflaración) tiene una especificación de excepción como se describe en especificación de excepción dinámica (hasta C++17)especificación de excepción (desde C++17)
[editar] Constructor por defecto implícitamente definido
Si el constructor por defecto implícitamente declarado no está definido como eliminado (= delete), se define (es decir, se genera y se compila un cuerpo de función) por el compilador si hay uso ODR o es necesario para la evaluación constante (desde C++11), y tiene el mismo efecto que un constructor definido por el usuario con un cuerpo vacío y una lista de inicializadores vacía. Es decir, llama a los constructores por defecto de las bases y de los miembros no estáticos de esta clase. Si esto satisface los requisitos de un constructor constexpr, el constructor generado es constexpr
. (desde C++11) Los tipos clase con un constructor vacío proporcionado por el usuario pueden tratarse de manera diferente que aquellos con un constructor definido implícitamente o constructor por defecto predeterminado (= default) durante la inicialización de un valor.
Si se encuentran presentes algunos constructores definidos por el usuario, el usuario aún puede forzar la generación automática de un constructor por defecto por el compilador que, de lo contrario, sería implícitamente declarado con la palabra clave |
(desde C++11) |
[editar] Constructor por defecto implícitamente declarado eliminado
El constructor por defecto implícitamente declarado o predeterminado (= default) (desde C++11) para una clase T
está indefinido (hasta C++11)definido como eliminado (desde C++11) si cualquiera de lo siguiente es verdadero:
-
T
tiene un miembro de tipo referencia sin un inicializador por defecto. (desde C++11) -
T
tiene un miembro const no construible por defecto constante si un inicializador de miembro por defecto (desde C++11). -
T
tiene un miembro (sin un inicializador de miembro por defecto) (desde C++11) que tiene un constructor por defecto eliminado, o su constructor por defecto es ambiguo o inaccesible desde este constructor. -
T
tiene una clase base directa o virtual que tiene un constructor por defecto eliminado, o es ambiguo o inaccesible desde este constructor. -
T
tiene una clase base directa o virtual, o un miembro de datos no estático, que tiene un destructor eliminado, o un destructor que es inaccesible desde este constructor.
|
(desde C++11) |
-
T
es una union y todos sus miembros variantes son const.
Si no se encuentran presentes constructores definidos por el usuario y el constructor por defecto implícitamente declarado no es trivial, el usuario aún puede inhibir la generación automática de un constructor por defecto implícitamente definido por el compilador con la palabra clave |
(desde C++11) |
[editar] Constructor por defecto trivial
El constructor por defecto para una clase T
es trivial (p. ej., no realiza ninguna acción) si todo lo siguiente es verdadero:
- El constructor no es proporcionado por el usuario (p. ej., es implícitamente definido o por defecto en su primera declaración).
-
T
no tiene funciones miembro virtuales. -
T
no tiene clases base virtuales.
|
(desde C++11) |
- Cada base directa de
T
tiene un constructor trivial por defecto. - Cada miembro no estático de tipo clase (o array de los mismos) tiene un constructor trivial por defecto.
Un constructor trivial por defecto es un constructor que no realiza ninguna acción. Todos los tipos de datos compatibles con el lenguaje C (tipos POD, o plain-old data types) son trivialmente construibles por defecto.
A diferencia de C, los objetos con constructores por defecto triviales no pueden crearse simplemente reinterpretando apropiadamente el almacenamiento alineado, como memoria asignada con std::malloc: se requiere de new
para formalmente introducir un nuevo objeto y evitar un comportamiento potencialmente indefinido.
[editar] Constructor por defecto seleccionable
Un constructor por defecto es seleccionable si es declarado por el usuario o declarado implícitamente y definible. |
(hasta C++11) |
Un constructor por defecto es seleccionable si no está eliminado (= delete). |
(desde C++11) (hasta C++20) |
Un constructor por defecto es seleccionable si
|
(desde C++20) |
La trivialidad de los constructores por defecto seleccionables determina si la clase es un tipo con tiempo de vida implícito, y si la clase es un tipo trivial.
[editar] Ejemplo
struct A { int x; A(int x = 1): x(x) {} // constructor por defecto definido por el usuario }; struct B: A { // B::B() es implícitamente definido, llama a A::A() }; struct C { A a; // C::C() es implícitamente definido, llama a A::A() }; struct D: A { D(int y): A(y) {} // D::D() no se declara porque existe otro constructor }; struct E: A { E(int y): A(y) {} E() = default; // explícitamente por defecto, llama a A::A() }; struct F { int& ref; // miembro referencia const int c; // miembro const // F::F() es implícitamente definido como eliminado }; // el constructor de copia declarado por el usuario (ya sea proporcionado por el usuario, // eliminado o por defecto) evita la generación implícita de un constructor por defecto struct G { G(const G&) {} // G::G() implícitamente definido como eliminado }; struct H { H(const H&) = delete; // H::H() implícitamente definido como eliminado }; struct I { I(const I&) = default; // I::I() implícitamente definido como eliminado }; int main() { A a; B b; C c; // D d; // ERROR en tiempo de compilación E e; // F f; // ERROR en tiempo de compilación // G g; // ERROR en tiempo de compilación // H h; // ERROR en tiempo de compilación // I i; // ERROR en tiempo de compilación }
[editar] Informes de defectos
Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
---|---|---|---|
CWG 2084 | C++11 | Los inicializadores de miembro por defecto no tienen efecto en si un constructor por defecto predeterminado de una unión se elimina) |
Evitan que el constructor por defecto predeterminado se defina como eliminado |