web-dev-qa-db-fra.com

Le mot clé static et ses différentes utilisations en C ++

Le mot clé static a plusieurs significations en C++, ce qui me rend très confus et je ne peux jamais m'empêcher de penser à la façon dont il est censé fonctionner.

D'après ce que je comprends, il y a static durée de stockage, ce qui signifie qu'elle dure toute la durée du programme dans le cas d'un programme global, mais lorsque vous parlez d'un local, cela signifie qu'il est initialisé à zéro par défaut. .

La norme C++ dit ceci pour les membres de données de classe avec le mot clé static:

.7.1 Durée de stockage statique [basic.stc.static]

3 Le mot-clé static peut être utilisé pour déclarer une variable locale avec une durée de stockage statique.

4 Le mot-clé static appliqué à un membre de la classe dans une définition de classe indique la durée de stockage statique du membre.

Qu'est-ce que cela signifie avec variable locale ? Est-ce une variable locale de fonction? Parce qu'il y a aussi le fait que lorsque vous déclarez une fonction locale en tant que static, elle n'est initialisée qu'une seule fois, la première fois qu'elle entre dans cette fonction.

Il ne parle également que de la durée de stockage des membres de la classe. Qu'en est-il non spécifique à une instance? C'est aussi une propriété de static non? Ou est-ce la durée de stockage?

Maintenant, qu'en est-il du cas avec static et de la portée du fichier? Toutes les variables globales sont-elles considérées comme ayant une durée de stockage statique par défaut? Ce qui suit (de la section 3.7.1) semble l'indiquer ainsi:

1 Toutes les variables qui n'ont pas de durée de stockage dynamique, n'ont pas de durée de stockage de thread et qui sont non locales ont une durée de stockage statique. Le stockage de ces entités doit durer pendant toute la durée du programme (3.6.2, 3.6.3)

Quel est le rapport entre static et le couplage d'une variable?

L'ensemble de ce mot-clé static est carrément déroutant. Quelqu'un peut-il préciser ses différentes utilisations en anglais et me dire quand initialiser une static membre de la classe?

176
Tony The Lion

Variables:

static il existe des variables pour la "durée de vie" de l'unité de traduction définie dans et:

  • Si elle se trouve dans une étendue d’espace de nommage (c’est-à-dire en dehors de fonctions et de classes), il est alors impossible d’y accéder depuis une autre unité de traduction. Ceci est appelé "liaison interne" ou "durée de stockage statique". (Ne faites pas cela dans les en-têtes sauf pour constexpr. N'importe quoi d'autre, et vous vous retrouverez avec une variable distincte dans chaque unité de traduction, ce qui est complètement déroutant)
  • S'il s'agit d'une variable dans une fonction , il est impossible d'y accéder depuis l'extérieur de la fonction, comme pour toute autre variable locale. (c'est le local qu'ils ont mentionné)
  • les membres de la classe n'ont pas de portée restreinte en raison de static, mais peuvent être adressés à partir de la classe ainsi que par une instance (comme std::string::npos). [Remarque: vous pouvez déclarer des membres statiques dans une classe, mais ils doivent généralement toujours être définis dans une unité de traduction (fichier cpp). ), et en tant que tel, il n'y en a qu'un par classe]

emplacements comme code:

static std::string namespaceScope = "Hello";
void foo() {
    static std::string functionScope= "World";
}
struct A {
   static std::string classScope = "!";
};

Avant que toute fonction dans une unité de traduction soit exécutée (éventuellement après le début de l'exécution de main), les variables ayant une durée de stockage statique (portée de l'espace de noms) dans cette unité de traduction seront "constantes initialisées" (jusqu'à constexpr si possible ou zéro sinon), puis les non-locales sont "dynamiquement initialisées" correctement dans l'ordre dans lequel elles sont définies dans l'unité de traduction (pour des choses comme std::string="HI"; qui n'est pas 't constexpr). Enfin, la statique de la fonction locale sera initialisée la première fois que l'exécution "atteint" la ligne où elles sont déclarées. Toutes les variables static ont toutes été détruites dans l'ordre inverse de l'initialisation.

Le moyen le plus simple d’obtenir ce résultat est de définir toutes les variables statiques non constexpr initialisées dans des locaux statiques de fonction, ce qui garantit que toutes vos statistiques/globales sont correctement initialisées lorsque vous essayez de les utiliser, quoi qu’il en soit, empêchant ainsi le fiasco d’ordre d’initialisation statique .

T& get_global() {
    static T global = initial_value();
    return global;
}

Soyez prudent, car lorsque la spécification indique que les variables d'espace de noms ont une "durée de stockage statique" par défaut, elles désignent le bit "durée de vie de l'unité de traduction", mais cela ne signifie pas . il est impossible d'y accéder en dehors du fichier.

Les fonctions

Fait beaucoup plus simple, static est souvent utilisé comme fonction de membre de classe et très rarement pour une fonction autonome.

Une fonction de membre statique diffère d'une fonction de membre ordinaire en ce sens qu'elle peut être appelée sans instance de classe. Comme elle ne possède pas d'instance, elle ne peut pas accéder aux membres non statiques de la classe. Les variables statiques sont utiles lorsque vous souhaitez avoir une fonction pour une classe qui ne fait absolument pas référence à des membres d'instance, ou pour gérer des variables static.

struct A {
    A() {++A_count;}
    A(const A&) {++A_count;}
    A(A&&) {++A_count;}
    ~A() {--A_count;}

    static int get_count() {return A_count;}
private:
    static int A_count;
}

int main() {
    A var;

    int c0 = var.get_count(); //some compilers give a warning, but it's ok.
    int c1 = A::get_count(); //normal way
}

Une fonction libre static signifie que la fonction ne sera pas référencée par une autre unité de traduction et que l'éditeur de liens peut donc l'ignorer complètement. Cela a un petit nombre d'objectifs:

  • Peut être utilisé dans un fichier cpp pour garantir que la fonction n'est jamais utilisée à partir d'un autre fichier.
  • Peut être placé dans un en-tête et chaque fichier aura sa propre copie de la fonction. Pas utile, car inline fait à peu près la même chose.
  • Accélère le temps de liaison en réduisant le travail
  • Peut mettre une fonction du même nom dans chaque unité de traduction et ils peuvent tous faire des choses différentes. Par exemple, vous pouvez placer un static void log(const char*) {} dans chaque fichier cpp, et chacun d'entre eux peut se connecter de manière différente.
127
Mooing Duck

La durée de stockage statique signifie que la variable réside au même endroit en mémoire pendant toute la durée du programme.

La liaison est orthogonale à cela.

Je pense que c'est la distinction la plus importante que vous puissiez faire. Comprenez ceci et le reste, ainsi que vous en souvenir, devrait être facile (ne vous adressez pas à @Tony directement, mais celui qui le lira dans le futur) .

Le mot-clé static peut être utilisé pour désigner le stockage interne et stockage statique, mais ils sont fondamentalement différents.

Qu'est-ce que cela signifie avec variable locale? Est-ce une variable locale de fonction?

Oui. Indépendamment du moment où la variable est initialisée (au premier appel de la fonction et lorsque le chemin d’exécution atteint le point de déclaration), elle résidera au même endroit en mémoire pendant la durée de vie du programme. Dans ce cas, static lui donne un stockage statique.

Maintenant, qu'en est-il du cas avec statique et la portée du fichier? Toutes les variables globales sont-elles considérées comme ayant une durée de stockage statique par défaut?

Oui, tous les globals ont par définition une durée de stockage statique (maintenant que nous avons clarifié ce que cela signifie). Mais Les variables liées aux espaces de noms ne sont pas déclarées avec static, car cela leur donnerait un lien interne, donc une variable par unité de traduction.

Quel est le lien entre la statique et le couplage d’une variable?

Il donne un lien interne entre variables de domaine de noms. Il donne aux membres et aux variables locales la durée de stockage statique.

Développons tout cela:

//

static int x; //internal linkage
              //non-static storage - each translation unit will have its own copy of x
              //NOT A TRUE GLOBAL!

int y;        //static storage duration (can be used with extern)
              //actual global
              //external linkage
struct X
{
   static int x;     //static storage duration - shared between class instances 
};

void foo()
{
   static int x;     //static storage duration - shared between calls
}

Tout ce mot clé statique est carrément déroutant

Certainement, à moins que vous ne le connaissiez. :) En essayant d'éviter d'ajouter de nouveaux mots-clés à la langue, le comité a réutilisé celui-ci, IMO, à cet effet - confusion. Il est utilisé pour signifier différentes choses (devrais-je dire, probablement des choses opposées).

63
Luchian Grigore

Afin de clarifier la question, je préférerais classer l'utilisation du mot clé 'statique' sous trois formes différentes:

(A). variables

(B). fonctions

(C). variables membres/fonctions de classes

l'explication suit ci-dessous pour chacune des sous-positions:

(A) mot clé 'statique' pour variables

Celui-ci peut être un peu délicat, mais si expliqué et compris correctement, c'est assez simple.

Pour expliquer cela, il est d’abord très utile de connaître la portée , la durée et le couplage des variables, sans lesquelles il est toujours difficile de voir à travers le flou. concept de mot-clé staic

1. Portée : détermine où, dans le fichier, la variable est accessible. Il peut être de deux types: (i) Portée locale ou en bloc . (ii) Portée globale

2. Duration : Détermine le moment où une variable est créée et détruite. Encore une fois, il s’agit de deux types: (i) Durée de stockage automatique (pour les variables ayant une portée Local ou Bloc). (ii) Durée de stockage statique (pour les variables ayant une portée globale ou des variables locales (dans une fonction ou dans un bloc de code) avec statique spécificateur).

3. Liaison : Détermine si une variable peut être accédée (ou liée) dans un autre fichier. Encore une fois (et heureusement), il en existe de deux types: (i) Liaison interne (pour les variables ayant une portée de bloc et une portée globale/portée de fichier/étendue de nom global ) (ii) Lien externe (pour les variables n’ayant que pour Portée globale/Portée de fichier/Portée d’espace de noms global)

Reportons-nous à un exemple ci-dessous pour une meilleure compréhension des variables globales et locales simples (pas de variables locales avec une durée de stockage statique):

//main file
#include <iostream>

int global_var1; //has global scope
const global_var2(1.618); //has global scope

int main()
{
//these variables are local to the block main.
//they have automatic duration, i.e, they are created when the main() is 
//  executed and destroyed, when main goes out of scope
 int local_var1(23);
 const double local_var2(3.14);

 {
/* this is yet another block, all variables declared within this block are 
 have local scope limited within this block. */
// all variables declared within this block too have automatic duration, i.e, 
/*they are created at the point of definition within this block,
 and destroyed as soon as this block ends */
   char block_char1;
   int local_var1(32) //NOTE: this has been re-declared within the block, 
//it shadows the local_var1 declared outside

 std::cout << local_var1 <<"\n"; //prints 32

  }//end of block
  //local_var1 declared inside goes out of scope

 std::cout << local_var1 << "\n"; //prints 23

 global_var1 = 29; //global_var1 has been declared outside main (global scope)
 std::cout << global_var1 << "\n"; //prints 29
 std::cout << global_var2 << "\n"; //prints 1.618

 return 0;
}  //local_var1, local_var2 go out of scope as main ends
//global_var1, global_var2 go out of scope as the program terminates 
//(in this case program ends with end of main, so both local and global
//variable go out of scope together

Vient maintenant le concept de liaison. Lorsqu'une variable globale définie dans un fichier est destinée à être utilisée dans un autre fichier, la liaison de la variable joue un rôle important.

La liaison des variables globales est spécifiée par les mots-clés: (i) statique , et, (ii) extern

(Maintenant, vous obtenez l'explication)

un mot clé statique peut être appliqué à des variables ayant une portée locale ou globale et, dans les deux cas, cela signifie différentes choses. Je vais d'abord expliquer l'utilisation du mot clé 'statique' dans les variables à portée globale (où je précise également l'utilisation du mot clé 'extern'), puis celle des mots clés à portée locale.

1. Mot clé statique pour les variables à portée globale

Les variables globales ont une durée statique, ce qui signifie qu'elles ne sortent pas de la portée lorsqu'un bloc de code particulier (par exemple, main ()) dans lequel il est utilisé se termine. Selon le lien, ils ne peuvent être accédés que dans le même fichier où ils ont été déclarés (pour une variable globale statique) ou en dehors du fichier même en dehors du fichier dans lequel ils ont été déclarés (variables globales de type extern)

Dans le cas d'une variable globale ayant un spécificateur externe, et si cette variable est utilisée en dehors du fichier dans lequel elle a été initialisée, elle doit être déclarée dans le fichier où elle est utilisée, exactement comme une fonction doit être transmise. déclaré si sa définition est dans un fichier différent de celui où il est utilisé.

En revanche, si la variable globale a un mot clé static, elle ne peut pas être utilisée dans un fichier en dehors duquel elle a été déclarée.

(voir exemple ci-dessous pour clarification)

par exemple:

//main2.cpp
 static int global_var3 = 23;  /*static global variable, cannot be                            
                                accessed in anyother file */
 extern double global_var4 = 71; /*can be accessed outside this file                  linked to main2.cpp */
 int main() { return 0; }

main3.cpp

//main3.cpp
#include <iostream>

int main()
{
   extern int gloabl_var4; /*this variable refers to the gloabal_var4
                            defined in the main2.cpp file */
  std::cout << global_var4 << "\n"; //prints 71;

  return 0;
}

maintenant, toute variable de c ++ peut être une constante ou une non-constante et pour chaque "const-ness", nous obtenons deux cas de liaison c ++ par défaut, dans le cas où aucune n'est spécifiée:

(i) Si une variable globale est non-const, son lien est externe par défaut , c’est-à-dire que la variable globale non-const est accessible dans un autre Fichier .cpp par déclaration forward en utilisant le mot clé extern (en d’autres termes, les variables globales non constantes ont un lien externe (avec une durée de cours statique)). De plus, l'utilisation du mot-clé extern dans le fichier d'origine où il a été défini est redondante. Dans ce cas pour rendre une variable globale non-const inaccessible au fichier externe, utilisez le spécificateur 'static' avant le type de la variable .

(ii) Si une variable globale est const, son lien est statique par défaut , c’est-à-dire qu’une variable globale const n’est pas accessible dans un fichier autre que est défini (en d’autres termes, les variables globales const ont un lien interne (avec une durée statique bien sûr)). De plus, l'utilisation d'un mot clé statique pour empêcher l'accès d'une variable globale const dans un autre fichier est redondante. Ici, pour qu'un lien global const ait un lien externe, utilisez le spécificateur 'extern' avant le type de la variable

Voici un résumé des variables de portée globale avec divers liens

//globalVariables1.cpp 

// defining uninitialized vairbles
int globalVar1; //  uninitialized global variable with external linkage 
static int globalVar2; // uninitialized global variable with internal linkage
const int globalVar3; // error, since const variables must be initialized upon declaration
const int globalVar4 = 23; //correct, but with static linkage (cannot be accessed outside the file where it has been declared*/
extern const double globalVar5 = 1.57; //this const variable ca be accessed outside the file where it has been declared

Nous examinons ensuite le comportement des variables globales ci-dessus lorsqu’elles sont accédées dans un fichier différent.

//using_globalVariables1.cpp (eg for the usage of global variables above)

// Forward declaration via extern keyword:
 extern int globalVar1; // correct since globalVar1 is not a const or static
 extern int globalVar2; //incorrect since globalVar2 has internal linkage
 extern const int globalVar4; /* incorrect since globalVar4 has no extern 
                         specifier, limited to internal linkage by
                         default (static specifier for const variables) */
 extern const double globalVar5; /*correct since in the previous file, it 
                           has extern specifier, no need to initialize the
                       const variable here, since it has already been
                       legitimately defined perviously */

2. Mot clé statique pour les variables à portée locale

Mises à jour (août 2019) sur le mot clé statique pour les variables de portée locale

Cet autre peut être divisé en deux catégories:

(i) mot clé statique pour les variables dans un bloc de fonction , et (ii) mot clé statique pour les variables dans un nom non nommé bloc local.

(i) mot clé statique pour les variables dans un bloc de fonction.

Un peu plus tôt, j'ai mentionné que les variables de portée locale ont une durée automatique, c'est-à-dire qu'elles commencent à exister lorsque le bloc est entré (que ce soit un bloc normal ou un bloc de fonction) et cessent d'exister lorsque le bloc se termine, histoire longue, Les variables de portée locale ont une durée automatique et les variables de durée automatique (et les objets) n'ont pas de lien, ce qui signifie qu'elles sont non visible en dehors du bloc de code.

Si un spécificateur statique est appliqué à une variable locale dans un bloc de fonction, il modifie la durée de la variable de manière automatique. en statique et sa durée de vie correspond à la durée totale du programme, ce qui signifie qu’il a un emplacement de mémoire fixe et que sa valeur n’est initialisée qu’une seule fois avant le démarrage du programme, comme indiqué en cpp référence (l'initialisation ne doit pas être confondue avec l'affectation)

prenons un exemple.

//localVarDemo1.cpp    
 int localNextID()
{
  int tempID = 1;  //tempID created here
  return tempID++; //copy of tempID returned and tempID incremented to 2
} //tempID destroyed here, hence value of tempID lost

int newNextID()
{
  static int newID = 0;//newID has static duration, with internal linkage
  return newID++; //copy of newID returned and newID incremented by 1
}  //newID doesn't get destroyed here :-)


int main()
{
  int employeeID1 = localNextID();  //employeeID1 = 1
  int employeeID2 = localNextID();  // employeeID2 = 1 again (not desired)
  int employeeID3 = newNextID(); //employeeID3 = 0;
  int employeeID4 = newNextID(); //employeeID4 = 1;
  int employeeID5 = newNextID(); //employeeID5 = 2;
  return 0;
}

En regardant le critère ci-dessus pour les variables locales statiques et les variables globales statiques, on pourrait être tenté de demander quelle pourrait être la différence entre elles. Bien que les variables globales soient accessibles à tout moment dans le code (dans la même chose que dans une unité de traduction différente, en fonction de la const - ness et extern - ness), une variable statique définie dans un bloc fonctionnel n'est pas directement accessible. La variable doit être renvoyée par la valeur de la fonction ou la référence. Montrons ceci par un exemple:

//localVarDemo2.cpp 

//static storage duration with global scope 
//note this variable can be accessed from outside the file
//in a different compilation unit by using `extern` specifier
//which might not be desirable for certain use case.
static int globalId = 0;

int newNextID()
{
  static int newID = 0;//newID has static duration, with internal linkage
  return newID++; //copy of newID returned and newID incremented by 1
}  //newID doesn't get destroyed here


int main()
{
    //since globalId is accessible we use it directly
  const int globalEmployee1Id = globalId++; //globalEmployeeId1 = 0;
  const int globalEmployee2Id = globalId++; //globalEmployeeId1 = 1;

  //const int employeeID1 = newID++; //this will lead to compilation error since newID++ is not accessible direcly. 
  int employeeID2 = newNextID(); //employeeID3 = 0;
  int employeeID2 = newNextID(); //employeeID3 = 1;

  return 0;
}

Plus d'explications sur le choix de la variable statique globale globale et statique peuvent être trouvées sur ce thread stackoverflow

(ii) mot clé statique pour les variables dans un bloc local non nommé.

il est impossible d'accéder aux variables statiques d'un bloc local (pas un bloc de fonction) en dehors du bloc une fois que le bloc local est hors de portée. Aucune mise en garde à cette règle.

    //localVarDemo3.cpp 
    int main()
    {

      {
          const static int static_local_scoped_variable {99};
      }//static_local_scoped_variable goes out of scope

      //the line below causes compilation error
      //do_something is an arbitrary function
      do_something(static_local_scoped_variable);
      return 0;
    }

C++ 11 a introduit le mot clé constexpr qui garantit l'évaluation d'une expression au moment de la compilation et permet au compilateur d'optimiser le code. Maintenant, si la valeur d'une variable statique constante dans une portée est connue au moment de la compilation, le code est optimisé d'une manière similaire à celle avec constexpr. Voici un petit exemple

Je recommande aux lecteurs de rechercher également la différence entre constexpr et static const pour les variables dans ce fil de stackoverflow . ceci conclut mon explication pour le mot clé static appliqué aux variables.

B. Mot-clé 'static' utilisé pour les fonctions

en termes de fonctions, le mot-clé static a une signification simple. Ici, il fait référence à la liaison de la fonction Normalement, toutes les fonctions déclarées dans un fichier cpp ont une liaison externe par défaut, c.-à-d. Qu'une fonction définie dans un fichier peut être utilisé dans un autre fichier cpp par déclaration anticipée.

en utilisant un mot clé statique avant la déclaration de fonction limite son lien à internal , c’est-à-dire qu’une fonction statique ne peut pas être utilisée dans un fichier en dehors de sa définition.

C. Staitc Mot-clé utilisé pour les variables membres et les fonctions de classes

1. Mot-clé 'static' pour les variables membres de classes

Je commence directement avec un exemple ici

#include <iostream>

class DesignNumber
{
  private:

      static int m_designNum;  //design number
      int m_iteration;     // number of iterations performed for the design

  public:
    DesignNumber() {     }  //default constructor

   int  getItrNum() //get the iteration number of design
   {
      m_iteration = m_designNum++;
      return m_iteration;
   }
     static int m_anyNumber;  //public static variable
};
int DesignNumber::m_designNum = 0; // starting with design id = 0
                     // note : no need of static keyword here
                     //causes compiler error if static keyword used
int DesignNumber::m_anyNumber = 99; /* initialization of inclass public 
                                    static member  */
enter code here

int main()
{
   DesignNumber firstDesign, secondDesign, thirdDesign;
   std::cout << firstDesign.getItrNum() << "\n";  //prints 0
   std::cout << secondDesign.getItrNum() << "\n"; //prints 1
   std::cout << thirdDesign.getItrNum() << "\n";  //prints 2

   std::cout << DesignNumber::m_anyNumber++ << "\n";  /* no object
                                        associated with m_anyNumber */
   std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 100
   std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 101

   return 0;
}

Dans cet exemple, la variable statique m_designNum conserve sa valeur et cette variable membre privée unique (car elle est statique) est partagée avec toutes les variables du type d'objet DesignNumber.

De même que les autres variables membres, les variables membres statiques d'une classe ne sont associées à aucun objet de classe, ce qui est démontré par l'impression de anyNumber dans la fonction principale.

variables de membre statique const vs non-const dans la classe

(i) Variables de membre statique de la classe non const Dans l'exemple précédent, les membres statiques (à la fois publics et privés) étaient des constantes. La norme ISO interdit aux membres statiques non const d'être initialisés dans la classe. Par conséquent, comme dans l'exemple précédent, ils doivent être initialisés après la définition de la classe, en précisant que le mot clé static doit être omis.

(ii) Variables membres const-static de la classe Ceci est simple et va de pair avec la convention d'initialisation des autres variables membres const, c'est-à-dire les variables membres stat const de une classe peut être initialisée au moment de la déclaration et peut être initialisée à la fin de la déclaration de la classe avec une réserve indiquant que le mot clé const doit être ajouté au membre statique lorsque en cours d'initialisation après la définition de la classe.

Je recommanderais toutefois d’initialiser les variables membres statiques const au point de déclaration. Cela va avec la convention C++ standard et donne au code une apparence plus nette

pour plus d'exemples sur les variables de membre statique dans une classe, recherchez le lien suivant dans learncpp.com http://www.learncpp.com/cpp-tutorial/811-static-member-variables/

2. Mot-clé 'static' pour la fonction membre des classes

Tout comme les variables membres de classes peuvent être statiques, il en est de même des fonctions membres de classes. Les fonctions membres normales des classes sont toujours associées à un objet du type classe. En revanche, les fonctions membres statiques d'une classe ne sont associées à aucun objet de la classe, c'est-à-dire qu'elles n'ont pas * ce pointeur.

Deuxièmement, puisque les fonctions membres statiques de la classe n'ont pas * ce pointeur, elles peuvent être appelées à l'aide du nom de la classe et de l'opérateur de résolution de portée dans la fonction principale (NomClasse :: nomFonction ();).

Troisièmement, les fonctions membres statiques d'une classe ne peuvent accéder qu'aux variables membres statiques d'une classe, car les variables membres non statiques d'une classe doivent appartenir à un objet de classe.

pour plus d'exemples sur les fonctions membres statiques dans une classe, consultez le lien suivant sur learncpp.com

http://www.learncpp.com/cpp-tutorial/812-static-member-functions/

22
ggulgulia

C'est en fait assez simple. Si vous déclarez une variable comme statique dans l'étendue d'une fonction, sa valeur est conservée entre les appels successifs à cette fonction. Alors:

int myFun()
{
static int i=5;
i++;
return i;
}
int main()
{
printf("%d", myFun());
printf("%d", myFun());
printf("%d", myFun());
}

affichera 678 au lieu de 666, car il se souvient de la valeur incrémentée.

Les membres statiques, quant à eux, conservent leur valeur sur toutes les instances de la classe. Donc le code suivant:

struct A
{
static int a;
};
int main()
{
A first;
A second;
first.a = 3;
second.a = 4;
printf("%d", first.a);
}

affichera 4, car first.a et second.a sont essentiellement la même variable. Pour l’initialisation, voir cette question.

19

Lorsque vous déclarez une variable static au niveau du fichier, cette variable est uniquement disponible dans ce fichier (techniquement, l'unité de traduction * , mais ne compliquons pas trop cela). Par exemple:

a.cpp

static int x = 7;

void printax()
{
    cout << "from a.cpp: x=" << x << endl;
}

b.cpp

static int x = 9;

void printbx()
{
    cout << "from b.cpp: x=" << x << endl;
}

main.cpp:

int main(int, char **)
{
    printax(); // Will print 7
    printbx(); // Will print 9

    return 0;
}

Pour une variable locale , static signifie que la variable sera initialisée à zéro et conserve sa valeur entre les appels:

unsigned int powersoftwo()
{
    static unsigned lastpow;

    if(lastpow == 0)
        lastpow = 1;
    else
        lastpow *= 2;

    return lastpow;
}

int main(int, char **)
{
    for(int i = 0; i != 10; i++)
        cout << "2^" << i << " = " << powersoftwo() << endl;
}

Pour les variables class , cela signifie qu'il n'y a qu'une seule instance de cette variable partagée entre tous les membres de cette classe. Selon les autorisations, il est possible d'accéder à la variable de l'extérieur de la classe en utilisant son nom complet.

class Test
{
private:
    static char *xxx;

public:
    static int yyy;

public:
    Test()
    {        
        cout << this << "The static class variable xxx is at address "
             << static_cast<void *>(xxx) << endl;
        cout << this << "The static class variable yyy is at address "
             << static_cast<void *>(&y) << endl;
    }
};

// Necessary for static class variables.
char *Test::xxx = "I'm Triple X!";
int Test::yyy = 0;

int main(int, char **)
{
    Test t1;
    Test t2;

    Test::yyy = 666;

    Test t3;
};

Marquer une fonction non-classe comme static rend la fonction uniquement accessible à partir de ce fichier et inaccessible à partir d'autres fichiers.

a.cpp

static void printfilename()
{ // this is the printfilename from a.cpp - 
  // it can't be accessed from any other file
    cout << "this is a.cpp" << endl;
}

b.cpp

static void printfilename()
{ // this is the printfilename from b.cpp - 
  // it can't be accessed from any other file
    cout << "this is b.cpp" << endl;
}

Pour les fonctions de membre de classe, les marquer comme suit: static signifie que la fonction n'a pas besoin d'être appelée sur une instance particulière d'un objet (c'est-à-dire qu'elle n'a pas de pointeur this.).

class Test
{
private:
    static int count;

public:
    static int GetTestCount()
    {
        return count;
    };

    Test()
    {
        cout << this << "Created an instance of Test" << endl;
        count++;
    }

    ~Test()
    {
        cout << this << "Destroyed an instance of Test" << endl;
        count--;
    }
};

int Test::count = 0;

int main(int, char **)
{
    Test *arr[10] = { NULL };

    for(int i = 0; i != 10; i++)
        arr[i] = new Test();

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    // now, delete them all except the first and last!
    for(int i = 1; i != 9; i++)
        delete arr[i];        

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    delete arr[0];

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    delete arr[9];

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    return 0;
}
8
Nik Bougalis

Les variables statiques sont partagées entre chaque instance d'une classe, au lieu que chaque classe ait sa propre variable.

class MyClass
{
    public:
    int myVar; 
    static int myStaticVar;
};

//Static member variables must be initialized. Unless you're using C++11, or it's an integer type,
//they have to be defined and initialized outside of the class like this:
MyClass::myStaticVar = 0;

MyClass classA;
MyClass classB;

Chaque instance de 'MyClass' a son propre 'myVar', mais partage le même 'myStaticVar'. En fait, vous n'avez même pas besoin d'une instance de MyClass pour accéder à 'myStaticVar', vous pouvez y accéder en dehors de la classe de la manière suivante:

MyClass::myStaticVar //Assuming it's publicly accessible.

Lorsqu'il est utilisé dans une fonction en tant que variable locale (et non en tant que variable de membre de classe), le mot clé static a un effet différent. Il vous permet de créer une variable persistante sans donner de portée globale.

int myFunc()
{
   int myVar = 0; //Each time the code reaches here, a new variable called 'myVar' is initialized.
   myVar++;

   //Given the above code, this will *always* print '1'.
   std::cout << myVar << std::endl;

   //The first time the code reaches here, 'myStaticVar' is initialized. But ONLY the first time.
   static int myStaticVar = 0;

   //Each time the code reaches here, myStaticVar is incremented.
   myStaticVar++;

   //This will print a continuously incrementing number,
   //each time the function is called. '1', '2', '3', etc...
   std::cout << myStaticVar << std::endl;
}

C'est une variable globale en termes de persistance ... mais sans portée globale/accessibilité.

Vous pouvez également avoir des fonctions membres statiques. Les fonctions statiques sont fondamentalement des fonctions non membres, mais à l'intérieur de l'espace de noms du nom de la classe et avec un accès privé aux membres de la classe.

class MyClass
{
    public:
    int Func()
    {
        //...do something...
    }

    static int StaticFunc()
    {
        //...do something...
    }
};

int main()
{
   MyClass myClassA;
   myClassA.Func(); //Calls 'Func'.
   myClassA.StaticFunc(); //Calls 'StaticFunc'.

   MyClass::StaticFunc(); //Calls 'StaticFunc'.
   MyClass::Func(); //Error: You can't call a non-static member-function without a class instance!

   return 0;
}

Lorsque vous appelez une fonction membre, il existe un paramètre caché appelé 'this', qui est un pointeur sur l'instance de la classe appelant la fonction. Les fonctions membres statiques ne pas ont ce paramètre caché ... elles sont appelables sans instance de classe, mais ne peuvent pas non plus accéder aux variables membres non statiques d'une classe, car elles n'ont pas de 'this 'pointeur pour travailler avec. Ils ne sont appelés sur aucune instance de classe spécifique.

8
Jamin Grey

Qu'est-ce que cela signifie avec variable locale? Est-ce une variable locale de fonction?

Oui - Non global, tel qu'une variable locale de fonction.

Parce qu'il y a aussi que lorsque vous déclarez une fonction locale comme statique, elle n'est initialisée qu'une seule fois, la première fois qu'elle entre dans cette fonction.

Droite.

Il ne parle également que de la durée de stockage des membres de la classe. Qu'en est-il non spécifique à une instance, c'est aussi une propriété de static non? Ou est-ce la durée de stockage?

class R { static int a; }; // << static lives for the duration of the program

c'est-à-dire que toutes les occurrences de R share int R::a - int R::a ne sont jamais copiées.

Maintenant, qu'en est-il du cas avec statique et la portée du fichier?

Effectivement un global qui a un constructeur/destructeur le cas échéant - l'initialisation n'est pas différée jusqu'à l'accès.

Quel est le lien entre la statique et le couplage d’une variable?

Pour une fonction locale, c'est externe. Accès: Il est accessible à la fonction (à moins bien sûr que vous le retourniez).

Pour une classe, c'est externe. Accès: les spécificateurs d'accès standard s'appliquent (public, protégé, privé).

static peut également spécifier une liaison interne, en fonction de l'endroit où elle est déclarée (fichier/espace de noms).

Tout ce mot clé statique est carrément déroutant

Il a trop de buts en C++.

quelqu'un peut-il clarifier les différentes utilisations de l'anglais et aussi me dire quand initialiser un membre statique de la classe?

Il est automatiquement initialisé avant main s'il est chargé et possède un constructeur. Cela peut sembler une bonne chose, mais l’ordre d’initialisation est en grande partie hors de votre contrôle. Par conséquent, une initialisation complexe devient très difficile à gérer, et vous voulez le minimiser - si vous devez avoir une statique, alors les échelles locales sont bien meilleures entre les bibliothèques et projets. En ce qui concerne les données avec une durée de stockage statique, vous devriez essayer de minimiser cette conception, en particulier si elles sont modifiables (variables globales). Le "temps" d’initialisation varie également pour un certain nombre de raisons - le chargeur et le noyau ont quelques astuces pour réduire l’empreinte mémoire et différer l’initialisation, en fonction des données en question.

1
justin

Je ne suis pas un programmeur C, je ne peux donc pas vous donner d'informations sur les utilisations de static dans un programme C correctement, mais lorsqu'il s'agit de programmation orientée objet, static déclare essentiellement qu'une variable, ou une fonction ou une classe est identique. tout au long de la vie du programme. Prends pour exemple.

class A
{
public:
    A();
    ~A();
    void somePublicMethod();
private:
    void somePrivateMethod();
};

Lorsque vous instanciez cette classe dans votre classe principale, vous faites quelque chose comme ceci.

int main()
{
   A a1;
   //do something on a1
   A a2;
   //do something on a2
}

Ces deux instances de classe sont complètement différentes l'une de l'autre et fonctionnent indépendamment l'une de l'autre. Mais si vous deviez recréer la classe A comme ça.

class A
{
public:
    A();
    ~A();
    void somePublicMethod();
    static int x;
private:
    void somePrivateMethod();
};

Permet de revenir à la main encore.

int main()
{
   A a1;
   a1.x = 1;
   //do something on a1
   A a2;
   a2.x++;
   //do something on a2
}

Alors a1 et a2 partageraient la même copie de int x, toutes les opérations sur x dans a1 influenceraient directement les opérations de x en a2. Donc si je devais faire ça

int main()
{
   A a1;
   a1.x = 1;
   //do something on a1
   cout << a1.x << endl; //this would be 1
   A a2;
   a2.x++;
   cout << a2.x << endl; //this would be 2 
   //do something on a2
}

Les deux instances de la classe A partagent des variables et des fonctions statiques. J'espère que ça répond à ta question. Ma connaissance limitée de C me permet de dire que définir une fonction ou une variable en tant que statique signifie que seul le fichier dans lequel la fonction ou la variable est définie en tant que statique est visible. Mais ce serait mieux répondu par un type C et non par moi. C++ permet à la fois aux C et C++ de déclarer vos variables statiques, car elles sont totalement compatibles avec C.

1
David Tr

Objet statique: Nous pouvons définir des membres de classe statiques à l'aide du mot clé static. Lorsque nous déclarons un membre d'une classe comme statique, cela signifie que quel que soit le nombre d'objets de la classe créés, il n'existe qu'une seule copie du membre statique.

Un membre statique est partagé par tous les objets de la classe. Toutes les données statiques sont initialisées à zéro lorsque le premier objet est créé, si aucune autre initialisation n'est présente. Nous ne pouvons pas le mettre dans la définition de la classe, mais il peut être initialisé en dehors de la classe comme dans l'exemple suivant en redéclarant la variable statique, en utilisant l'opérateur de résolution de portée: pour identifier la classe à laquelle elle appartient.

Essayons l'exemple suivant pour comprendre le concept de membres de données statiques:

#include <iostream>

using namespace std;

class Box
{
   public:
      static int objectCount;
      // Constructor definition
      Box(double l=2.0, double b=2.0, double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // Increase every time object is created
         objectCount++;
      }
      double Volume()
      {
         return length * breadth * height;
      }
   private:
      double length;     // Length of a box
      double breadth;    // Breadth of a box
      double height;     // Height of a box
};

// Initialize static member of class Box
int Box::objectCount = 0;

int main(void)
{
   Box Box1(3.3, 1.2, 1.5);    // Declare box1
   Box Box2(8.5, 6.0, 2.0);    // Declare box2

   // Print total number of objects.
   cout << "Total objects: " << Box::objectCount << endl;

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il en résulte le résultat suivant:

Constructor called.
Constructor called.
Total objects: 2

Membres de fonction statique: En déclarant un membre de fonction comme statique, vous le rendez indépendant de tout objet particulier de la classe. Une fonction membre statique peut être appelée même si aucun objet de la classe n'existe et que l'accès aux fonctions statiques s'effectue uniquement à l'aide du nom de la classe et de l'opérateur de résolution de portée ::.

Une fonction membre statique ne peut accéder qu’à un membre de données statique, à d’autres fonctions membres statiques et à toute autre fonction extérieure à la classe.

Les fonctions membres statiques ont une portée de classe et elles n'ont pas accès au pointeur this de la classe. Vous pouvez utiliser une fonction membre static pour déterminer si certains objets de la classe ont été créés ou non.

Essayons l’exemple suivant pour comprendre le concept de membres de fonctions statiques:

#include <iostream>

using namespace std;

class Box
{
   public:
      static int objectCount;
      // Constructor definition
      Box(double l=2.0, double b=2.0, double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // Increase every time object is created
         objectCount++;
      }
      double Volume()
      {
         return length * breadth * height;
      }
      static int getCount()
      {
         return objectCount;
      }
   private:
      double length;     // Length of a box
      double breadth;    // Breadth of a box
      double height;     // Height of a box
};

// Initialize static member of class Box
int Box::objectCount = 0;

int main(void)
{

   // Print total number of objects before creating object.
   cout << "Inital Stage Count: " << Box::getCount() << endl;

   Box Box1(3.3, 1.2, 1.5);    // Declare box1
   Box Box2(8.5, 6.0, 2.0);    // Declare box2

   // Print total number of objects after creating object.
   cout << "Final Stage Count: " << Box::getCount() << endl;

   return 0;
}

Lorsque le code ci-dessus est compilé et exécuté, il en résulte le résultat suivant:

Inital Stage Count: 0
Constructor called.
Constructor called.
Final Stage Count: 2
1
Nima Soroush