When a variable with the same name is declared inside a nested block, it can “hide
” or “shadow
” a variable with the same name in an outer block. This phenomenon is known as name hiding or shadowing.
What is Variable Shadowing❔
Variable shadowing occurs when a variable declared in an inner scope (like a block or a function) has the same name as a variable declared in an outer scope. The inner variable "shadows" the outer variable, making the outer variable inaccessible within the inner scope.
Example 1:
#include <iostream>
int main() {
// Outer block
int apples { 5 }; // Outer block apples
{ // Nested block
// Inner block apples refers to outer block apples
std::cout << apples << '\n'; // Output: 5
int apples{ 0 }; // Define apples in the scope of the nested block
// Inner block apples now refers to the nested block apples
// The outer block apples is temporarily hidden
apples = 10; // Assign value 10 to nested block apples, not outer block apples
std::cout << apples << '\n'; // Output: 10
} // Nested block apples destroyed
std::cout << apples << '\n'; // Output: 5 (Outer block apples remains unaffected)
return 0;
} // Outer block apples destroyed
In this example, a variable named apples
is declared in both the outer and nested blocks. The inner block's apples
temporarily hides the outer block's apples
within its scope.
Example 2:
#include <iostream>
int main() {
// Outer block
int apples { 5 }; // Outer block apples
{ // Nested block
// Inner block apples refers to outer block apples
std::cout << apples << '\n'; // Output: 5
// No inner block apples defined in this example
apples = 10; // This applies to outer block apples
std::cout << apples << '\n'; // Output: 10
} // Outer block apples retains its value even after leaving the nested block
std::cout << apples << '\n'; // Output: 10 (Outer block apples remains unaffected)
return 0;
} // Outer block apples destroyed
In this example, since there is no inner block variable apples
defined, the name apples
within the nested block still refers to the outer block's apples
.
Shadowing of Global Variables
#include <iostream>
int value { 5 }; // Global variable
void foo() {
std::cout << "Global variable value: " << value << '\n'; // Global value is not shadowed here
}
int main() {
int value { 7 }; // Hides the global variable value until the end of this block
++value; // Increments local value, not global value
std::cout << "Local variable value: " << value << '\n';
foo();
return 0;
} // Local value is destroyed
In this example, a local variable value
inside the main
function shadows the global variable value
within its scope. The global variable is accessible using the scope operator (::
).
1 Shadowing Hierarchy:
- When accessing a variable, the compiler looks for the nearest declaration first (inner scope) and then moves outward (outer scope).
2 Avoiding Shadowing:
- To prevent confusion, it’s best to avoid naming variables in inner scopes the same as those in outer scopes. Use meaningful names to increase code readability.
3 Use of ::
Operator:
- In C++, you can access the outer variable explicitly using the scope resolution operator
::
, especially if you want to refer to the outer variable inside the inner scope.
#include <iostream>
using namespace std;
int var = 7;
int main()
{
int var = 1;
cout << ::var;
}
// Output
7
Best Practices
1 Avoid Variable Shadowing:
- Shadowing of local and global variables should generally be avoided, as it can lead to inadvertent errors where the wrong variable is used or modified.
2 Use Meaningful Prefixes:
- Consider using meaningful prefixes, such as “
g_
” for global variables, to differentiate them from local variables. This practice enhances code readability and helps avoid shadowing issues.
3 Limit Scope:
- Keep variable scopes as small as possible. Use local variables within functions or blocks to reduce the likelihood of shadowing.
void process() {
int result; // Limited to this function
}
4 Explicitly Reference Outer Variables:
- If you need to access a shadowed variable, use the scope resolution operator
::
to refer explicitly to the outer variable.
std::cout << "Global count: " << ::globalCounter << std::endl;