Afin de clarifier la question, je préfère classer l'utilisation du mot-clé «statique» sous trois formes différentes:
(UNE). les variables
(B). les fonctions
(C). Variables membres / fonctions des classes
l'explication ci-dessous pour chacune des sous-rubriques:
(A) mot-clé 'statique' pour les variables
Celui-ci peut être peu délicat, mais s'il est expliqué et compris correctement, il est assez simple.
Pour expliquer cela, il est d'abord très utile de connaître la portée, la durée et le lien des variables, sans lesquelles les choses sont toujours difficiles à voir à travers le concept trouble du 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 étendue . (ii) Portée mondiale
2. Durée : détermine quand une variable est créée et détruite. Encore une fois, il est de deux types: (i) Durée de stockage automatique (pour les variables ayant une portée locale 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 spécificateur statique ).
3. Lien : détermine si une variable est accessible (ou liée) dans un autre fichier. Encore une fois (et heureusement), il est de deux types: (i) Liaison interne
(pour les variables ayant une portée de bloc et une portée globale / portée de fichier / portée globale de l'espace de noms) (ii) Liaison externe (pour les variables n'ayant qu'une portée globale / portée de fichier / Portée de l'espace de noms global)
Voyons 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
Maintenant vient le concept de Linkage. Lorsqu'une variable globale définie dans un fichier est destinée à être utilisée dans un autre fichier, le lien de la variable joue un rôle important.
Le couplage des variables globales est spécifié par les mots clés: (i) statique , et, (ii) extern
(Maintenant, vous obtenez l'explication)
un mot-clé statique peut être appliqué à des variables de portée locale et globale, et dans les deux cas, elles signifient des choses différentes. J'expliquerai d'abord l'utilisation du mot-clé «statique» dans les variables à portée globale (où je clarifie également l'utilisation du mot-clé «extern») et ensuite pour celles à portée locale.
1. Mot-clé statique pour les variables de portée globale
Les variables globales ont une durée statique, ce qui signifie qu'elles ne sortent pas du champ d'application lorsqu'un bloc de code particulier (par exemple, main ()) dans lequel il est utilisé se termine. Selon le lien, ils sont accessibles uniquement dans le même fichier où ils sont déclarés (pour la variable globale statique), ou en dehors du fichier même en dehors du fichier dans lequel ils sont déclarés (variables globales de type externe)
Dans le cas d'une variable globale ayant un spécificateur externe, et si cette variable est accessible en dehors du fichier dans lequel elle a été initialisée, elle doit être déclarée en avant dans le fichier où elle est utilisée, tout comme une fonction doit être en avant déclaré si sa définition se trouve dans un fichier différent de celui où elle est utilisée.
En revanche, si la variable globale a un mot-clé statique, elle ne peut pas être utilisée dans un fichier en dehors duquel elle a été déclarée.
(voir l'exemple ci-dessous pour des éclaircissements)
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 en c ++ peut être soit un const, soit un non-const et pour chaque 'const-ness' nous obtenons deux cas de liaison c ++ par défaut, au cas où aucun n'est spécifié:
(i) Si une variable globale est non-const, son lien est extern par défaut , c'est-à-dire que la variable globale non-const est accessible dans un autre fichier .cpp par déclaration directe à l'aide du mot-clé extern (en d'autres termes, non const global les variables ont un lien externe (avec une durée statique bien sûr)). L'utilisation du mot-clé extern dans le fichier d'origine où il a été défini est également redondante. Dans ce cas, pour rendre une variable globale non const inaccessible au fichier externe, utilisez le spécificateur «statique» 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 celui où elle est définie, (en d'autres termes, les variables globales const ont un lien interne (avec une durée statique) bien sûr)). L'utilisation d'un mot-clé statique pour empêcher l'accès à une variable globale const dans un autre fichier est également redondante. Ici, pour faire en sorte qu'une variable globale 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
Ensuite, nous étudions le comportement des variables globales ci-dessus lorsqu'elles sont accessibles 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 avec portée locale
Mises à jour (août 2019) du mot clé statique pour les variables de portée locale
Cela peut encore être subdivisé en deux catégories:
(i) mot clé statique pour les variables d'un bloc fonctionnel , et (ii) mot clé statique pour les variables d'un bloc local sans nom.
(i) mot-clé statique pour les variables d'un bloc fonctionnel.
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, que ce soit un bloc fonctionnel) et cessent d'exister lorsque le bloc se termine, bref, les variables avec portée locale ont une durée automatique et les variables de durée automatiques (et les objets) n'ont pas de lien, ce qui signifie qu'ils ne sont pas visibles en dehors du bloc de code.
Si un spécificateur statique est appliqué à une variable locale dans un bloc fonctionnel, il modifie la durée de la variable automatique en statique et sa durée de vie est la durée totale du programme, ce qui signifie qu'il a un emplacement de mémoire fixe et que sa valeur est initialisée uniquement une fois avant le démarrage du programme comme mentionné dans la référence cpp (l'initialisation ne doit pas être confondue avec l'affectation)
permet de jeter un oeil à 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 examinant le critère ci-dessus pour les variables locales statiques et les variables globales statiques, on pourrait être tenté de se demander quelle pourrait être la différence entre elles. Alors que les variables globales sont accessibles à tout moment dans le code (dans la même unité de traduction que dans différentes selon la const -ness et l' extern -ness), une variable statique définie dans un bloc fonction n'est pas directement accessible. La variable doit être renvoyée par la valeur ou la référence de la fonction. Voyons cela 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 et statique locale peuvent être trouvées sur ce thread stackoverflow
(ii) mot-clé statique pour les variables dans un bloc local sans nom.
les variables statiques dans un bloc local (pas un bloc fonctionnel) ne sont pas accessibles 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 const dans une étendue 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 également aux lecteurs de rechercher la différence entre constexpr
et static const
pour les variables dans ce thread stackoverflow . ceci conclut mon explication du mot-clé statique appliqué aux variables.
Mot-clé 'statique' utilisé pour les fonctions
en termes de fonctions, le mot-clé statique a une signification simple. Ici, il se réfère à la liaison de la fonction
Normalement, toutes les fonctions déclarées dans un fichier cpp ont un lien externe par défaut, c'est-à-dire qu'une fonction définie dans un fichier peut être utilisée dans un autre fichier cpp par déclaration directe.
l'utilisation d'un mot clé statique avant la déclaration de fonction limite son lien à interne , c'est-à-dire qu'une fonction statique ne peut pas être utilisée dans un fichier en dehors de sa définition.
C. Mot-clé Staitc utilisé pour les variables membres et les fonctions des classes
1. mot clé "statique" pour les variables membres des 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 seule variable membre privée (car elle est statique) est partagée n / b 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
const vs variables de membres statiques non const dans la classe
(i) Variables de membre statique de classe non const
Dans l'exemple précédent, les membres statiques (publics et privés) n'étaient pas constants. La norme ISO interdit l'initialisation des membres statiques non const dans la classe. Par conséquent, comme dans l'exemple précédent, ils doivent être initialisés après la définition de classe, avec la mise en garde que le mot clé statique doit être omis
(ii) les variables membres const-stat de la classe
ceci est simple et va avec la convention de l'initialisation des autres variables membres const, c'est-à-dire que les variables membres stat const d'une classe peuvent être initialisées au point de déclaration et elles peuvent être initialisées à la fin de la déclaration de classe avec une mise en garde que le mot clé const doit être ajouté au membre statique lors de son initialisation après la définition de classe.
Je recommanderais cependant d'initialiser les variables de membre statique const au point de déclaration. Cela va avec la convention C ++ standard et rend le code plus propre
pour plus d'exemples sur les variables membres statiques dans une classe, recherchez le lien suivant sur learncpp.com
http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
2. Mot clé "statique" pour la fonction membre des classes
Tout comme les variables membres des classes peuvent être statiques, les fonctions membres des classes peuvent également l'être. 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 de l'opérateur de résolution de nom et de portée de classe dans la fonction principale (ClassName :: functionName ();)
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, recherchez le lien suivant sur learncpp.com
http://www.learncpp.com/cpp-tutorial/812-static-member-functions/