c++ - objetos - ¿Por qué se pueden modificar los miembros const en un constructor?
herencia c++ constructores (3)
Tengo curiosidad de por qué los miembros de const pueden modificarse en el constructor.
¿Hay alguna regla estándar en la inicialización que anule la "const-ness" de un miembro?
struct Bar {
const int b = 5; // default member initialization
Bar(int c):b(c) {}
};
Bar *b = new Bar(2); // Problem: Bar::b is modified to 2
// was expecting it to be an error
¿Algunas ideas?
Añadiendo a la gran respuesta de songyuanyao, si desea un miembro de datos const
que no pueda inicializar en un constructor, puede hacer que el miembro sea static
:
struct Bar {
static const int b = 5; // static member initialization
Bar(int c)
:b(c) // Error: static data member can only be initialized at its definition
{
b = c; // Error: b is read-only
}
};
En C ++ 17 puedes mejorar esto aún más haciendo que esté en inline
:
struct Bar {
inline static const int b = 5; // static member initialization
Bar(int c)
:b(c) // Error: static data member can only be initialized at its definition
{
b = c; // Error: b is read-only
}
};
De esta forma no tendrás problemas con ODR.
Cuando tu lo hagas:
struct Bar {
const int b = 5; // default member initialization
...
};
Le está diciendo al compilador que haga esto con el constructor predeterminado:
...
Bar() : b(5)
{}
...
Independientemente de si ha proporcionado el constructor predeterminado o no. Cuando proporciona el constructor predeterminado y la asignación inicial, anula el código de asignación predeterminado del compilador (es decir, b(5)
). La inicialización / asignación predeterminada en la declaración es útil cuando tienes múltiples constructores, y puedes asignar o no los miembros de const en todos los constructores:
...
Bar() = default; // b=5
Bar(int x) : b(x) // b=x
Bar(double y) : /*other init, but not b*/ // b=5
...
Esto no es modificación (o asignación), sino initialization . p.ej
struct Bar {
const int b = 5; // initialization (via default member initializer)
Bar(int c)
:b(c) // initialization (via member initializer list)
{
b = c; // assignment; which is not allowed
}
};
El miembro de datos const
no se puede modificar ni asignar, pero podría (y debe) inicializarse a través de la lista de inicializadores de miembros o el inicializador de miembros predeterminado.
Si tanto el inicializador de miembro predeterminado como el inicializador de miembro se proporcionan en el mismo miembro de datos, se ignorará el inicializador de miembro predeterminado. Es por eso que b->b
se inicializa con el valor 2
.
Si un miembro tiene un inicializador de miembro predeterminado y también aparece en la lista de inicialización de miembro en un constructor, se ignora el inicializador de miembro predeterminado.
Por otro lado, el inicializador de miembro predeterminado tiene efecto solo cuando el miembro de datos no está especificado en la lista de inicializadores de miembros. p.ej
struct Bar {
const int b = 5; // default member initialization
Bar(int c):b(c) {} // b is initialized with c
Bar() {} // b is initialized with 5
};