Identifier Scope
Every identifier has a scope that is determined by where it is declared. Identifier Scope in a program is the region(s) of the program within which the identifier can be used. Using a name outside of its scope is an error.
The same name may declared/used in different scopes. Ambiguities are resolved as follows:
- The name from the most local scope is used.
- If the name is not defined in the most local scope, the same name defined in the nearest enclosing scope will be used.
- If the name is not defined in any enclosing scope, then the compiler will report an error.
There are five possible scopes in C++.
- Block scope (local to a block of statements)
- Function scope (the entire extent of a function)[1]
[1] Only labels have function scope.
- Class scope (the entire extent of a class, including its member functions)
- File scope (the entire extent of a source code file)
- Global scope (the entire extent of a program)
Because the compiler only deals with one source file at a time, only the Linker can tell the difference between global and file scope, as Example 20.3 shows.
Example 20.3. Global versus File scope
// In File 1: int g1; // global int g2; // global static int g3; // keyword static limits g3 to file scope (etc.) // In File 2: int g1; // linker error! extern int g2; // okay, share variable space static int g3; // okay: 2 different variable spaces (etc.) |
20.2.1. Default Scope of Identifiers: A Summary
Let's look at the five scopes in a bit more detail.
- Block scope. An identifier declared inside curly braces (excluding namespace blocks) { . . . } or in a function parameter list has block scope. Block scope extends from the declaration to the enclosing right brace.
- Function scope. Labels in C/C++ have their own scope. They are accessible before and after their declaration, for the whole function. C supports a very rarely used and often shunned goto statement that requires a label. The thing that makes its scope unique is that the label (the declaration) can appear after the first goto that uses it. Example 20.4 shows an example of its use. goto is seldom used by serious programmers but labels, because they exist, sometimes pop up in code and are used to solve various compatibility problems.[2]
[2] Such as preventing the C++ compiler from choking on the signals: and slots: declarations.
Avoid goto and labels in your code.
- Class scope. An identifier that is declared inside a class definition has class scope. Class scope is anywhere in the class definition[3] or in the bodies of member functions.[4]
[3] Including inline function definitions above the declarations of referred members
[4] Keeping in mind that the scope of non-static members excludes the bodies of static member functions
- File scope. This is basically the same as global scope, except that file scope variables are not exported to the linker. The keyword static hides an identifier from other source files and gives it file scope. File scope variables cannot be declared extern and accessed from another file.
File scope variables, because they are not exported, do not pollute the global namespace. They are often used in C programs because C has no concept of private class members.
File scope is available in C++ for backward compatibility with C, but we prefer to use namespaces or static class members instead.
- Global scope. An identifier whose declaration is not in between braces (round or curly) has global scope. The scope of such an identifier begins at the declaration and extends from there to the bottom of the source code file. extern declarations may be used to access global definitions in other source files.
An identifier in a namespace is available from other scopes through the using keyword. It is also available globally through the use of the scope resolution :: operator. Namespace variables and static class members are accessible globally and have static storage, like global variables, except that they do not enlarge the global namespace. See Section 20.4 for more details.
Use of global scope for variables is unnecessary in C++. In general, only classes and namespaces should be defined in global scope. If you need a "global" variable, you can achieve something similar through the use of public static class member or a namespace member. |
Example 20.4. src/goto/goto.cpp
[ . . . . ] int look() { int i=0; for (i=0; i<10; ++i) { if (i == rand() % 20) goto found; <-- 1 } return -1; found: <-- 2 return i; } [ . . . . ] (1)It would be better to use break or continue. (2)goto serves as a forward declaration to a label. |
20.2.2. File Scope versus Block Scope and operator::
We have seen and used the scope resolution operator to extend the scope of a class or access its members with ClassName::. A similar syntax is used to access the individual symbols in a namespace with NamespaceName::. C++ also has a (unary) file scope resolution operator, ::, that provides access to global, namespace, or file scope objects from inside an enclosed scope. The following exercise deals with the use of this operator with various scopes.
Exercise: File Scope Versus Block Scope and Operator::
Determine the scope of each of the variables in Example 20.5. Then be the computer and predict the output of the program.
Example 20.5. src/early-examples/scopex.cpp
#include using namespace std; long x = 17; float y = 7.3; <-- 1 static int z = 11; <-- 2 class Thing { int m_Num; <-- 3 public: static int sm_Count; <-- 4 Thing(int n = 0) : m_Num(n) {++sm_Count;} ~Thing() {--sm_Count;} int getNum() { return m_Num; } }; int Thing::sm_Count = 0; Thing t(11); int fn(char c, int x) { <-- 5 int z = 5; <-- 6 double y = 6.933; { char y; <-- 7 Thing z(4); <-- 8 y = c + 3; ::y += 0.3; <-- 9 cout << y << endl; <-- 10 } cout << Thing::sm_Count << endl; <-- 11 y /= 3.0; <-- 12 ::z++; <-- 13 cout << y << endl; return x + z; } int main() { int x, y = 10; char ch = 'B'; <-- 14 x = fn(ch, y); cout << x << endl; cout << ::y << endl; <-- 15 cout << ::x / 2 << endl; cout << ::z << endl; } (1)Scope: ________________ (2)Scope: ________________ (3)Scope: ________________ (4)Scope: ________________ (5)Scope: ________________ (6)Scope: ________________ (7)Scope: ________________ (8)Scope: ________________ (9)Scope: ________________ (10)Scope: ________________ (11)Scope: ________________ (12)Scope: ________________ (13)Scope: ________________ (14)Scope: ________________ (15)Scope: ________________ |