I am trying to understand the following bit of code:
#include<iostream> using namespace std; class Base { public: virtual void f(float) { cout << "Base::f(float)\n"; } }; class Derived : public Base { public: virtual void f(int) { cout << "Derived::f(int)\n"; } }; int main() { Derived *d = new Derived(); Base *b = d; d->f(3.14F); b->f(3.14F); }
Will print
Derived::f(int) Base::f(float)
And I donβt know exactly why.
The first call to d-> f (3.14F) calls the function f in Derived. Why am I not 100% sure. I looked at this (http://en.cppreference.com/w/cpp/language/implicit_cast) which says:
The value of a floating point class can be converted to a prvalue of any integer type. The fractional part is truncated, i.e. The fractional part is discarded. If the value cannot fit into the destination type, the behavior is undefined
Which tells me that you cannot do this, since the float does not fit into the int. Why is this implicit conversion allowed?
Secondly, even if I just accept the above as OK, the second call to b-> f (3.14F) does not make sense. b-> f (3.14F) calls the virtual function f, so it is dynamically resolved to call f () associated with the dynamic type of the object pointed to by b, which is a derived object. Since we are allowed to convert 3.14F to int, because the first call to the function indicates that it is legal, this (in my opinion) should again call the Derived :: f (int) function. However, it calls a function in the base class. So why is that?
edit: this is how I understood it and explained it to myself.
b is a pointer to a base object, so we can only use b to access the elements of the base object, even if b really points to some Derived object (this is standard OO / inheritance material).
The only exception to this rule is when a Base member function is declared virtual. In this case, the Derived object can override this function by providing a different implementation using the same signature . If this happens, then this derived implementation will be called at run time, even if we access the member function through a pointer to the underlying object.
Now, in the code snippet above, we have no redefinition, because the signatures of B :: f and D :: f are different (one is float, the other is int). Therefore, when we call b-> f (3.14F), the only function that is considered is the original B :: f, which is what is called.