Please consider the following code:
class Abase{};
class A1:public Abase{};
class A2:public A1{};
//etc
class Bbase{
public:
virtual void f(Abase* a);
virtual void f(A1* a);
virtual void f(A2* a);
};
class B1:public Bbase{
public:
void f(A1* a);
};
class B2:public Bbase{
public:
void f(A2* a);
};
int main(){
A1* a1=new A1();
A2* a2=new A2();
Bbase* b1=new B1();
Bbase* b2=new B2();
b1->f(a1); // calls B1::f(A1*), ok
b2->f(a2); // calls B2::f(A2*), ok
b2->f(a1); // calls Bbase::f(A1*), ok
b1->f(a2); // calls Bbase::f(A2*), no- want B1::f(A1*)!
}
I'm interested to know why C++ chooses to resolve the function call on the last line by upcasting the this
pointer of the object to the base class, rather than upcasting the argument of f()
? Is there any way that I can get the behaviour I want?
The choice of which version of f
to call is made by looking at the compile-time type of the parameter. The run-time type isn't considered for this name resolution. Since b1
is of type Bbase*
, all of Bbase
's members are considered; the one that takes an A2*
is the best match, so that's the one that gets called.
"...chooses to resolve the function call on the last line by upcasting the this pointer of the object to the base class...". What are you talking about? In all of your calls, the object pointer type is Bbase *
and the functions the calls resolve to belong to either Bbase
or its descendants. The compiler never does any upcasting in order to resolve your calls. In fact, the first two calls require downcasting in order to call the proper overrider, since the overrider belongs to the class located further down in the hierarchy. As for the last two calls - they are dispatched into the Bbase
class through a pointer of Bbase *
type. The types match exactly, no casting of any kind takes place.
As for the overload resolution... Overload resolution is a compile time process, which is based on the static types of the arguments and the ranks of possible conversions. You supplied an argument of A2 *
type. The f(A2 *)
candidate matched your argument precisely. The f(A1 *)
candidate requires a extra conversion from A2 *
to A1 *
. The candidate that matches exactly is considered a better one, so it wins the overload resolution. Simple.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With