C++ Tutorial

Class and Object

Reference

Inheritance and Derivation

Polymorphism and Virtual Functions

Operator Overloading

Template

Exception

Object Oriented Advanced

Input/Output Stream

File Operations

Name Shadowing In C++ Inheritance

In C++ inheritance, name shadowing occurs when a derived class has a member with the same name as a member in the base class. When this happens, the member of the derived class hides or "shadows" the member of the base class. In this tutorial, we'll cover name shadowing in C++ inheritance and how to avoid it.

  • Include the required headers:

To use the iostream library, include the iostream header.

#include <iostream>
  • Base Class:

Create a base class with a function that will be shadowed in the derived class.

class Base {
public:
    void print() {
        std::cout << "This is the base class print function." << std::endl;
    }
};
  • Derived Class:

Create a derived class with a function that has the same name as the function in the base class.

class Derived : public Base {
public:
    void print() {
        std::cout << "This is the derived class print function." << std::endl;
    }
};
  • Name Shadowing:

When calling the print() function using a derived class object, the derived class version of the function will be called, and the base class version will be shadowed.

int main() {
    Derived d;
    d.print(); // Calls the print() function of the derived class
    return 0;
}

Output:

This is the derived class print function.
  • Avoiding Name Shadowing:

To call the base class version of the function, use the scope resolution operator ::.

int main() {
    Derived d;
    d.Base::print(); // Calls the print() function of the base class
    return 0;
}

Output:

This is the base class print function.

Another way to avoid name shadowing is by using virtual functions. If a base class function is declared as virtual, the compiler will perform a dynamic dispatch, ensuring the correct version of the function is called based on the object type.

Example:

class Base {
public:
    virtual void print() {
        std::cout << "This is the base class print function." << std::endl;
    }
};

class Derived : public Base {
public:
    void print() override {
        std::cout << "This is the derived class print function." << std::endl;
    }
};

int main() {
    Base* base_ptr = new Derived(); // Base class pointer pointing to a derived class object
    base_ptr->print(); // Calls the derived class print function, since it's declared virtual in the base class
    delete base_ptr;
    return 0;
}

Output:

This is the derived class print function.

By understanding name shadowing in C++ inheritance, you can avoid issues when working with derived classes and ensure the correct version of a function is called. Using the scope resolution operator or virtual functions, you can control the behavior of your class hierarchy as needed.

  1. Scope resolution operator and name shadowing in C++:

    • Description: Introduces the scope resolution operator (::) as a mechanism to access hidden or shadowed names in C++.
    • Example Code:
      #include <iostream>
      
      // Base class
      class Base {
      public:
          int value = 10;
      };
      
      // Derived class
      class Derived : public Base {
      public:
          int value = 20;
      
          void displayValues() {
              std::cout << "Derived value: " << value << std::endl;          // Accessing derived class member
              std::cout << "Base value (using scope resolution): " << Base::value << std::endl;  // Accessing base class member
          }
      };
      
      int main() {
          Derived derivedObj;
          derivedObj.displayValues();
          return 0;
      }
      
  2. Preventing ambiguity with name shadowing in C++:

    • Description: Demonstrates how to avoid ambiguity caused by name shadowing in C++ through proper access and qualification.
    • Example Code:
      #include <iostream>
      
      // Base class
      class Base {
      public:
          int value = 10;
      };
      
      // Another Base class with a different member
      class AnotherBase {
      public:
          int value = 30;
      };
      
      // Derived class inheriting from both Base classes
      class Derived : public Base, public AnotherBase {
      public:
          void displayValues() {
              std::cout << "Base value: " << Base::value << std::endl;             // Accessing Base class member
              std::cout << "AnotherBase value: " << AnotherBase::value << std::endl; // Accessing AnotherBase class member
          }
      };
      
      int main() {
          Derived derivedObj;
          derivedObj.displayValues();
          return 0;
      }