Consider the following snippet of code:
#include <iostream>
class Base {
public:
Base() {
std::cout << "Base::constr" << std::endl;
print();
}
virtual ~Base() = default;
void print() const { printImpl(); }
private:
virtual void printImpl() const {
std::cout << "Base::printImpl" << std::endl;
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "Derived::constr" << std::endl;
}
private:
void printImpl() const override {
std::cout << "Derived::printImpl" << std::endl;
}
};
int main() {
Base* ptr = new Derived();
ptr->print();
delete ptr;
}
The above code will print the following:
Base::constr
Base::printImpl
Derived::constr
Derived::printImpl
but I don't understand why printImpl private function is accessible from the base's print function. In my understanding this pointer implicitly passed to the print function holds the derived object's address, but I thought private member functions could be called ONLY from the member functions (and from friend functions) of the same class and here, Base class is not the same class as Derived, although there is an is a relationship.
First, as @Eljay notes -
printImpl()is a method, albeit virtual, of theBaseclass. So, it's accessible from the base class.Derivedmerely provides a different implementation of it. And the whole point of virtual functions is that you can call a subclass' override using a base class reference or pointer.In other words,
privateonly regards access by subclasses; it's meaningless to keep somethingprivatefrom a class' base class: If a method is at all known to the base class, it must be a method of the base class... a virtual method.Having said all that - note that the
Derivedversion ofprintImpl()is effectively inaccessible fromprint()- when it's invoked within the base class constructor. This is because during that call, the constructed vtable is only that ofBase, soprintImplpoints toBase::printImpl.And indeed,
print()is a member ofBase, which invokesprintImpl()- another method ofBase.