A quite simple C++ code:
#include <iostream>
using namespace std;
class Foo {
public:
void callPrint() {
print();
}
void print() {
cout << "Foo" << endl;
}
};
class Bar : public Foo {
public:
void print() {
cout << "Bar" << endl;
}
};
int main() {
Bar b;
b.callPrint();
return 0;
}
Here the output is "Foo". And if I make the "Foo::print()" virtual, the output will be "Bar". My questions are:
When the Foo::print()
is non-virtual, why is it called when a Bar
object is passed to Foo::callPrint()
, is there type (both static and dynamic) mismatch?
When Foo:callPrint()
is virtual, the call b.callPrint()
is not via reference or pointer, however Bar::print()
is called. This is not so-called polymorphism, then how to explain this behavior, according to either language definition or compiler implementation?
When you call b.callPrint();
, control transfers to function callPrint
in base class. Now the type of this
is Foo *
which points to an object of Bar *
. Now when you call print()
or this->print()
In case of non virtual function, the called function is decided at compile time on basis of type of this
and thus Foo::print
is invoked.
In case of virtual function, the called function is decided at run times based on the type of pointed object, and thus Bar::print
is invoked.
Do you want to add more fun? Make the function Foo::print()
a virtual
function and call it from the constructor of Foo
and create an object of Bar
.
Standard has nice paragraph (10.3/9):
[ Note: The interpretation of the call of a virtual function depends on the type of the object for which it is called (the dynamic type), whereas the interpretation of a call of a non-virtual member function depends only on the type of the pointer or reference denoting that object (the static type) (5.2.2). — end note ]
print()
is called on implicit this
whose (when dereferenced) dynamic type is Bar
, however inside callPrint()
it's static type is Foo
.
When it is non virtual the call to print
is not overridden by the subclass and thus prints "Foo".
When it is virtual the call to print is overridden by the subclass and thus the prints "Bar".
This is expected behaviour. When you declare a method as virtual then you are saying that the behaviour of the class depends on its subclasses and can (has to) be overridden. You cannot understand the behaviour of a virtual class without knowing all its subclasses.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With