Il motivo è che se la classe non ha un costruttore definito dall'utente, allora può essere POD e la classe POD non è inizializzata per impostazione predefinita. Quindi, se dichiari un oggetto const di POD che non è inizializzato, a cosa serve? Quindi penso che lo Standard imponga questa regola in modo che l'oggetto possa effettivamente essere utile.
struct POD
{
int i;
};
POD p1; //uninitialized - but don't worry we can assign some value later on!
p1.i = 10; //assign some value later on!
POD p2 = POD(); //initialized
const POD p3 = POD(); //initialized
const POD p4; //uninitialized - error - as we cannot change it later on!
Ma se rendi la classe un non-POD:
struct nonPOD_A
{
nonPOD_A() {} //this makes non-POD
};
nonPOD_A a1; //initialized
const nonPOD_A a2; //initialized
Notare la differenza tra POD e non-POD.
Il costruttore definito dall'utente è un modo per rendere la classe non POD. Ci sono diversi modi per farlo.
struct nonPOD_B
{
virtual void f() {} //virtual function make it non-POD
};
nonPOD_B b1; //initialized
const nonPOD_B b2; //initialized
Si noti che nonPOD_B non definisce un costruttore definito dall'utente. Compilalo. Compilerà:
E commenta la funzione virtuale, quindi dà l'errore, come previsto:
Beh, penso che tu abbia frainteso il passaggio. Per prima cosa dice questo (§8.5 / 9):
Se per un oggetto non è specificato alcun inizializzatore e l'oggetto è di tipo (possibilmente qualificato da cv) non-POD di tipo (o array), l'oggetto deve essere inizializzato per default; [...]
Si parla di classi non POD possibilmente qualificate per cv . Cioè, l'oggetto non POD deve essere inizializzato per impostazione predefinita se non è specificato alcun inizializzatore. E cos'è l' inizializzazione predefinita ? Per i non POD, le specifiche dicono (§8.5 / 5),
Inizializzare di default un oggetto di tipo T significa:
- se T è un tipo di classe non POD (clausola 9), viene chiamato il costruttore di default per T (e l'inizializzazione è mal formata se T non ha un costruttore di default accessibile);
Parla semplicemente del costruttore predefinito di T, indipendentemente dal fatto che il suo definito dall'utente o generato dal compilatore sia irrilevante.
Se sei chiaro fino a questo punto, allora capisci cosa dice la specifica successiva ((§8.5 / 9),
[...]; se l'oggetto è di tipo qualificato const, il tipo di classe sottostante deve avere un costruttore predefinito dichiarato dall'utente.
Quindi questo testo implica che il programma sarà mal formato se l'oggetto è di tipo POD qualificato const e non è specificato alcun inizializzatore (perché i POD non sono inizializzati di default):
POD p1; //uninitialized - can be useful - hence allowed
const POD p2; //uninitialized - never useful - hence not allowed - error
A proposito, questo si compila bene , perché non è POD e può essere inizializzato di default .
a, ma gcc-4.3.4 lo accetta anche quando lo fai (vedi ideone.com/uHvFS )