Re: Partial overwriting of a method in subclasses
walkman wrote:
class A {};
class B : public A {};
// service classes
class C
{
public:
virtual ~C() {};
virtual void func(A& guest) {}
virtual void func(B& guest) {}
};
class D : public C
{
public:
virtual ~D() {};
virtual void visit(A& guest) { func(guest); }
virtual void func(B& guest) {}
};
[...]
Now, this code does not compile in GCC 4.1.2, nor does it compile in
the online Comeau C++ form (http://www.comeaucomputing.com/tryitout/),
where the first complains about a lack of definition of D::func(A&)
and the later about imposibility to cast down A& to B& so that it
could use D::func(B&) in D::visit(...), which is finally the same
problem.
Take a simpler example:
struct base {
virtual void foo( int&);
virtual void foo( double&);
};
struct derived {
virtual void foo( double&);
};
int main() {
derived d;
int i;
d.foo(i);
}
Your problem is that the first thing that is done by the compiler is to look
up 'foo' in the context of a memberfunction of 'd'. It finds one in
class 'derived', so now it tries to resolve overloads. Since the only
overload clearly doesn't fit, it bails. The rules of C++ name lookup simply
dictate that the compiler behave that way. In fact I would expect this
problem when overloading to be a FAQ, shame on you if it is!
1.- am I always forced to overwrite all versions of a method with the
same name, but with different signature?
No.
2.- why cannot compiler figure out itself that in D::visit(A&) the
call to C::func(A&) is the right solution? It seems to me natural as
this is how I always thought this kind of polymorphism works
(obviously wrong!)... Do I really have to explicitly implement it this
way?:
virtual void visit(A& guest) {C::func(guest)} - "C::" seems
superfluous...
You could use 'using C::func;', I believe.
3.- does this something to do with the fact that C++ implements only
single-dispatch, instead of double-dispatch? (yet, when func is not
overwritten in D at all, compiler figure stuff out correctly!)
Right, because it first searches the derived class (i.e. the static type)
and then its baseclasses. There, it finds a suitable overload to choose
from.
4.- how can I solve this problem without overwriting all the versions
of func(...)? In my real application C and D are visitors of an
extensive hierarchy and overloading all the versions of func(...)
would result into a big code bloat and explicit call to C::func() as
described in point 2 seems ugly to me.
Firstly, let's make a small extension to my example which will make it
compile:
base& b = d;
b.foo(i);
This will first choose an overload from the baseclass (b's static type) and
then polymorphically invoke it (it isn't overloaded in the derived class,
but if you gave it a double it would use derived::foo).
This then leads to a simple solution:
struct base {
void foo(int& i) { do_foo(i); }
void foo(double& d) { do_foo(d); }
private:
virtual void do_foo( int&);
virtual void do_foo( double&);
};
struct derived {
private:
virtual void do_foo( double&);
};
Uli
--
Sator Laser GmbH
Gesch?ftsf?hrer: Ronald Boers, Amtsgericht Hamburg HR B62 932
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]