The scope of a name binding - an association of a name to an entity, such as a variable or function - is the region of a computer program where the binding is valid, i.e., where the name can be used to refer to the entity. In other parts of the program, the name may refer to a different entity (it may have a different binding), or to nothing at all (it may be unbound).
There are many kinds of scope in C++; for our purposes, three of them are important:
Block scope (a.k.a. local scope): A name declared within a block of code enclosed by braces ({ }
) is accessible only within that block and blocks enclosed by it, and only after the point of declaration. Function parameter names have block scope, as if they had been declared inside the block enclosing the function body.
For example, in the following code, the variables radius
, area
, and r
all have block scope. The highlighted areas show the scope of the variables:
Scope of the variable radius
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
const double PI = 3.14159;
double circle_area(double);
int main()
{
double radius;
cout << "Enter a radius: ";
cin >> radius
double area = circle_area(radius);
cout << "Area: " << area;
return 0;
}
double circle_area(double r)
{
return PI * r * r;
}
Scope of the variable area
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
const double PI = 3.14159;
double circle_area(double);
int main()
{
double radius;
cout << "Enter a radius: ";
cin >> radius
double area = circle_area(radius);
cout << "Area: " << area;
return 0;
}
double circle_area(double r)
{
return PI * r * r;
}
Scope of the variable r
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
const double PI = 3.14159;
double circle_area(double);
int main()
{
double radius;
cout << "Enter a radius: ";
cin >> radius
double area = circle_area(radius);
cout << "Area: " << area;
return 0;
}
double circle_area(double r)
{
return PI * r * r;
}
Block scope variables are also called local variables.
File scope (a.k.a. global scope): Any name declared outside all code blocks or classes has file scope. Such a name is visible anywhere in the file after its declaration.
For example, in the following code, the variable PI
has been declared at file scope. The highlighted area shows the scope of PI
:
Scope of the variable PI
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
const double PI = 3.14159;
double circle_area(double);
int main()
{
double radius;
cout << "Enter a radius: ";
cin >> radius
double area = circle_area(radius);
cout << "Area: " << area;
return 0;
}
double circle_area(double r)
{
return PI * r * r;
}
File scope variables are also called global variables.
Class scope: Names of class members (data members and member function names) have class scope. Names with class scope are accessible in all of the member functions of the class. Code outside the class may access the class scope names only if they are public. In addition, non-static
class members must be accessed through an object - the object name, a reference to the object, or a pointer to the object will suffice - and the appropriate member selection operator.
Variables declared inside a member function (including the function's parameters) have block scope, not class scope.
Variable shadowing occurs when a variable declared within a given scope has the same name as a variable declared in an outer scope. The outer variable is said to be shadowed. This can lead to confusion, as it may be unclear which variable subsequent uses of the variable name refer to. Here are some examples of shadowing:
In the following code fragments, the scope of the outer variable is shown highlighted in yellow. The scope of inner variables that shadow the outer variable is shown highlighted in blue or green.
A block scope variable in an inner block shadows a block scope variable declared with the same name in an outer block
void fn()
{
int x = 25;
cout << "Outer x is " << x << endl;
for (int x = 0; x < 5; x++)
cout << "Inner x is " << x << endl;
cout << "Outer x is " << x << endl;
}
A block scope variable shadows a file scope variable with the same name
int x = 25;
void fn1()
{
cout << "Global x is " << x << endl;
}
void fn2()
{
cout << "Global x is " << x << endl;
for (int x = 0; x < 5; x++)
cout << "Local x is " << x << endl;
cout << "Global x is " << x << endl;
}
void fn3(int x)
{
x = x + 5;
cout << "Parameter x is " << x << endl;
}
A block scope variable in a member function of a class shadows a class scope data member of the class with the same name
class Student
{
private:
char name[31];
double gpa;
public:
// Constructors
Student();
Student(const char*, double);
void set_name(const char*);
const char* get_name() const;
...
};
...
void Student::set_name(const char* name)
{
strcpy(name, name);
}
const char* Student::get_name() const
{
return name;
}
(The code above is rather ridiculous if you bother to think about it even a little bit. In the function set_name()
, how could the compiler possibly tell that our first use of the name
in the strcpy()
function call is supposed to refer to the class scope data member, while the second use is supposed to refer to the block scope function parameter? It can't. What the code above actually does is copy the function parameter name
into itself, leaving the data member name
untouched.)
Accessing Shadowed Variables
In some cases, it is still possible to access a shadowed variable.
A global variable shadowed by a local variable or parameter may be accessed by prefixing the global variable name with the unary scope resolution operator ::
. For example:
int x = 25;
void fn1()
{
cout << "Global x is " << x << endl;
}
void fn2()
{
cout << "Global x is " << x << endl;
for (int x = 0; x < 5; x++)
{
cout << "Local x is " << x << endl;
cout << "Global x is " << ::x << endl;
}
cout << "Global x is " << x << endl;
}
void fn3(int x)
{
x = x + 5;
cout << "Parameter x is " << x << endl;
cout << "Global x is " << ::x << endl;
}
A class scope data member shadowed by a block scope variable or parameter may be accessed by explicitly using the this
pointer. For example:
class Student
{
private:
char name[31];
double gpa;
public:
// Constructors
Student();
Student(const char*, double);
void set_name(const char*);
const char* get_name() const;
...
};
...
void Student::set_name(const char* name)
{
strcpy(this->name, name);
}
const char* Student::get_name() const
{
return name;
}
It is not possible to access a block scope variable declared in an outer block that has been shadowed by a block scope variable declared in an inner block. Luckily, the C++ compiler will warn you about doing that.