Re: Covariant virtual function result types
Am 24.11.2011 01:40, schrieb Lorenzo Caminiti:
When invoking a covariant virtual function, the derived function body
is executed but the result type of the base function is returned. Is
there any way to get C++ to return the result type of the derived
function instead?
Generally, there are static types and dynamic types. The static type is
what the compiler verifies and where it issues errors on mismatches. The
dynamic type is used at runtime, when using RTTI or doing virtual
function calls.
The type of something returned by a function is static, meaning that it
can't change at runtime. The dynamic type can change, if you have a
pointer to "Base", the dynamic type may well be "Derived".
struct rx {};
struct ry : rx {};
struct x {
virtual rx* f() {
std::cout<< "rx* f()"<< std::endl;
return&rx_;
}
rx rx_;
};
struct y : x {
ry* f() {
std::cout<< "ry* f()"<< std::endl;
return&ry_;
}
ry ry_;
};
Virtual function returning a pointer, derived class returning a pointer
to another derived type, i.e. covariant return type. Nothing special here.
int main ( ) {
y yy;
y* yp =&yy;
x* xp =&yy;
ry* ryp = yp->f(); // calls y::f
rx* rxp = xp->f(); // calls y::f but returns rx* instead of ry*
The static type of "xp->f()" is "rx*", this can't change at runtime.
// ry* nope = xp->f();
// error: calls y::f but returns rx* instead of ry*
Okay, there are a few ways out:
1. You know that "xp" points to an "y", so you also know that the
returned "rx*" is actually an "ry*". What you can do is to simply use a
"static_cast<ry*>()" to convert the result. Of course, if you make a
mistake and "xp" does not point to an "y", you are invoking undefined
behaviour. If "rx" was polymorphic, i.e. at least one virtual function,
you could use a dynamic_cast.
2. Since you know that "xp" points to an "y", just convert that to an
"y*" using "static_cast<y*>(xp)". If you use that to invoke a function
"f()", it will statically find "y::f" which has the expected return
type. Note that here you can also use a "dynamic_cast" in order to
verify the type.
3. You could replace the type "rx" in the baseclass' with "ry".
4. Using templates, you could then avoid writing similar code for "x"
and "y", instead just pass them in as template parameters.
5. You could create a visitor (look up "Visitor Pattern") that does the
right thing for different types. This would just allow you to cleanly
call the according different code and is an alternative to using dynamic
casts in order to find the correct type.
In most cases, the question you will have to answer is whether you know
the type or not. If you know it, a static cast with possible a comment
explaining it should do the job. If you don't know the type, you must be
able to gracefully handle both "x" and "y", and for that some kind of
dynamic dispatch is needed, either via virtual functions or dynamic cast.
Good luck!
Uli
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]