Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A counter-intuitive function call in C++

Tags:

c++

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:

  1. 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?

  2. 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?

like image 281
Vanilla Avatar asked Jun 16 '16 05:06

Vanilla


3 Answers

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()

  1. 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.

  2. 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.

like image 180
Mohit Jain Avatar answered Oct 23 '22 07:10

Mohit Jain


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.

like image 33
PcAF Avatar answered Oct 23 '22 07:10

PcAF


  1. When it is non virtual the call to print is not overridden by the subclass and thus prints "Foo".

  2. 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.

like image 29
Ely Avatar answered Oct 23 '22 06:10

Ely