Re: Pure virtual functions and multiple inheritance
On 2009-01-30, Kevin Smith <no@spam.com> wrote:
Can I provide the implementation of a pure virtual function by inheriting
from another class? eg.:
class A{
public:
virtual void f() = 0;
};
class B{
public:
void f(){};
};
class C: public A, public B{};
My compiler (VC++) tells me that C is an abstract class, even though there
is a public implementation of f() in C. Is this Standard?
["Followup-To:" header set; replies to this article will be configured
to go to comp.lang.c++, unless you manually edit the header.]
It is not standard, and other compilers also won't like this, like GNU
C++ 4.3.2.
The pure virtual simply isn't being overridden by a class that isn't deriving
from B. They are two different functions. Note that if you had this:
class A{
public:
virtual void f() { /* A behavior */ }
};
class B{
public:
virtual void f() { /* B behavior */ }
};
and you combine these into the same derived class C, then you still have two
different functions. One does not override the other. There is an A::f and a
B::f. If you have a B& reference to a C object, then calling f gets you B::f
with the B behavior. If you have an A& reference to the object, then calling f
on that reaches A::f with A behavior. Moreover, if you try to call f on a C
object, it will be ambiguous:
C x;
x.f(); // ambiguous call; did you want A::f or B::f?
But if both functions are virtual, and C does implement a void C::f(), then
that overrides both! Now if you call f through an A& reference, you get C::f,
and same via a B& reference.
So in your case, what you need is this:
class C: public A, public B
{
public:
void f() { B::f(); }
};
Now if objects of type C are used through a B class reference, the call to f
goes to B::f, of course. This is not a virtual call. B::f is not virtual
and cannot be overridden. C::f overrides only A::f. The C::f definition
suppresses the lexical visibility of B::f in the C class scope, but does
not override that function.
But if f is called on a C object through an A reference, it is routed to C::f;
it is only thanks to C::f that the call then reaches B::f.