Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the rules for virtual function lookup?

#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 ?
like image 584
lava Avatar asked Mar 21 '11 00:03

lava


2 Answers

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

like image 197
James McNellis Avatar answered Sep 20 '22 09:09

James McNellis


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.

like image 41
MSalters Avatar answered Sep 18 '22 09:09

MSalters