Accessing Parent Class Members in C++
When building object-oriented programs in C++, inheritance allows you to create new classes (derived classes) that inherit properties and behaviors from existing classes (base or parent classes). Often, a derived class needs to extend the functionality of a parent class method, rather than completely override it. This means you might want to call the parent class’s version of a function from within the derived class’s function. This tutorial explains how to do just that.
The Scope Resolution Operator
The primary way to access members (functions and variables) of a parent class from a derived class is using the scope resolution operator (::
). This operator allows you to explicitly specify which class’s member you are referring to.
Here’s how it works:
class Parent {
public:
void print() {
std::cout << "Parent's print function\n";
}
};
class Child : public Parent {
public:
void print() {
Parent::print(); // Call the parent class's print function
std::cout << "Child's print function\n";
}
};
int main() {
Child c;
c.print();
return 0;
}
In this example:
Child
inherits fromParent
.- Both
Parent
andChild
have a function calledprint()
. - Inside
Child::print()
,Parent::print()
explicitly calls theprint()
function defined in theParent
class. - The output will be:
Parent's print function Child's print function
This demonstrates that you can call the parent class’s function before, after, or even within the derived class’s implementation.
Why Use the Scope Resolution Operator?
There are several scenarios where using the scope resolution operator is crucial:
- Extending Functionality: When you want to add functionality to an inherited function without completely replacing it, call the parent’s function to perform the original behavior.
- Avoiding Ambiguity: If the derived class has a member with the same name as a member in the base class (method overloading or shadowing), the scope resolution operator clarifies which member you intend to use.
- Multiple Inheritance: When a class inherits from multiple base classes, the scope resolution operator becomes essential for specifying which base class’s member you want to access. For example, if you have
Base1
andBase2
, you can callBase1::function()
orBase2::function()
.
Example with Multiple Inheritance
class Left {
public:
void foo() {
std::cout << "Left::foo()\n";
}
};
class Right {
public:
void foo() {
std::cout << "Right::foo()\n";
}
};
class Bottom : public Left, public Right {
public:
void foo() {
Left::foo();
Right::foo();
std::cout << "Bottom::foo()\n";
}
};
int main() {
Bottom b;
b.foo();
return 0;
}
In this case, the Bottom
class inherits from both Left
and Right
, both of which have a foo()
function. The scope resolution operator (Left::foo()
and Right::foo()
) is used to explicitly call the foo()
function from each base class. The output will be:
Left::foo()
Right::foo()
Bottom::foo()
Virtual Functions and Polymorphism
When dealing with inheritance and function overriding, it’s important to understand the concept of virtual functions. Declaring a function as virtual
in the base class allows derived classes to override the function’s behavior while still allowing the base class pointer or reference to call the correct version of the function at runtime (this is known as polymorphism).
class Parent {
public:
virtual void print() {
std::cout << "Parent's print function\n";
}
};
class Child : public Parent {
public:
void print() override {
std::cout << "Child's print function\n";
}
};
int main() {
Parent* ptr = new Child();
ptr->print(); // Calls Child::print() due to the 'virtual' keyword
delete ptr;
return 0;
}
In this case, because Parent::print()
is declared as virtual
, ptr->print()
will call the print()
function defined in the Child
class, even though ptr
is a pointer to a Parent
object. The override
keyword is optional but good practice as it tells the compiler you intend to override a virtual function.
Considerations
- Access Control: You can only access public and protected members of the base class from the derived class. Private members are not accessible.
- Ambiguity: In cases of multiple inheritance, ensure that the use of the scope resolution operator is unambiguous to avoid compilation errors.
By using the scope resolution operator and understanding the concepts of virtual functions, you can effectively leverage inheritance and polymorphism in your C++ programs.