Scope

Learn more about how and when we can access variables, by understanding the importance of the scope in which they exist.
This lesson is part of the course:

Intro to C++ Programming

Become a software engineer with C++. Starting from the basics, we guide you step by step along the way

Free, Unlimited Access
3D art of a man using a telescope
Ryan McCombe
Ryan McCombe
Updated

In programming, we can imagine our code being split into regions, sometimes referred to as scopes.

When we declare a variable in one region or scope, it may not necessarily be accessible to other scopes.

Global / File Scope

We have thus far been declaring our variables at the top of our files, outside of any function body. This scope is sometimes referred to as the global scope, also known as the file scope.

This is because, as we’ve seen, we’ve been able to freely access these variables anywhere within our file:

#include <iostream>
using namespace std;

int x{42};

void Log(){ cout << "x is " << x; }

int main(){
  Log();
  cout << "\nit's definitely " << x;
}
x is 42
it's definitely 42

But this is not the only place we can declare variables. For example, we can also create variables within the scope of a function, by placing it between the { and } of the function’s body.

Below, we’ve moved our x variable into the scope of our Log function. As a result, it is no longer in the global scope, and is therefore no longer accessible by our main function.

As such, our code throws a compilation error:

#include <iostream>
using namespace std;

void Log(){
  int x{42};
  cout << "x is " << x;
}

int main(){
  Log();
  cout << "\nit's definitely " << x;
}
error: 'x': undeclared identifier

Block Scope

Block scopes are created when we have a pair of curly braces {} in our code. For example, function bodies create a block scope, as we’ve seen above.

This concept isn't limited to function bodies - for example, if and else statements can also create a block scope. Let's see an example:

#include <iostream>
using namespace std;

int main() {
  bool shouldLog{true};
  if (shouldLog) {
    string Message{"Hello World"};
  }
  cout << Message;
}
error: `Message`: undeclared identifier

In this code, the variable Message is declared within the if statement's block. Consequently, Message only exists within this block and is inaccessible outside of it.

When we try to use Message outside of its block (here, in the cout statement), the compiler throws an error. This is because Message is not recognized outside its defining block.

Block scopes do not need to be associated with functions or if statements - we can open a set of curly braces any time we want, thereby creating a new scope.

It’s somewhat uncommon to do this, but it highlights the key point:

#include <iostream>
using namespace std;

int main() {
  {
    string Message{"Hello World"};
  }
  cout << Message;
}
error: `Message`: undeclared identifier

Function Parameter Scope

Function parameters are scoped to the block of the function for which they are defined. That is, they have the same scope as if they had been variables declared within the function body.

Scope Access Rules

In C++, the scope access rules govern how different parts of a program can access variables.

The key rule is: a scope can access variables from its parent scopes, but not from its child scopes. The previous errors were all caused by code in a scope trying to access a variable in a nested, or child scope.

Previously, we’ve been writing code in function scopes that access variables in parent scopes (typically, the global scope). As we’ve seen, that has been successful:

#include <iostream>
using namespace std;
string Message{"Hello World"};

int main(){
  // Accessing variable in parent scope
  cout << Message; 
}
Hello World

Below, we show another variation of a child scope successfully accessing a variable in a parent scope:

#include <iostream>
using namespace std;

int main(){
  bool shouldLog{true};
  string Message{"Hello World"};
  if (shouldLog) {
    // Accessing variable in parent scope
    cout << Message;
  }
}
Hello World

Here, Message is declared in the main function's scope. The if statement within main represents a child scope, nested within the main function’s scope.

As such, variables declared in main (parent scope) can be accessed in the if statement (child scope).

Test your Knowledge

Scope Access

What will the following function return?

int GetInt() {
  int x{1};
  { x++; }
  return x;
}

What will the following function return?

int GetInt() {
  {
    int x{1};
    x++;
  }
  return x;
}

Shadowed Variables / Name Hiding

Shadowing or name hiding in C++ occurs when two variables in different scopes have the same name.

The variable in the inner scope "shadows" the variable in the outer scope, making the outer variable inaccessible within the inner scope. Here's an example to demonstrate this concept:

#include <iostream>
using namespace std;

int main(){
  int x{1};
  {
    // This 'x' shadows the outer 'x'
    int x{2};
    cout << "Inner x: " << x; // Outputs 2
  }
  cout << "\nOuter x: " << x; // Outputs 1
}
Inner x: 2
Outer x: 1

In this example, there are two variables named x. The x inside the block is separate and shadows the x declared in the main function.

Within the block, any reference to x refers to the inner x (with value 2), not the outer x (with value 1). When the block ends, the inner x goes out of scope, and the outer x becomes accessible again.

Shadowing is typically something we want to avoid, as it can lead to confusion and bugs. However, it’s still important to understand what’s going on here, so we can ensure we’re accessing the correct variables.

Test your Knowledge

Variable Shadowing

What will the following function return?

int GetInt() {
  int x{1};
  {
    int x{2};
  }
  return x;
}

Preview: Designing with Scopes

Right now, the rules and complexes around scopes might seem a bit much, especially given how simple our programs are.

As our projects become more complex, we’ll come to appreciate and embrace scoping to make our program more manageable.

We'll soon learn to use the scope resolution operator and namespaces, which help access and group code across different scopes, helping us with this task.

Summary

In this lesson on scope in C++, you've learned several key concepts:

  • Global/File Scope: Variables declared outside any function have global scope and can be accessed anywhere within the file.
  • Block Scope: Variables declared within a set of {} are only accessible within those braces.
  • Scope Access Rules: A scope can access variables from its parent scopes but not from its child scopes.
  • Shadowed Variables/Name Hiding: When two variables with the same name exist in different scopes, the one in the inner scope shadows the one in the outer scope.

Preview of the Next Lesson: Forward Declaration

In the next lesson, we will delve into the concept of forward declaration, focusing on its application in functions.

Forward declaration allows you to inform the compiler about the existence of an entity (like a function) before you provide its complete definition.

This technique can help in organizing and structuring your code more effectively. We'll explore:

  • What is a forward declaration
  • What is a circular dependency, and how can forward declarations solve them
  • Practical examples demonstrating forward declaration with functions.

Was this lesson useful?

Next Lesson

Forward Declarations

Understand what function prototypes are, and learn how we can use them to let us order our code any way we want.
3D art showing a technician character
Ryan McCombe
Ryan McCombe
Updated
Lesson Contents

Scope

Learn more about how and when we can access variables, by understanding the importance of the scope in which they exist.

3D art showing a progammer setting up a development environment
This lesson is part of the course:

Intro to C++ Programming

Become a software engineer with C++. Starting from the basics, we guide you step by step along the way

Free, Unlimited Access
3D art showing a progammer setting up a development environment
This lesson is part of the course:

Intro to C++ Programming

Become a software engineer with C++. Starting from the basics, we guide you step by step along the way

Free, unlimited access

This course includes:

  • 56 Lessons
  • Over 200 Quiz Questions
  • 95% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Next Lesson

Forward Declarations

Understand what function prototypes are, and learn how we can use them to let us order our code any way we want.
3D art showing a technician character
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved