web-dev-qa-db-fra.com

Ordre d'initialisation de la variable statique de classe

J'ai une classe A qui a deux variables statiques. J'aimerais en initialiser une avec une autre, une variable statique sans rapport, comme ceci:

#include <iostream>
class A
{
public:
    static int a;
    static int b;
};

int A::a = 200;
int a = 100;
int A::b = a;
int main(int argc, char* argv[])
{
    std::cout << A::b << std::endl;

    return 0;
}

La sortie est 200. Alors, quelqu'un pourrait-il me dire pourquoi?

61
QuantumPlus

C'est correct selon les règles de recherche. [basic.lookup.unqual]/1 dit:

Un nom utilisé dans la définition d'un membre de données statique de la classe X (après l'identificateur qualifié du membre statique) est recherché comme si le nom était utilisé dans une fonction membre de X. [Remarque: [class.static.data ] décrit en outre les restrictions relatives à l'utilisation de noms dans la définition d'un membre de données statique. - note de fin]

Puisque le a non qualifié est recherché comme si vous êtes dans une fonction membre, il doit trouver le membre A::a première. L'ordre d'initialisation de A::a et A::b n'affecte pas la recherche, bien que cela affecte la définition du résultat.

36
StoryTeller

Alors, quelqu'un pourrait-il me dire pourquoi?

Ceci est clairement indiqué dans basic.scope.class/4 , c'est moi qui souligne:

Le portée potentielle d'une déclaration qui s'étend jusqu'à la fin d'une définition de classe ou au-delà de cette définition s'étend également aux régions définies par ses définitions de membres, même si les membres sont définis lexicalement en dehors de la classe (this inclut les définitions de membres de données statiques , les définitions de classe imbriquées et les définitions de fonction de membre, y compris le corps de la fonction de membre et toute partie de la partie déclarateur de ces définitions qui suit l'identificateur de déclarant, y compris une clause de déclaration de paramètre et toute valeur par défaut arguments).

Ainsi, quand vous avez

int A::a = 200;
int a = 100;
int A::b = a; // note the '::' scope resolution operator
              // OUTPUT: 200

a fait en réalité référence à A::a parce que classe portée est étendu de A::b.

Contrairement à si vous avez:

int A::a = 200;
int a = 100;
int b = a; // note b is not A::b
           // i.e. without the '::', scope resolution operator
           // OUTPUT: 100

a ferait référence au (global) ::a puisque b ici n'est pas membre de class A,
c'est à dire. aucune extension de portée de classe.

16
Joseph D.

c ++ draft/class.static

Si un identificateur non qualifié est utilisé dans la définition d'un membre statique après l'identificateur déclarateur du membre , et le nom lookup ([basic.lookup.unqual]) découvre que l'id non qualifié fait référence à un membre statique , à un énumérateur ou à un type imbriqué de la classe du membre (ou d'une classe de base de la classe du membre ), l'identificateur non qualifié est transformé en une expression qualifiée dans laquelle le spécificateur de nom imbriqué nomme la portée de la classe à partir de laquelle le membre est référencé . [Remarque: voir [expr.prim.id] pour les restrictions sur l'utilisation de membres de données non statiques et de fonctions membres non statiques. - note de fin]

Il indique que l'identificateur non qualifié est transformé en une expression d'identificateur qualifié dans votre situation.

int A::b = a;

Vous pouvez définir des identifiants qualifiés, mais aucun spécificateur de nom imbriqué comme celui-ci.

int A::b = ::a;
8
dao leno

Parce que le nom recherche résout le a comme A::a. Si vous voulez faire cela, vous devrez résoudre l'étendue manuellement:

int A::b = ::a;
        // ^ Global scope resolution

Exemple en direct

6
Fantastic Mr Fox