The difference between
pa->foo();
and
pa->print();
is caused by a simple fact:
The type of a pointer instructs the compiler as to how to interpret the memory found at a particular address and also just how much memory that interpretation should span
, from book Inside the C++ object model.
In other words, when compiler tries to translate this line of code pa->foo()
, he only knows that pa is a pointer of class A and foo is function of class A. Although we know in fact pa points to a block of memory of class B, compiler doesn't and can't know that fact. He just resolve pa as a pointer of class A and find A's definition of function foo. Yet the magic of pa->print()
is due to the virtual function implementation of C++. For a normal function, compiler just parse its name and jump to the start address of that function. However, for a virtual function, compiler will first find the vptr pointer from the memory pointed by the pointer pa and resolve the vptr to find the right definition of print function. Because this time compiler reads the vptr from memory and the memory is in fact belong to class B, B's print will be called.
Here is another example to illustrate it:
// What gets printed?
#include <iostream>
using namespace std;
class A {
public:
int b;
A(int a = 5) : i(a) {
b = 42;
cout << "A" << endl;
}
void foo() { cout << "this.i " << i << endl; }
virtual void print() const { cout << i << " in A" << endl; }
protected:
int i;
};
class B : public A {
public:
int b;
B() : A(1) {
b = 43;
cout << "B default" << endl; }
void foo() { cout << i << " in B" << endl; }
void print() const { cout << i << " in B" << endl; }
};
int main() {
A *pa;
B b;
pa=&b;
cout << pa->b << endl;
cout << b.A::b << ", " << b.b << endl;
//pa->foo();
//pa->print();
return 0;
}
The output is
A
B default
42
42, 43
By the way, virtual function mechanism only works on pointer or reference, because for a object A, A.print()
must resolve to vptr in a block of memory of class A which is A's print function