Mastering Inheritance and Shadowing in OOPLearn how to harness the power of inheritance in object-oriented programming, including how to handle function shadowing, access hidden base class functions, and use virtual functions to achieve polymorphism.

Unlocking the Power of Inheritance in Object-Oriented Programming

Inheritance is a fundamental concept in object-oriented programming (OOP) that enables the creation of derived classes from a base class. This powerful feature allows derived classes to inherit characteristics from their base class, making it possible to build complex systems with ease.

The Magic of Shadowing

But what happens when a derived class defines a function with the same name as one in its base class? This phenomenon is known as shadowing, where the derived class’s function takes precedence over the base class’s function. For instance, consider a scenario where we define a print() function in both a Base and a Derived class.

class Base {
public:
    void print() {
        std::cout << "Base class" << std::endl;
    }
};

class Derived : public Base {
public:
    void print() {
        std::cout << "Derived class" << std::endl;
    }
};

When we call the print() function using an object of the Derived class, the print() function of the Derived class executes, effectively shadowing the print() function of the Base class.

Accessing Shadowed Functions

So, how do we access the shadowed function of the base class? The answer lies in using the scope resolution operator ::. By employing this operator, we can explicitly call the shadowed function from the base class. Alternatively, we can use a pointer of the base class to point to an object of the derived class and then call the function from that pointer.

int main() {
    Derived obj;
    obj.print(); // Output: Derived class

    obj.Base::print(); // Output: Base class

    Base* ptr = &obj;
    ptr->print(); // Output: Base class

    return 0;
}

Real-World Examples

Let’s dive into some practical examples to illustrate these concepts:

Example 1: Shadowing in Action

In this example, we define a print() function in both the Base and Derived classes. When we call the print() function from a Derived object, the print() function of the Derived class executes, shadowing the print() function of the Base class.

class Base {
public:
    void print() {
        std::cout << "Base class" << std::endl;
    }
};

class Derived : public Base {
public:
    void print() {
        std::cout << "Derived class" << std::endl;
    }
};

int main() {
    Derived obj;
    obj.print(); // Output: Derived class

    return 0;
}

Example 2: Accessing Shadowed Functions

Here, we demonstrate how to access the shadowed print() function of the Base class using the scope resolution operator ::.

int main() {
    Derived obj;
    obj.Base::print(); // Output: Base class

    return 0;
}

Example 3: Calling Shadowed Functions from Derived Classes

In this example, we show how to call the shadowed print() function from the Base class inside the Derived class itself.

class Derived : public Base {
public:
    void print() {
        std::cout << "Derived class" << std::endl;
        Base::print(); // Output: Base class
    }
};

int main() {
    Derived obj;
    obj.print();

    return 0;
}

Example 4: Using Pointers to Access Shadowed Functions

In this final example, we create a pointer of Base type that points to a Derived object. When we call the print() function using this pointer, it calls the print() function of the Base class.

int main() {
    Derived obj;
    Base* ptr = &obj;
    ptr->print(); // Output: Base class

    return 0;
}

The Power of Virtual Functions

To override the base function instead of accessing it, we need to employ virtual functions in the base class. By doing so, we can ensure that the correct function is called based on the object’s type, rather than its declared type.

class Base {
public:
    virtual void print() {
        std::cout << "Base class" << std::endl;
    }
};

class Derived : public Base {
public:
    void print() override {
        std::cout << "Derived class" << std::endl;
    }
};

int main() {
    Base* ptr = new Derived();
    ptr->print(); // Output: Derived class

    return 0;
}

Leave a Reply