shuhalo
shuhalo

Reputation: 6452

What's the deal with overloading virtual functions in C++?

The GCC manual contains the following explanation of the warning option -Woverloaded-virtual:

Warn when a function declaration hides virtual functions from a base class. For example, in:

struct A {
    virtual void f();
};

struct B: public A {
    void f(int);
};

The A class version of f is hidden in B, and code like:

B* b;
b->f();

Fails to compile.

What is the problem with this code? If it fails to compile, why is it a warning and not an error message? What is the canonical way to fix this and why?

Upvotes: 0

Views: 129

Answers (1)

cdhowie
cdhowie

Reputation: 169038

Introducing a name that is inherited from an ancestor type causes that name to be hidden in the derived type. This is why b->f(); does not compile.

The warning comes from the declaration of B::f. The compiler is telling you that this new declaration does not overload or override the function inherited from A. It hides it within B's scope. Sometimes you might want this, and there is nothing technically wrong with it, which is why it is not an error. However, because A::f is hidden in B, you can't invoke it (statically) on a B value/reference.

Note that this has nothing to do with the inherited member function being virtual (though you would not receive the warning about the declaration of B::f if A::f were not virtual, nevertheless both will fail to compile b->f() for the same reason). Perhaps more interesting, note that a type deriving B can override A::f even though it is not visible in B.

To have both (an overloaded f() in B) you can explicitly bring the name f from A into B:

struct B: public A {
    using A::f;
    void f(int);
};

Now both f() overloads are visible within B. Note that void f() is still virtual, but void f(int) was not declared virtual and so it isn't.

Another (ugly) workaround is to upcast the B pointer/reference to an A pointer/reference:

B *b = new B;
static_cast<A*>(b)->f();

Or, with a value instead of a pointer:

B b;
static_cast<A&>(b).f();

This uses the virtual function through the A type, where it is not hidden.

Upvotes: 2

Related Questions