Ci-dessous, un extrait de code qui pourrait être compilé et exécuté sans erreur dans vs2015
#include<iostream>
using namespace std;
class A {
public:
A(int b) :k(b) {}//second time
const int k = 666;//first time
};
int main() {
A a(555);
cout << a.k << endl;
return 0;
}
La sortie est 555
. Mais pour autant que je sache, const
objet ne doit être initialisé qu'une seule fois, après quoi la valeur est non modifiable.
Ce n'est pas initialisé deux fois; le initialiseur de membre par défaut est simplement ignoré. Donc pour A a(555);
, a.k
est initialisé comme 555
.
Si un membre a un initialiseur de membre par défaut et apparaît également dans la liste d'initialisation de membre dans un constructeur, l'initialiseur de membre par défaut est ignoré.
De la norme, [class.base.init]/1 :
Si un membre de données non statique donné possède à la fois un initialiseur de membre par défaut et un initialiseur de mem, l'initialisation spécifiée par l'initialiseur de mem est effectuée et l'initialiseur de membre par défaut du membre de données non statique est ignoré. [Exemple: étant donné
struct A { int i = /* some integer expression with side effects */ ; A(int arg) : i(arg) { } // ... };
le constructeur A(int) initialisera simplement i à la valeur de arg, et les effets secondaires dans l'initialiseur de membre par défaut de i n'auront pas lieu. - fin exemple]
D'autre part, étant donné
class A {
public:
A() {} // k will be initialized via default member initializer, i.e. 666
A(int b) :k(b) {} // k will be initialized via member initializer list, i.e. b
const int k = 666;
};
puis pour A a;
, a.k
sera initialisé comme 666
.
Il n'est initialisé qu'une seule fois.
const int k = 666;
serait utilisé s'il n'était pas fourni dans le constructeur.