What are the rules for virtual function lookup?
Asked Answered
H

3

5
#include <iostream>
class base
{
    public:
    virtual void print (int a)
    {   
        std::cout << "a: " << a << " base\n";
    }   
    virtual void print (int a, int b)
    {   
        std::cout << "base\n";
    }   
};

class derived : public base
{
    public:
    virtual void print (double d)
    {   
        std::cout << "derived\n";
    }   
};

int main ()
{
    int i = 10; 
    double d = 10000.0;
    base *b = new derived (); 
    b->print (i, i); 
    b->print (d);

    return 0;
}

The output of this function is:

base
a: 10000 base
  • Why b->print (d) don't invoke the derived class implementation and performs static cast on 'd' to provide a match with base class implementation ?
  • What rule is applied here during virtual function lookup ?
Hairbrush answered 21/3, 2011 at 0:29 Comment(1)
You're working with the type base, not derived. It doesn't have a function which takes a double, so it's casting to int to find the best match.Ivanaivanah
B
8

derived::print does not override any member function in base. It is declared as having a single parameter of type double but the two virtual member functions named print in base are declared as having one and two parameters of type int.

When you use b->print(d), only member functions in base are considered during overload resolution, so only void base::print(int) and void base::print(int, int) are considered. void derived::print(double) can't be found because the compiler has no idea that b points to a derived object.

If derived were to override one of the two print functions declared as virtual member functions in base, then that override would be called at runtime.

(On a somewhat related note, derived::print hides the two base::print member functions, so if you were to try to use one of the base class print functions, e.g., derived().print(1, 1), it would fail. You would need to use a using declaration to make those member functions available during name lookup.)

Bourgeon answered 21/3, 2011 at 0:33 Comment(0)
I
1

Overload resolution happens at compile time. Overrides happen at run time.

Therefore, the overload resolution of b->print(d); happens first. This selects Base::print(int) because it's the only one-argument print.

At runtime, b points to a Derived object that has no override for Base::print(int). Therefore, Base::print(int) is still called.

Intimidate answered 21/3, 2011 at 10:29 Comment(0)
G
0

Because double can be automatically converted to an int in the first definition it sees (in the base class)

See explicit keyword or this question

Gametophore answered 21/3, 2011 at 0:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.