La raison en est que si la classe n'a pas de constructeur défini par l'utilisateur, alors il peut s'agir de POD et la classe POD n'est pas initialisée par défaut. Donc si vous déclarez un objet const de POD qui n'est pas initialisé, à quoi cela sert-il? Je pense donc que la norme applique cette règle afin que l'objet puisse réellement être 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!
Mais si vous faites de la classe un non-POD:
struct nonPOD_A
{
nonPOD_A() {} //this makes non-POD
};
nonPOD_A a1; //initialized
const nonPOD_A a2; //initialized
Notez la différence entre POD et non-POD.
Le constructeur défini par l'utilisateur est un moyen de rendre la classe non-POD. Vous pouvez le faire de plusieurs manières.
struct nonPOD_B
{
virtual void f() {} //virtual function make it non-POD
};
nonPOD_B b1; //initialized
const nonPOD_B b2; //initialized
Remarquez que nonPOD_B ne définit pas de constructeur défini par l'utilisateur. Compilez-le. Il compilera:
Et commentez la fonction virtuelle, puis elle donne une erreur, comme prévu:
Eh bien, je pense que vous avez mal compris le passage. Il dit d'abord ceci (§8.5 / 9):
Si aucun initialiseur n'est spécifié pour un objet, et que l'objet est de type de classe non POD (éventuellement qualifié cv) (ou de son tableau), l'objet doit être initialisé par défaut; [...]
Il parle de classe non POD, éventuellement de type qualifié cv . Autrement dit, l'objet non POD doit être initialisé par défaut si aucun initialiseur n'est spécifié. Et qu'est-ce qui est initialisé par défaut ? Pour les non-POD, la spécification dit (§8.5 / 5),
Initialiser par défaut un objet de type T signifie:
- si T est un type de classe non POD (clause 9), le constructeur par défaut pour T est appelé (et l'initialisation est mal formée si T n'a pas de constructeur par défaut accessible);
Il parle simplement du constructeur par défaut de T, si son défini par l'utilisateur ou généré par le compilateur n'est pas pertinent.
Si vous êtes clair à ce sujet, alors comprenez ce que la spécification dit ensuite ((§8.5 / 9),
[...]; si l'objet est de type qualifié const, le type de classe sous-jacent doit avoir un constructeur par défaut déclaré par l'utilisateur.
Donc, ce texte implique que le programme sera mal formé si l'objet est de type POD qualifié par const et qu'aucun initialiseur n'est spécifié (car les POD ne sont pas initialisés par défaut):
POD p1; //uninitialized - can be useful - hence allowed
const POD p2; //uninitialized - never useful - hence not allowed - error
À propos, cela compile très bien , car il n'est pas POD et peut être initialisé par défaut .
a, mais gcc-4.3.4 l'accepte même lorsque vous le faites (voir ideone.com/uHvFS )