http://www.cnblogs.com/wolf-lifeng/p/3156936.html2.3 Global Scope 2.3.1 Overview
The global scope is the largest namespace scope, unlike the user-defined namespace scope, where the global scope does not need to be defined, and it naturally exists in C + + programs. The global scope is the outermost container, which is the parent scope of all scopes. In the global scope, you can define other namespaces, types, functions, variables, templates, and so on.
A function defined in a global scope is a global function, and a variable defined in the global scope is a global object. Global functions and global objects are valid throughout the global scope and their sub-scopes, and their lifecycles run throughout the program. Start by defining them until the entire program is finished running.
2.3.21-time Definition rule 2.3.2.1 declaration and definition
A variable can be declared more than once, but only once. declarations and definitions are two different concepts.
In the variable definition, in addition to the program to indicate the type and name of the variable, but also to allocate storage space for the variable and initialization operations. When defining a global variable, if the variable is not assigned an initial value, the system performs the default initialization work, such as: Integer variable assignment 0, string variable assignment null value, and so on. The value of the global variable is stored in the program's global store, and the value of the constant is stored in the global store, as well as the value of the static variable.
Declaring an action is a subset of the definition operation, and when declaring a variable, it simply indicates to the program the type and name of the variable, it does not allocate storage space for the variable, and therefore does not have initialization work.
The Declaration and definition of global variables and global functions are in the following format:
Statement Void myFunction (int);//declares a function that specifies the name of the function, the return value, and the parameter list. extern void myFunction (int);//When declaring a function, the extern keyword is optional, plus the keyword represents a display//declaration. Extern in MyVar; Declares a variable. You must add the keyword extern. Indicates that this is merely a declaration, and that the definition is in its/his place Extern Const char* Const myconstvar;//declares a constant pointer to a constant. Defined Void myFunction (int Para)//function definition, including function declaration part and Function body { function code for functions } Int myVar = 10;//variable definition Const char* Const MYCONSTVAR = new char[10];//constant definition. Extern int myintvar = definition of 50;//variable. |
When declaring a global variable, you must add the keyword extern and you cannot initialize the variable. If an initialization operation is performed on a variable, even if the extern keyword is preceded, it is considered to be the definition of the variable, not the declaration of the variable.
The relationship between declaration and definition is: The definition is also a declaration, the definition contains the declaration, but the declaration is just a sub-step of the definition. Sometimes declarations and definitions can be done together, such as declarations and definitions of local variables, and in some cases declarations and definitions need to be performed separately. When a variable needs to be used in multiple files, it is necessary to separate the declarations and definitions (generally global variables), otherwise you can use a definition statement to complete the declaration and definition of the variable (typically a local variable).
2.3.2.2 Logical organization of documents
A variable can be declared multiple times, but it is defined only once. There is a rule here: The Global object and global function are either defined only once, or there are multiple identical definitions in a program (in the case of both functions and global constants).
In order to obey the rule of definition, it is necessary to organize the documents. In general, global variables and global functions defined in the global scope need to be used in multiple files. In this case, the most reasonable form of file organization is: "header file +cpp file" forms. The specific process is described as follows:
- Declare global variables and global functions in the header file;
- Define inline functions in the header file, and constants that can determine values at compile time;
- Introduce a header file in the source file (. cpp file) and define the variables and functions declared in the header file;
- The header files that declare these global variables and global functions are introduced in files that need to use these global variables and global functions, starting with these global variables and global functions.
Header files are used to declare and not define functions and variables, while source files are used to implement variables and function definitions. Header files typically contain the definition of a class, the definition of an enumeration, the definition of a symbolic constant, the definition of an inline function, the declaration of an extern variable, the declaration of a function, a typedef declaration. If a variable is defined in the header file, then when the other file is introduced to it, it is assumed that the variable in the head file is defined once again. This is not allowed, according to the rule of a definition. However, there are three exceptions, class, inline functions, and the symbolic constants that can be determined at compile-time values can be defined in the header file.
The specific code that handles global variables and global functions in the same way as the header file is formatted as follows:
Declaration of functions and variables implemented in a header file --------------------A.h---------------------------------- extern int myintvar;//declares a variable that must begin with the keyword extern. Void myFunction (int);//declares a function that specifies the function name, return value, and argument list. Const DOUBLE Mydlvar = 3.14;//defines a constant. The value of the constant is known at compile time. Inline double Getdlvar ()//define inline function { Return Mydlvar; } Extern Const char* Const myconstvar;//declares a global constant, and the value of the constant is not known at compile time. The definition of variables and functions is implemented in the source file. ---------------------------A.cpp----------------------------------- #include "A.h" Int Myintvar = 100;//define Variable Void myFunction (int Para) { Implementation code for the function } Const char* Const MYCONSTVAR = The value of the new char[100];//constant can be determined at run time, so the definition is implemented here, and only in the header file is declared. Using the defined global variables and global functions in other files, first introduce the header file. ----------------------------Other.cpp-------------------------------- #include "A.h" --The following are specific uses. |
2.3.3 members of the global scope 2.3.3.1 Common variables
In C + +, compiling a program can be divided into the following stages:
- The preprocessing phase, which processes the # include command.
- Compile stage,
- Link stage.
If you use the #Include command in a source file, a header file is introduced into the source file. The pre-processing command is executed first before the compiler executes the compilation. That is, the merged file will exist as a file in the target source file in which all the code contained in the header file is merged. In other words, the compiler will only see the source file when compiling, and the header file is not visible during the compilation phase.
So, suppose the following implementation: In the header file A.h, a variable definition (not a declaration) is implemented, such as: "int a = 10;". Each time the header file is referenced once by another source file (#include "A.h"), the compiler will assume that the variable was defined once. If the header file is referenced more than two times, a redefinition error occurs. This is a violation of the definition of a law.
For the above reasons, for the normal global variables, the correct use is: first in the header file using the extern keyword to implement the declaration of the global variable, and then introduce the header file in the source file, and implement the definition of the global variable; The header file that declares the global variable is introduced in the source file that uses the global variable, and then it is used.
For normal global variables, this method can only be used for processing.
2.3.3.2 Const constant
Constants defined in the global scope have only a file scope. That is, a constant defined in the global scope is valid only within the file in which it is defined, and it does not affect constants defined in other files with the same name. Examples are as follows:
--------------------------A.h---------------------------- const int Myintvar = 100;//defines a constant in the header file ------------------------B.cpp---------------------------- #include "A.h" Int a = Myintvar; ------------------------C.cpp---------------------------- #include "A.h" Int B = Myintvar; |
Example 1
The above code will work correctly. Although the "A.h" header file is referenced several times, the global constant "Myintvar" defined in the B.cpp file does not affect the global constant "Myintvar" as defined in the C.cpp file because the global constant has only a file scope.
This is a way of using global constants, as long as the value of the global constant is determined at compile time. In the example above, the global constant "Myintvar" is not being actually stored in the global zone. During the compile phase, the compiler uses the value of the global constant to replace the place where the name "Myintvar" is used. Therefore, it is required that the definition of the global constant is visible where the global constant is used. This requirement is met in the same way as in Example 1. When using the extern keyword on a symbolic constant, or the address of a symbolic constant, the compiler allocates storage space for the symbolic constant, otherwise it simply performs a compile-time substitution.
Now consider the following question, if the value of the global constant is uncertain at compile time? For example: What happens if you use the new operator to define a global constant? Examples are as follows:
-------------------A.h--------------------- char* Const PCHAR = new char[100];//defines a constant pointer. Note the difference from: const char* PChar = new char[100]. -------------------B.cpp------------------ #include "A.h" ------------------C.cpp-------------------- #include "A.h" |
Example 2
Each time the header file is referenced in the source file, a memory allocation is performed. This is clearly inconsistent with the results we expect. What we want is a constant pointer, which points to a string. We can then use that constant pointer in several other files.
You can use the keyword extern to break the file scope of a const constant so that it has a global scope. Examples of specific practices are as follows:
-------------------------A.h--------------------- Extern char* Const pchar;//declares global constants, which can be referenced by other files ------------------------A.cpp-------------------- #include "A.h" char* Const PCHAR = new char[100];//defines constants, compiler allocates storage space Memset (PChar, ' 100 '); -------------------------B.cpp------------------- #include "A.h"//introduce a header file where you can use the declared global constants .... |
Example 3
The practice is to declare global constants in the header file using the keyword extern. With the extern keyword, the global constant has a global scope and is not limited to the file scope. The definition of the global constant is then implemented in the source file. Finally, the header file that declares the global constant is referenced in the source file that uses the global constant. This is the second way to use global constants, which are used when the value of the global constant is indeterminate at compile time.
As we can see, there are two ways to use global constants. When the value of a global constant is determined in the compile phase, we can use the first method, such as Example 1; When the value of a global constant is indeterminate in the compilation phase, but in the case where the run phase is deterministic, we can use the second method, such as Example 3.
2.3.3.3 Static variables
Static variables defined in the global scope also have a file scope. The static variable is valid only in the file in which it is defined. Static variables with the same name defined in multiple files do not affect each other, and no redefinition errors occur. Also, these static variables of the same name maintain a separate copy of the data, and the value of the static variable in one file does not affect the value of the static variable with the same name in the other file.
The file scope of a static variable cannot be broken, and you cannot use the keyword extern to have a global scope for static variables defined in the global scope.
Therefore, global static variables have only one usage, similar to the first way of using global constants. Examples are as follows:
-----------------------A.h------------------------- Static in myintvar = 100; ----------------------B.h------------------------- Int MyFunction1 (); --------------------C.h---------------------------- Int MyFunction2 (); ----------------------B.cpp------------------------- #include "A.h"//references a header file that defines a static variable, which is equivalent to defining a static variable in the source file #cindlue "B.h" Void MyFunction1 () { Int a = Myintvar; myintvar++; return A; } ----------------------------C.cpp--------------------------- #include "A.h"//references a header file that defines a static variable, which is equivalent to defining a static variable in the source file #include "C.h" Int MyFunction2 () { Int B = Myintvar; myintvar++; return b; } -----------------------------. main.cpp----------------------------- #include "B.h" #include "c.h" Void Main () { Int a = MyFunction1 (); Int B = MyFunction2 (); After execution, the value of a, B is 100. Note that static variables in the file scope each maintain a separate copy of the data, without affecting each other. } |
For these reasons, the global static variable is defined in the source file, where it is needed, and where it is defined. You do not need to define the header file beforehand.
Note the difference between global constants and global static variables: By default, global constants and global static variables have a file scope. However, you can adapt the keyword extern to break the global constants of the file scope and make it accessible in other files as well; you cannot use the keyword extern to break the file scope of a global static variable.
2.3.3.4 inline function
During the compile phase, the compiler expands the inline function at the call point, merging the code in the body of the function into the call point. Instead of executing the stack at run time, the function call is out of the way. When the compiler expands inline functions, in the current file, the definition of the inline function must be visible. Therefore, the inline function must be defined in the header file, and when the other source file introduces the header file, it is equivalent to the definition of the inline function that is visible in the source file. An inline function can be defined more than once, as long as the form of multiple definitions is guaranteed to be the same, according to a defined rule.
Class 2.4 domain 2.4. The composition of Class 1 definitions
the definition of a class is accomplished using a combination of a header file and a source file . The definition of a class, the definition of an inline function, the declaration of a static member variable are implemented in the header file, the definition of a class member function, and the definition of a static member variable is implemented in the source file. When implementing a source file, you must introduce a header file that defines the class. The specific sample code is as follows:
---------------------------A.h------------------------------------ Class MyClass { Typedef int sb4;//typedef definition, which introduces a mnemonic of type int. Public: MyClass (SB4 Para);//Declaration constructor The declaration of the inline function is resolved at the current position, and/or definition of the inline function resolves in the entire class domain inline void SetValue (SB4 Para)//Declaration portion of inline function. The SB4 can be used directly because SB4 has been declared before it. { M_ivar = para;//The definition part of the inline function. The entire class domain is resolved so that member variable M_ivar can be used directly. } Static SB4 GetValue ();//declaring a statically member function Private: SB4 m_ivar;//defining member variables Static SB4 m_staticvar;//declaration of statically variable };//within the entire curly brace range, belong to the class domain ----------------------------A.cpp--------------------------------- #include "A.h"//must introduce header file MYCLASS::SB4 Myclass::m_staticvar = GetValue ();//static member variables are defined and initialized. The red part belongs to the class domain, the member function GetValue () can be called directly; the green part is not a class domain and must be referenced with a decorated qualified name. Type SB4 must be referenced with a decorated qualified name. Myclass::myclass (SB4 Para) { M_ivar = Initialization of para;//member variables }//the red part belongs to the class domain, the type SB4 can be used directly, and the member variable M_ivar can be used directly. MYCLASS::SB4 Myclass::getvalue ()//the definition of a static member function. The green section does not belong to a class domain and must be referenced with a decorated qualified name. Type SB4 must be referenced with a decorated qualified name. { Return M_staticvar; } |
In the preceding code, the class definition is divided into two parts, implemented in the header file and the source file, respectively. The header file is an external interface that encapsulates the specific implementation in the source file.
Components of the 2.4.2 class domain
Each definition of a class introduces a class domain, and different classes have different class domains. Each class member, including member variables and member functions, belongs to that class of domain. Within a class domain, class members can be accessed directly using member names, and class members must be accessed through member access operators or domain resolution operators outside of the class. The class domain consists of the following three parts:
- In the header file of a class definition, the class body part belongs to the class domain of the class. The specific range is: From the positive curly brace "{" To the end of the inverted curly brace "}";
- In the source file defined by the member function, the part of the member function that is decorated with the qualified name belongs to the class domain. See 2.4.1 red Section;
- In the source file defined by the static member variable, the part of the static variable decorated with the qualified name belongs to the class domain. See 2.4.1 red section.
In the source file, the member function decorates the qualified name or the part of the static variable that precedes the qualified name does not belong to the class domain. If you want to refer to names in a class field in this section, you must use a decorated qualified name. See the Green section of section 2.4.1.
In the source file, the member names that belong to the class domain can be used directly, and no cosmetic qualification is required. See 2.4.1 red section.
How 2.4.3 class members are accessed
When you need to use a class in a program text file, you need to introduce a header file that implements that class definition in the file. When working with class members, there are two forms: using a member of a class in the outside of the class and using a member of the class within the class domain.
Scenario 1 : When you use members of a class outside of the class, you must use the member access operator or the domain resolution operator. The specific code is as follows:
Start using members of the class outside of the class Void Main () { MyClass objclass;//defining class objects; myclass* PClass = new myclass;//defines a class pointer. Objclass. SetValue (100);//In the class domain, access the class member using the class member access operator-the dot number. Pclass-> SetValue (100);//In the class domain, access the class member using the class member access operator-arrow. MyClass:: GetValue ();//The static members of the class are accessed using the domain resolution operator as part of the class. MYCLASS::SB4 MyVar = 100;//the type defined in the class is used in the form of a domain resolution operator in the outside class. } |
In the outside of the class, for class objects or pointers to class objects, you need to use the member access operator to access class members, and for static members of a class or types defined in a class, you need to use the domain resolution operator for access.
Scenario 2 : You can use member names directly when you use members of a class within a class domain. However, the member name must be declared between use, otherwise it cannot be used. The specific code is as follows:
----------------------A.h----------------------------- Class MyClass { Void SetValue (sb4 Para);//error. Type SB4 cannot be used at this location because the type is not declared before it is used. Typedef int sb4; Void SetValue (sb4 Para);//correct. Type SB4 can be used at this location because the type has been declared between uses. }; |
As you can see, the order in which class members are declared is important, and it affects the use of class members within the class domain.
exception : There is a special case where, when using a class member in an inline function, the declaration part of the inline function is parsed at the current position, and the definition part of the inline function is parsed throughout the class domain. Therefore, in the declaration portion of an inline function, you can only use the name that was declared before it, followed by the rule described in Scenario 2; In the definition part of an inline function, you could use the name declared in the entire class domain directly. See the 2.4.1 section for an example of an inline function in the specific code.
2.5 Local Scope
Variables defined in local scope are local variables, and local variables can be further divided into: automatic variables, register variables, and static local variables. In C + + programs, in addition to local variables, there are other types of variables, such as: global variables, constants, static variables, and variables defined with the new operator, which are distributed in memory as shown:
When an application is launched, a process is started. In a 32 system, allocate 4G of memory space to the process. Under a process, several threads are started as needed, one of which is the main thread. In this 4G of memory space, the following types of storage areas are included:
- The global storage area. In this region, global variables, static variables, and constants are stored. Initialized global variables, static variables are stored in one part of the global store, uninitialized global variables, static variables are stored in another part of the global store, and the heap's declaration cycle runs through the entire program's declaration cycle.
- Heap. In general, a process corresponds to a heap. Storing variables defined using the new operator in the heap;
- Stack. One thread corresponds to a stack. Thread starts, allocates stack space, thread ends, and stack space is retracted. Local variables are stored in the stack. These local variables include the parameters of the function, variables defined inside the function. These variables are freed as the function call is complete.
3 Name parsing
whether variables, functions, enumerations, pointers, references, or types (including built-in types or class types), they must be declared or defined before they are used . Examples are as follows:
Int a = 10; A = a + 1; Class myclass;//declares a category void MyFunction (myclass& objclass)//defines a function. The parameter of the function is a reference to the MyClass type. Although the MyClass class is not yet defined here, it is allowed. { } MyClass * PClass = NULL; Class MyClass { Public: Int M_ivalue; } PClass = new MyClass; MyClass objclass; MyFunction (objclass);//Call function. |
In the statement "int a = 10;" , if the variable "a" is to be defined, then the type "int" must be defined first. Because the type int is a built-in type, it is already defined before the type is used. So in the statement "int a = 10;" , the compiler knows that the variable a allocates four bytes of memory and stores data 10 in that memory location. If the type int is unknown before executing the statement, an undefined error will occur.
In the statement "a = a + 1;" , if you want to execute the statement, the variable a must be defined before the statement. When the statement is executed, the data is fetched from the memory corresponding to variable a, plus 1 and then stored in the corresponding memory of variable A. If the variable A is not previously defined, that is, the variable A is not allocated memory, an error occurs when the statement is executed.
In the statement "MyClass * pClass = NULL;" , the statement can be executed correctly because the MyClass class has been declared before the statement. Note that this is just a declaration, and the class MyClass is not yet defined. This is allowed because, for any type of pointer variable, its size is a fixed four bytes, and in the case of the class declaration, you can define a pointer variable and allocate four bytes of memory for that pointer variable. At this point, the memory that belongs to the pointer does not store the address of the MyClass object, because the MyClass class is not yet defined, and the compiler does not know how much memory is allocated for the object, and the pointer is initialized to NULL. After completing the definition of the MyClass class, execute the statement "PClass = new MyClass;" , the compiler knows how much memory needs to be allocated for the MyClass type object. Therefore, you begin to define an object of type MyClass and store its address in the memory that the pointer Pclass belongs to.
When you define a class object pointer, you can do it in two steps: The first step is to complete the declaration of the class, and after the class declaration, you can define a pointer to the class, which cannot be initialized to a meaningful value, and generally points to null. Second cloth: Complete the definition of the class, after which you can define the object of the class and assign the address of the class object to the pointer.
According to the rules above, within a class definition, you can define a pointer to the class's own type, but you are not allowed to define an object of that class's own type. Examples are as follows:
Class Node { Public: Node * pnext;//is correct, this is allowed. The compiler allocates only four bytes of memory. Node objnext;//error. The class definition has not been completed and the compiler does not know how much memory is allocated. }; Node objnode;//is correct, the class definition is complete, and the compiler knows how much memory should be allocated. |
When defining a pointer or reference to a type, the type can be declared first and then implemented in subsequent sections, which must be defined in advance when using objects such as variables, functions, enumerations, and so on.
In C + +, if you want to use an object entity (such as a built-in type, a class type, a user-defined variable, a function, a pointer, and so on), the object entity must be declared or defined before it is used. When the compiler compiles a C + + program, if an entity name is found in the program code (such as Int,a,myclass in the code above), then the compiler looks for a declaration or definition of that name in the various scopes of C + + (because it needs to know the size of the object's entity memory, the memory address, And in-memory values). We call this process a name resolution .
These scopes that can be looked up by the compiler include: global scope, namespace scope, class domain, local scope, and so on. There are two main issues to be told in this section:
- Rules of name parsing, order;
- The reason for the hidden rule of the variable.
The process and order of name resolution are as follows:
In the process of name parsing, the order of name resolution is to find from the location where the name is used, from small scope to large scope, and when the declaration or definition of that name is found, the name lookup action ends.
When an entity of the same name is defined in two different scopes, the entity defined in the small scope hides the entity defined in the large scope. Because the compiler starts looking from a small scope and finds the definition or declaration of the first name, the name lookup action stops, so the name defined in the small scope hides the name defined in the large scope.
In the, the search order of Clue 1 is: class domain, namespace scope, global scope; The search order of Clue 2 is: local scope, namespace scope, global scope, and the search Order of Clue 3 is: local scope, class domain, namespace scope, global scope; the lookup order of thread 4 is: namespace scope , global scope.
Depending on where the name is used, the name resolution can be divided into the following situations:
- Name resolution is performed in the namespace scope. The namespace includes the global role domain name space, and the user-defined namespace, as well as the namespace nesting situation. At the time of name resolution, the compiler will look for a declaration or definition of the name in the namespace before it is used, starting with where the name is used. If the declaration or definition is found, then the name resolution succeeds, otherwise the outgoing line does not define the error. The compiler does not look for the namespace portion of the name after it is used, so it is not possible to use it before it is defined.
Int a = 10;//is hidden Namespace MySpace [ Int A = 100;//find the definition of a variable here, find stop. If the A variable is not defined here, then the lookup will continue forward until the definition of the A variable is found in the global scope. A = a + 1;//when using a, start looking forward from that position to the definition of a. A =:: A + 1//uses a variable that is hidden in the global scope. } |
- Name resolution is performed in the class definition. The name that is used appears in the header file of the class definition. The order of name resolution is described as follows:
- Look in the class domain. Starting from the location where the name is used, find the domain part of the class before the name is used, and will not find the class domain part after the name is used.
- Look in the namespace scope. Starting at the location defined by the class, find the namespace scope section before the class is defined. Does not find the namespace scope part after the class is defined.
- Looks in the parent scope of the current namespace scope, including the global scope. Finds only the portion of the current namespace that precedes the defined point.
Typedef short mydata;//The type definition is hidden by the definition in MySpace. Namespace MySpace { Typedef int mydata;//finds here, finds the definition of the MyData name, and ends the name resolution. Class MyClass { MyClass (MyData Para);//look forward from this position. The type of para is int. typedef double MYDATA;//The location is not found. } } |
- Name resolution is performed in the class member definition. The name used appears in the CPP file defined by the class member, typically starting at the local scope. The name used may be in the form parameter part of the function, or inside the function body. The order of name resolution is described as follows:
The
- is found in the local scope. Starting from the location where the name is used, find the local scope portion of the name before it is used, and will not find the local scope part after the name is used. The
- is found in the class field. Look in the entire class field, no front or back. This differs from finding in namespace scopes. The
- is located in the namespace scope, as well as the parent scope of the namespace scope, until the global scope. The rules are described in the same 2.
-------------------------------------A.h-------------------------------------- Int MyData = 10;//is hidden Namespace MySpace { Int MyData = 100;//is hidden Class MyClass { Public: Void myFunction (); The name resolution of the INT mydata;//variable is located here. }; Void DealData ()//The name resolution of the function is found here { } } -------------------------------A.cpp-------------------------------- #include "A.h" Void myclass::myfunction () { DealData (myData);//Here, two name parsing is required. First, the name resolution of the function Dealdata (), because the function was defined in the previous global scope when the function was called, so the name resolution was successful. The second name resolves the variable mydata, and the definition of the variable is found in the entire class field. } |
C + + scope (ii)