3

I am reading a C++ puzzle here: http://gotw.ca/gotw/005.htm

I did not understand his explanation on static vs dynamic overload resolution (or default paramaters), so I tried to distill the issue and write some tests myself:

class Base {
    public:
    virtual void foo() {cout << "base/no parameters" << endl;}
    virtual void foo(int a) {cout << "base/int" << endl;}
};

class Derived : public Base {
    public:
    void foo() {cout << "derived/no parameters" << endl;}
    void foo(double a) {cout << "derived/int" << endl;}
};

int main() {
    Base* ptr = new Derived;
    ptr->foo();
    ptr->foo(1.0);
}

The output is:

derived/no parameters
base/int

How come in the call to foo(), C++ seems to recognize that it is pointing to a Derived but in the call foo(1.0), C++ does not see void foo(double a) function in the Derived class?

In my mind there are competing ideas, that C++ has polymorphism, which explains the first call, but that overload resolution is done at compile-time, which explains the second call.

newprogrammer
  • 2,514
  • 2
  • 28
  • 46

6 Answers6

3

This is classical example for Function Hiding.
A function in dervied class overriddes the Base class function if and only if:

  1. virtual keyword is present atleast on the Base class function.
  2. The function in Derived class has exact same signature as the Base class function.

The second rule has an exception where Covariant return types are allowed.

Given the above two rules:

The no parameter foo() function in derived class overiddes the Base class foo() and hence dynamic dispatch works for it as you expected.

The version of foo(double) with one parameter does not override the Base class foo(int) function it merely Hides it. Since there is no overidding there is no dynamic dispatch, the compiler merely calls the foo(int) function it finds in the scope of the Base class.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
2

C++ does not see void foo(double a) function in the Derived class?

C++ does see the function, but it's not associated with Base::foo's virtualness due to function signature difference:

virtual void Base::foo(int);  // 'Base' signature
void Derived::foo(double);    // 'Derived' signature

So here there are 2 important facts for Derived::foo(double):

  1. doesn't relate (override) to Base::foo(int)
  2. not a virtual method (even making it virtual doesn't help)

1st point is more important, because when you call

// 'ptr' refers 'Base' method signature; so 'double' implicitly converts to 'int'
ptr->foo(1.0);

Base pointer is used. In the vtable list it has only one entry of Base::foo(int). And thus it's called.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • I'm not really familiar with vtable, so I'm wondering in general: When you create a pointer to an object, is the vtable associated with the pointer or with the actual object? – newprogrammer Feb 03 '12 at 06:24
  • 2
    @newprogrammer, vtables are implementation specific detail and you need not worry about them; the important thing is to study upon the **observable** behavior; i.e. when `Base::foo(int)` should be called and when not. If you are interested in `vtables` you can see [this question](http://stackoverflow.com/questions/99297/at-as-deep-of-a-level-as-possible-how-are-virtual-functions-implemented). – iammilind Feb 03 '12 at 06:29
2

ptr is of type Base*

The only function in Base taking 1.0 as a parameter is virtual void foo(int a).

Now, remember, for a function to be virtually overriden, it needs to match the signature perfectly (minus variance but it doesn't apply in your case). You are not overriding foo(int) but actually creating a new foo(double).

Coincoin
  • 27,880
  • 7
  • 55
  • 76
  • *...but actually creating a new `foo(double)`* and in the process **hiding** the base class *`foo(int)`*. – Alok Save Feb 03 '12 at 06:19
1

C++ cannot see the void foo(double a) in the Derived class because it is not overriding a virtual function with the signature void foo(double a) in the Base class(where you are trying to call it from).

There is a void foo(int a) in the Base class, but it is an entirely different function according to the rules of C++.


On the other hand, the void foo() in the Derived class is overriding the virtual function void foo() in the Base class, as they both have the same signature.

1
class Base {
    public:
    virtual void foo() {cout << "base/no parameters" << endl;}
    virtual void foo(int a) {cout << "base/int" << endl;}
        };

class Derived : public Base {
    public:
    void foo() {cout << "derived/no parameters" << endl;}
    void foo(int a) {cout << "derived/int" << endl;}
     //  then your derived class function   will call 
};

int main() {
    Base* ptr = new Derived;
    ptr->foo();
    ptr->foo(1.0);

}
Santosh
  • 45
  • 4
0

static vs dynamic overload resolution !!! What does it mean here?

Overloading is always statically bound and the functions are to be defined within a class( not one function is in base class and other function is in derive class).

So foo(double a) and foo(int a)are not overloaded. At the same these are not overridden as the signature is different. That's why no virtual mechanism is taking place for statement ptr->foo(1.0);

user966379
  • 2,823
  • 3
  • 24
  • 30