89

clang emits a warning when compiling the following code:

struct Base
{
    virtual void * get(char* e);
//    virtual void * get(char* e, int index);
};

struct Derived: public Base {
    virtual void * get(char* e, int index);
};

The warning is:

warning: 'Derived::get' hides overloaded virtual function [-Woverloaded-virtual]

(the said warning needs to be enabled of course).

I don't understand why. Note that uncommenting the same declaration in Base shuts the warning up. My understanding is that since the two get() functions have different signatures, there can be no hiding.

Is clang right? Why?

Note this is on MacOS X, running a recent version of Xcode.

clang --version
Apple LLVM version 5.0 (clang-500.1.74) (based on LLVM 3.3svn)

Update: same behavior with Xcode 4.6.3.

Jean-Denis Muys
  • 6,772
  • 7
  • 45
  • 71

4 Answers4

136

This warning is there to prevent accidental hiding of overloads when overriding is intended. Consider a slightly different example:

struct chart; // let's pretend this exists
struct Base
{
    virtual void* get(char* e);
};

struct Derived: public Base {
    virtual void* get(chart* e); // typo, we wanted to override the same function
};

As it is a warning, it doesn't necessarily mean it is a mistake, but it might indicate one. Usually such warnings have a means of shutting them off by being more explicit and letting the compiler know you did intend what you wrote. I believe in this case you can do the following:

struct Derived: public Base {
    using Base::get; // tell the compiler we want both the get from Base and ours
    virtual void * get(char* e, int index);
};
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • 13
    It could be pointed out that, this solution to "locally turn off the warning" is also changing the code's semantic : you can now invoke the `get` function member with a single argument on an object of static type `Derived`. Without the using declaration, the same thing would lead to a compilation error. – Ad N Nov 22 '13 at 13:43
35

Another way of disabling the warning keeping the struct public interface intact would be:

struct Derived: public Base
{
    virtual void * get(char* e, int index);
private:
    using Base::get;
};

This disallows a consumer of Derived to call Derived::get(char* e) while silencing the warning:

Derived der;
der.get("", 0); //Allowed
der.get("");    //Compilation error
Pedro
  • 451
  • 4
  • 5
  • 3
    This is definitely a safe way to remove this warning when you planned to replace the base's class `get` method! – jpo38 Feb 08 '19 at 07:30
  • Beware, however, of cases where this would cause an ambiguous call. So this solution isn't 100% save either. – sigy Aug 25 '20 at 15:15
27

R. Martinho Fernandes solution's is perfectly valid if you actually want to bring the get() method taking a single char* argument into Derived scope.

Actually, in the snippet you provided, there is no need for virtual methods (since Base and Derived do not share any method with the same signature).

Assuming there is actually a need for polymorphism, the hiding behavior could nonetheless be what is intended. In this case, it is possible to locally disable Clang's warning, with the following pragma :

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
    // Member declaration raising the warning.
#pragma clang diagnostic pop
Ad N
  • 7,930
  • 6
  • 36
  • 80
  • 1
    This answer was doubly amazing. At first it was the exact answer for what I was looking for, that I "wanted my method out there". As I was writing a comment in my code for the reason of the pragma & how clang was stupid, my eyes caught that I wrote override, but the warning was overload. Then I clicked & realized I forgot `const` on the inherited method, and clang was right all along. When in doubt, trust the compiler. When you doubt the compiler, trust the compiler. :) +1 for both giving me both what I sought and needed! – nevelis Jul 31 '16 at 08:03
20

Warning means, that there will be no void * get(char* e) function in the scope of Derived class, cause it hidden by another method with same name. Compiler won't search for function in base classes if derived class has at least one method with specified name, even if it has another arguments.

This sample code won't compile:

class A
{
public:
    virtual void Foo() {}
};

class B : public A
{
public:
    virtual void Foo(int a) {}
};


int main()
{
    B b;
    b.Foo();
    return 0;
}
Paul Du Bois
  • 2,097
  • 1
  • 20
  • 31
WormholeWizard
  • 366
  • 1
  • 3
  • 2
    That's a good point: hiding is *actually* *actively* happening, even though the different signatures should be enough to prevent it. – Jean-Denis Muys Aug 30 '13 at 12:39
  • My definition of hiding is having the same signature but not to override... which is not the case here. – NGauthier Mar 11 '15 at 19:22
  • The solution to avoid hiding, from __C++ in a Nutshell__: "Insert a using declaration in the derived class if you want the compiler to consider the base class functions as candidates", as shown in other answers. – qris Dec 06 '16 at 21:08
  • If it would also include a solution (using...) this should be the accepted answer, as it is the only one that correctly explains what happens and why this is a valid warning – MikeMB Jun 01 '17 at 05:04
  • 2
    This is the clearest answer I think. However worth noting that you can actually still call `b.Foo();`. You just need to write `b.A::Foo();`. – Timmmm May 14 '19 at 15:30