c++ overloaded virtual function warning by clang?
Asked Answered
E

4

91

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.

Elishaelision answered 29/8, 2013 at 15:32 Comment(0)
F
139

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);
};
Ferryman answered 29/8, 2013 at 15:38 Comment(1)
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.Puttee
N
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
Nidifugous answered 12/5, 2015 at 13:45 Comment(2)
This is definitely a safe way to remove this warning when you planned to replace the base's class get method!Swage
Beware, however, of cases where this would cause an ambiguous call. So this solution isn't 100% save either.Hayott
P
28

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
Puttee answered 22/11, 2013 at 13:57 Comment(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!Downbow
C
21

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;
}
Cyd answered 29/8, 2013 at 15:47 Comment(5)
That's a good point: hiding is actually actively happening, even though the different signatures should be enough to prevent it.Elishaelision
My definition of hiding is having the same signature but not to override... which is not the case here.Expansionism
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.Composure
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 warningViola
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();.Cornelie

© 2022 - 2024 — McMap. All rights reserved.