[ fromfile: scopestorage.xml id: defaultscope ]
We examine the six principal scopes and provide some examples.
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.
A label is an identifier followed by a colon (:).
Labels in C/C++ functions have their own scope.
They are accessible before and after their declaration, throughout the function definition.
C and C++ support a very rarely used and (justifiably) shunned goto
statement that requires a label.
The thing that makes its scope unique is that the label (i.e., the self-declaration) can appear after the first statement (e.g., goto
) that refers to it. Example 20.3 shows an example of the use of the strongly deprecated goto
statement and its related label.
Example 20.3. src/goto/goto.cpp
A related but less dangerous use of labels is in the switch
statement block.
The switch
statement is a computed goto
statement that, because its action is contained within a single block, does not create the same kinds of validation problems that goto
can create.
Example 20.4 shows an example of switch
usage.
Example 20.4. src/switch/switchdemo.cpp
#include <QTextStream> #include "usermanager.h" QTextStream cout(stdout); QTextStream cin(stdin); enum Choices {LOAD = 1, ADD, CHANGE, CHECK, SAVE, LIST, QUIT}; // Function Prototypes void addUsers(UserManager&); void changePassword(UserManager&); Choices menu(); //etc. int main() { // some code omitted while (1) { switch (menu()) { case LOAD: cout << "Reading from file ...\n" << um.loadList() << " loaded to list" << endl; break; case ADD: cout << "Adding users to the list ..." << endl; addUsers(um); break; case SAVE: cout << "Saving changes ...\n" << um.saveList() << " users in file" << endl; break; case CHANGE: cout << "Changing password ..." << endl; changePassword(um); break; case CHECK: cout << "Checking a userid/pw combo ..." << endl; checkUser(um); break; case LIST: cout << "Listing users and passwords ...\n"; um.listUsers(); break; case QUIT: cout << "Exiting the program ..." << endl; return 0; default: cout << "Invalid choice! " << endl; } } }
<include src="src/switch/switchdemo.cpp" href="src/switch/switchdemo.cpp" id="switcheroo" mode="cpp"/>
As we observed in Section 19.2.2, case
labels (other than default) differ from ordinary labels because they are required to be integral constants.
The scope of a case
label is the entire switch
statement so you might call it switch scope.
Labels are sometimes used to solve various compatability problems. For example, labels are used to prevent the C++ compiler from choking on the signals:
and slots:
declarations in certain class definitions (Section 8.3).
Note | |
---|---|
Even though |
Namespace Scope.
An identifier declared inside a namespace
has namespace scope.
It can be used anywhere, below the declaration, inside the namespace
definition.
namespace
definitions are open and can be expanded.
A subsequent definition of the same namespace
simply adds items to it, as you can see in Example 20.5. Any attempt to redefine items inside the namespace
produces a compile error.
Example 20.5. src/namespace/openspace/opendemo.txt
//File: a.h" #ifndef _A_H_ #define _A_H_ #include <iostream> namespace A { using namespace std; void f() { cout << "f from A\n"; } void g() { cout << "g from A\n"; } } #endif //File: new-a.h #ifndef NEW_A_H_ #define NEW_A_H_ #include <iostream> namespace A { //void k() { h(); } //void g() { cout << "Redefine g()/n"; } void h() { cout << "h from newA\n"; g(); } } #endif File: opendemo.cpp #include "a.h" #include "new-a.h" int main() { using namespace A; f(); h(); } /*Run openspace> ./a.out f from A h from newA g from A openspace> */
<include src="src/namespace/openspace/opendemo.txt" href="src/namespace/openspace/opendemo.txt" id="opendemo" mode="cpp"/>
An identifier declared inside a class
definition has class scope.
Class Scope is anywhere in the class
definition [113] or in the bodies of member functions. [114]
File Scope.
An identifier whose declaration is not between curly braces can have file scope if it is declared static
.
Its scope extends from the declaration to the end of the file.
The keyword static
hides the identifier from other source files and restricts its scope to the file in which it was declared.
File Scope variables cannot be declared extern
and accessed from another file.
File Scope variables, because they are not exported, do not expand (pollute) the global namespace.
They are often used in C programs because C does not have an implementation hiding feature like private
for class members.
Note | |
---|---|
File scope is available in C++ for backward compatibility with C, but namespaces or static class members should be used instead whenever possible. |
Global Scope.
An identifier whose declaration is not between curly braces, and is not declared static
, is said to have global scope.
The scope of such an identifier begins at the declaration and extends from there to the bottom of the source code file, but it can be extended to other source files with the use of the extern
keyword.
The extern
declaration may be used to access a globally defined identifier in other source files.
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 a public static
class member or a namespace
member.
Because a compiler deals with one source file at a time, only the linker (or a template-compiler) makes a strong distinction between global and file scope, as Example 20.6 shows.
Example 20.6. 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; // OK, share variable space static int g3; // okay, 2 different variable spaces (etc.)
An identifier in a namespace
can be made available globally through the use of the scope resolution operator, NamespaceName::
.
It can also be made available to other scopes without using scope resolution through the using
keyword.
Namespace variables and static class members have static storage and can be made accessible globally. They are like global variables, except that they do not enlarge (pollute) the global namespace. See Section 20.4 for more details.
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |