Can anyone tell me how does return type covariance work in the following code?
class X
{
public:
int x;
};
class Y: public OtherClass, public X
{
};
static Y inst;
class A {
public:
virtual X* out() = 0;
};
class B : public A
{
public:
virtual Y* out()
{
return &inst;
}
};
void main()
{
B b;
A* a = &b;
//x and y have different addresses. how and when is this conversion done??
Y* y = b.out();
X* x = a->out();
}
EDIT: I'm sorry I must not have been clear enough. x and y point to different addresses just like I expect since there's multiple inheritance involved so X and Y objects are not on the same address. My question is when is this cast being done? the out() function couldn't have done this because it always returns a pointer to Y from its point of view. The caller of out() couldn't have done this because it sees X* whose concrete type might be X or Y. When is the cast done then?
By "how does it work", I presume you're asking about what the generated code looks like. (In a typical implementation, of course. We all know that the generated code can vary somewhat between implementations.) I'm aware of two possible implementations:
The compiler always generates code to return a pointer to the base
class; i.e. in B::out
, the compiler will convert the Y*
to an X*
before returning it. At the call site, if the call was through an
lvalue with static type B
, the compiler will generate code to
reconvert the returned value to Y*
.
Alternatively (and I think this is more frequent, but I'm far from
sure), the compiler generates thunks, so when you call a->out
, the
virtual function which gets called is not directly B::out
, but a small
wrapper which converts the Y*
returned from B::out
to an X*
.
Both g++ and VC++ seem to use thunks (from a very quick glance).