c++ overloaded virtual function warning by clang? - c++

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.

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);
};

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

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

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;
}

Related

Woverloaded-virtual warning on usual method

I'm confused why the following code produces Woverloaded-virtual warning.
class TestVirtual
{
public:
TestVirtual();
virtual void TestMethod(int i);
};
class DerivedTestVirtual : public TestVirtual
{
public:
void TestMethod();
};
Derived class has usual method TestMethod with no parameters - signature differs from similar virtual method of base class. Then why compiler cannot resolve this situation?
The reason for the warning is that the no parameter version is hiding the int version from the base class.
DerivedTestVirtual tdv;
tdv.TestMethod(0); // This line will cause an error.
You can circumvent that by declaring you use all of the original overloads from the base, like so:
class DerivedTestVirtual : public TestVirtual
{
public:
using TestVirtual::TestMethod;
void TestMethod();
};
The warning is there to bring the issue to your attention. And it's also useful since such a mistake can happen when you try to override it, but accidentally end up overloading. Though nowadays you'd use the override specifier to catch that instead.

Virtual functions and default parameters

Lets say I have a class A, B and C
class A{
public:
virtual void f4(){
cerr<<"A::f4()"<<endl;
}
};
class B: public A{
public:
virtual void f4(int n){
cerr<<"B::f4("<<n<<")"<<endl;
}
};
class C: public B{
public:
virtual void f4(int n = 1){
cerr<<"C::f4("<<n<<")"<<endl;
}
};
If I have:
C c;
A& rac = c;
rac.f4();
I was expecting c's version of f4 to be called but that's not what happens. Can someone explain?
Compiling with clang -Wall the following warnings occur:
main.cpp:14:22: warning: 'B::f4' hides overloaded virtual function [-Woverloaded-virtual]
virtual void f4(int n){
^
main.cpp:6:22: note: hidden overloaded virtual function 'A::f4' declared here: different number of parameters (0 vs 1)
virtual void f4(){
^
These warnings explain what's going on. A virtual function is only overridden by another function with the same signature.
B::f4(int) does not override A::f4() because they have different parameter lists. Instead, it is a different virtual function.
So rac.f4() just calls A::f4() which is not overridden.
Since C++11 you can help to detect this problem:
virtual void f4(int n) override {
// ^^^^^^^^
Then the compiler will give an error if this function does not actually override something from the base.
Because the signatures of f4 don't match between A and B/C classes.
This is A's function signature for f4:
void A::f4() // no parameters
B and C use this function signature
void B::f4(int n)
If you are doing to override a method, it needs to have the same return type and identical parameter list. Otherwise, even if the method in the derived class has the same name as the parent class, C++ will don't consider that an override.
FWIW, C::f4 does override B::f4. The default parameter you introduce on class C doesn't influence the virtual methods override behavior. And this is the exact reason why, on my team, we disallow overloading methods with different signatures and banning default parameters. Because it leads to bugs like this.
Here's C's v-table (the methods available on it):
void C::f4(); // no parameters, overrides A::f4()
void C::f4(int n); // overrides B::f4()

Disabling visual C++ virtual function override warning for certain methods

I would like to enable C4263 (Visual C++) warning on our code base, however, the warning gives out some false positives. We would like to disable the warning such that only the false positives disappear. I tried to simplify the issue with some generic code:
class B {
public:
virtual void funcA();
virtual void funcB();
};
class D : public B
{
virtual void funcA(int);
virtual void funcB(int);
};
With this code we I get following warnings:
void D::funcA(int)' : member function does not override any base class virtual member function
void D::funcB(int)' : member function does not override any base class virtual member function
What I am trying to achieve is to disable the warning for funcA (or funcB) and let the rest of the class be affected by it.
I tried putting
#pragma warning(push)
#pragma warning(disable:4263)
.
.
.
#pragma warning(pop)
around funcA but that does not solve the problem. If the pragmas wrap the whole class that both of the warnings disappear.
Any ideas?
This is a strange error given the documentation for it:
https://msdn.microsoft.com/en-us/library/ay4h0tc9.aspx?f=255&MSPPError=-2147217396
'function' : member function does not override any base class virtual
member function
A class function definition has the same name as a virtual function in
a base class but not the same number or type of arguments. This
effectively hides the virtual function in the base class.
The last sentence is the interesting one, and it suggested to me that if you unhide the base class functions, the warning will no longer appear.
And indeed this is the case. The following code does not output C4263:
class B {
public:
virtual void funcA();
virtual void funcB();
};
class D : public B
{
using B::funcA;
using B::funcB;
virtual void funcA(int);
virtual void funcB(int);
};
The warning seems a little strange. If you're dispatching from the base class pointer, it doesn't matter what functions the derived class hides, as they won't be hidden when using a base class pointer. But herein lies the answer!
What's actually happening here is the compiler is guessing your intentions. Because you are introducing a new signature, it means you will be using either polymorphic or non-polymorphic dispatch using a derived pointer (not a base pointer). If you were not doing this, it would be impossible to call your overload. The compiler figures that if you are doing this, you will be hiding the un-overridden functions. And that's what the warning is about.
In an example:
struct Base
{
virtual void DoThing(int)
{
std::cout << "INT " << std::endl;
}
};
struct Derived: public Base
{
virtual void DoThing(char) // Add a function to handle chars
{
std::cout << "CHAR " << std::endl;
}
};
int main()
{
Derived *derived = new Derived;
Base *base = derived;
base->DoThing(1);
derived->DoThing(1);
derived->DoThing('a');
}
This outputs:
INT CHAR CHAR
The intention may have been to add an overload to handle a different case, but instead it's hiding all the existing overloads. The warning is correct given the rules of the language. The warning isn't exact, it's trivial to determine cases where it doesn't get invoked but it should. It in-fact does the opposite of false-warnings :)
To defeat this warning, the using declaration should be used.

Eclipse reports bug on valid cpp inheritance

Eclipse is reporting a bug on "new Listener()", though this compiles and executes with g++. Note the classes have more data than listed here as this is trimmed down, so removing the seemingly empty classes is not an option. Is there something that I can add/change to make both Eclipse and g++ happy. I will not be able to change the Base* classes though.
class BaseIntf {
public:
virtual ~BaseIntf() {}
virtual void foo() = 0;
};
class BaseImpl: public virtual BaseIntf {
public:
virtual void foo() {}
};
class ListenerBaseInft: public virtual BaseIntf {
};
class Listener: public ListenerBaseInft, public BaseImpl {
};
int main(int argc, char *argv[]) {
// Eclipse:
// The type 'Listener' must implement the inherited pure virtual method 'BaseIntf::foo'
Listener* listener = new Listener();
listener->foo();
return 0;
}
C++ has a feature called dominance. Normally, when a class (say A) is derived from two classes (say A1 and A2), each implementing the same virtual function (say void f()), the derived class needs to implement that function as well. A pure virtual function counts as an implementation too.
However, there is an exception: when A1 is itself derived from A2, then A1s implementation of f() is said to dominate that of A2, and the latter is excluded from consideration. Thus, A does not have to reimplement f().
Your compiler probably fails to take that exception into account. It's a compiler bug.
To work around it, define foo in Listener:
void foo() { BaseImpl::foo(); }
which is ugly, but so is the compiler bug.

is this a compilation bug of Visual 2010?

class Base {
public:
virtual void myFunc(double a, double b) { };
virtual void myFunc(double a) { };
};
class Derived : public Base {
public:
virtual void myFunc(double a) { return this->myFunc(a, 0.0); };
}; // ^^^^^^^^^^^^^^^^^^^^
The previous code won't compile : error C2660: 'Derived::myFunc' : function does not take 2 arguments
Apparently the compiler cannot see that I'm trying to call the function defined in Base class, or any function that overrides it. On the other hand, the following code compiles ok:
class Base {
public:
virtual void myFunc2(double a, double b) { };
virtual void myFunc(double a) { };
};
class Derived : public Base {
public:
virtual void myFunc(double a) { return this->myFunc2(a, 0.0); };
};
I think what i'm trying to do in the first example is legal C++, so is this a bug in the VS2010 compiler? I have the same results with VS2008
thanks
edit : a workaround I found is to use
virtual void myFunc(double a) { return ((Base*)this)->myFunc(a, 0.0); };
but I'm not 100% sure it has the exact same effect, can anyone confirm?
This behavior is by design.
Functions in a derived class hide other overloads in the base class.
This is not a bug.
You have a choice in C++ whether the inherited overloads should be hidden (which is the safer, default behavior) or available:
class Derived : public Base {
public:
virtual void myFunc(double a) { return this->myFunc(a, 0.0); };
using Base::myFunc;
};
Alternatively, you can use the Base::myFunc syntax at the point of the function call.
There is an explanation of the default behavior of interaction between namespaces and overloading in D&E, section 17.4.5.3 and 17.5. Suppose that Base is a library class whereas Derived is your application code. The next version of the library will certainly have new overloads for many functions, possibly even myFunc, and you certainly do not want your well tested program to silent rebind its myFunc calls to other overloads and call something else.