216 votes

Référence non définie à un membre de classe statique

Quelqu'un peut-il expliquer pourquoi le code suivant ne compilera pas? Au moins sur g ++ 4.2.4.

Et plus intéressant, pourquoi compilera-t-il quand je jette MEMBRE à int?

 #include <vector>

class Foo {  
public:  
    static const int MEMBER = 1;  
};

int main(){  
    vector<int> v;  
    v.push_back( Foo::MEMBER );       // undefined reference to `Foo::MEMBER'
    v.push_back( (int) Foo::MEMBER ); // OK  
    return 0;
}
 

206voto

Drew Hall Points 15917

Vous devez réellement définir le membre statique quelque part (après la définition de la classe). Essaye ça:

 class Foo { /* ... */ };

const int Foo::MEMBER;

int main() { /* ... */ }
 

Cela devrait se débarrasser de la référence indéfinie.

78voto

Douglas Mayle Points 7216

Le problème vient du fait que, d'un choc des nouvelles fonctionnalités C++ et de ce que vous essayez de faire. Tout d'abord, jetons un coup d'oeil à la push_back signature:

void push_back(const T&)

Il attend une référence à un objet de type T. en Vertu de l'ancien système d'initialisation, par exemple un membre existe. Par exemple, le code suivant compile parfaitement:

#include <vector>

class Foo {
public:
    static const int MEMBER;
};

const int Foo::MEMBER = 1; 

int main(){
    std::vector<int> v;
    v.push_back( Foo::MEMBER );       // undefined reference to `Foo::MEMBER'
    v.push_back( (int) Foo::MEMBER ); // OK  
    return 0;
}

C'est parce qu'il est un objet réel, quelque part, qui a de la valeur stockée. Si, toutefois, vous passez à la nouvelle méthode de spécification de static const membres, comme vous avez ci-dessus, Foo::MEMBRE n'est plus un objet. C'est une constante, un peu semblable:

#define MEMBER 1

Mais sans les maux de tête d'un pré-processeur de macro (et avec le type de sécurité). Cela signifie que le vecteur, qui attend une référence, ne peut pas en obtenir un.

63voto

Richard Corden Points 12292

La norme C++ nécessite une définition pour votre static const membre si la définition est en quelque sorte nécessaire.

La définition est nécessaire, par exemple si c'est l'adresse qui est utilisée. push_back prend son paramètre par référence const, et donc strictement le compilateur a besoin de l'adresse de votre membre et vous avez besoin de la définir dans l'espace de noms.

Lorsque vous effectuez un cast explicite de la constante, vous êtes en train de créer un temporaire et c'est ce temporaire qui est lié à la référence (en vertu des règles spéciales dans le standard).

C'est vraiment un cas intéressant, et je pense effectivement qu'il vaut la peine de soulever une question de façon à ce que les mst être modifié pour avoir le même comportement pour votre constante membre!

Bien que, dans une étrange façon cela pourrait être considéré comme un usage légitime de la unaires opérateur"+". Fondamentalement le résultat de l' unary + est une rvalue et donc les règles de liaison des rvalues à const références s'appliquent et nous n'utiliserons pas l'adresse de notre static const membre:

v.push_back( +Foo::MEMBER );

10voto

iso9660 Points 51

Aaa.h

 class Aaa {

protected:

    static Aaa *defaultAaa;

};
 

Aaa.cpp

 // You must define an actual variable in your program for the static members of the classes

static Aaa *Aaa::defaultAaa;
 

0voto

Paul Tomblin Points 83687

Aucune idée de pourquoi la distribution fonctionne, mais Foo :: MEMBER n'est pas alloué jusqu'à ce que Foo soit chargé pour la première fois, et puisque vous ne le chargez jamais, il n'est jamais alloué. Si vous aviez une référence à un Foo quelque part, cela fonctionnerait probablement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X