Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Virtual functions with different argument types

I'm trying to understand how virtual functions work, and I am stuck at a certain part.

I have written this small programm:

class First
{
public:
    virtual void f(int a) 
    {
        cout << "First!" << endl;
        cout << a << endl;
    }
};

class Second : public First
{
public:
    void f(int a) {
        cout << "Second!" << endl;
        cout << a << endl;
    }
};

void main() {
    Second s;
    First *p = &s;
    p->f(5);
    First n;
    p = &n;
    p->f(3);
    _getch();
}

This code results in:

Second!
5
First!
3

However, if I change int in the Second::f() function to a different type, like this:

class First
{
public:
    virtual void f(int a) {
        cout << "First!" << endl;
        cout << a << endl;
    }
};

class Second : public First
{
public:
    void f(double a) { //double instead int here!
        cout << "Second!" << endl;
        cout << a << endl;
    }
};

void main() {
    Second s;
    First *p = &s;
    p->f(5);
    First n;
    p = &n;
    p->f(3);
    _getch();
}

My program never calls Second::f(), and I'm getting this as a result:

First!
5
First!
3

Can someone explain to me why this happens?

like image 932
Evgeny Avatar asked Apr 26 '17 20:04

Evgeny


1 Answers

When using virtual function dispatch, the so-called "final overrider" is what gets called. For a function to even override an inherited virtual function, it must meet some criteria:

If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (8.3.5), cv-qualification, and refqualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf.

-- ISO/IEC 14882:2001(E) §10.3 (bold emphasis mine)

Quite simply, in your second example the parameter list for Second::f(double) differs from that of First::f(int), so Second::f(double) is not (automatically) virtual and does not override First::f(int).

The C++11 keyword override declares your intent that a method override an inherited virtual method so that the compiler can tell you when it does not. For example, had you done this instead:

void f(double a) override {

The compiler would have given you this diagnostic to inform you that it doesn't actually override anything, and it even informs you why it doesn't ("type mismatch at 1st parameter ('int' vs 'double')"):

main.cpp:15:18: error: non-virtual member function marked 'override' hides virtual member function
void f(double a) override { //double instead int here!
                 ^
main.cpp:7:14: note: hidden overloaded virtual function 'First::f' declared here: type mismatch at 1st parameter ('int' vs 'double')
virtual void f(int a) {
             ^
like image 185
cdhowie Avatar answered Sep 30 '22 04:09

cdhowie