web-dev-qa-db-fra.com

Pourquoi ne pouvons-nous pas initialiser les membres de la classe à leur déclaration?

Je me demande s'il y a une raison pour laquelle nous ne pouvons pas initialiser les membres lors de leur déclaration.

class Foo
{
    int Bar = 42; // this is invalid
};

Comme équivalent à l'utilisation de listes d'initialisation de constructeur.

class Foo
{
    int Bar;
public:
    Foo() : Bar(42) {}
}

Ma compréhension personnelle est que l'exemple ci-dessus est beaucoup plus expressif et intentionnel. De plus, c'est une syntaxe plus courte. Et je ne vois aucune possibilité de confusion avec d'autres éléments de langage.

Y a-t-il une clarification officielle à ce sujet?

28
danijar

L'initialisation des membres non statiques ne pouvait pas être effectuée comme ceci avant C++ 11. Si vous compilez avec un compilateur C++ 11, il devrait accepter avec plaisir le code que vous avez donné.

J'imagine que la raison de ne pas l'autoriser en premier lieu est qu'une déclaration de membre de données n'est pas une définition. Aucun objet n'est introduit. Si vous avez un membre de données tel que int x;, aucun objet int n'est créé tant que vous n'avez pas réellement créé un objet du type de la classe. Par conséquent, un initialiseur sur ce membre serait trompeur. Ce n'est que lors de la construction qu'une valeur peut être affectée au membre, c'est précisément à cela que servent les listes d'initialisation des membres.

Il y avait également quelques problèmes techniques à résoudre avant que l'initialisation des membres non statiques puisse être ajoutée. Considérez les exemples suivants:

struct S {
    int i(x);
    // ...
    static int x;
};

struct T {
    int i(x);
    // ...
    typedef int x;
};

Lorsque ces structures sont en cours d'analyse, au moment de l'analyse du membre i, il est ambigu qu'il s'agisse d'une déclaration de membre de données (comme dans S) ou d'une déclaration de fonction membre (comme dans T).

Avec la fonctionnalité ajoutée, ce n'est pas un problème car vous ne pouvez pas initialiser un membre avec cette syntaxe de parenthèses. Vous devez utiliser un accolade-ou-égal-initialiseur tel que:

int i = x;
int i{x};

Ceux-ci ne peuvent être que des membres de données et nous n'avons donc plus de problème.

Voir la proposition N2628 pour un examen plus approfondi des problèmes à prendre en compte lors de la proposition d'initialiseurs de membres non statiques.

24
Joseph Mansfield

La raison principale est que l'initialisation s'applique à un objet ou à une instance, et dans la déclaration de la classe, il n'y a ni objet ni instance; vous ne l'avez que lorsque vous commencez à construire.

Il y a eu une certaine évolution à cet égard. Déjà, à la toute fin de la normalisation de C++ 98, le comité a ajouté la possibilité de le faire pour les membres const stat de type intégral --- principalement parce que ceux-ci peuvent être utilisés dans des contextes où le compilateur doit pouvoir voir l'initialisation . En C++ 11, le langage a été étendu pour permettre de spécifier un initialiseur dans la déclaration, mais ce n'est qu'un raccourci - l'initialisation réelle a toujours lieu en haut du constructeur.

5
James Kanze