tags:

views:

131

answers:

4

I had a frustrating problem recently that boiled down to a very simple coding mistake. Consider the following code:

#include <iostream>

class Base
{
public:
    void func() { std::cout << "BASE" << std::endl; }
};

class Derived : public Base
{
public:
    virtual void func() { std::cout << "DERIVED" << std::endl; }
};

int main(int argc, char* argv[])
{
    Base* obj = new Derived;
    obj->func();
    delete obj;

    return 0;
}

The output is

BASE

Obviously (for this case), I meant to put the virtual keyword on Base::func so that Derived::func would be called in main. I realize this is (probably) allowed by the c++ standard, and possibly with good reason, but it seems to me that 99% of the time this would be a coding mistake. However, when I compiled using g++ and all the -Wblah options I could think of, no warnings were generated.

Is there a way to generate a warning when both a base and derived class have member functions of the same name where the derived class's function is virtual and the base class's function is not?

+5  A: 

In Visual C++ you can use the override extension. Like this:

virtual void func() override { std::cout << "DERIVED" << std::endl; }

This will give an error if the function doesn't actually override a base class method. I use this for ALL virtual functions. Typically I define a macro like this:

#ifdef _MSC_VER
#define OVERRIDE override
#else
#define OVERRIDE
#endif

So I can use it like this:

virtual void func() OVERRIDE { std::cout << "DERIVED" << std::endl; }

I've looked for something like this in g++ but couldn't find a similar concept.

The only thing I dislike about it in Visual C++ is that you can't have the compiler require it (or at least warn) on all overridden functions.

Aaron
I use this as well. It's also handy when someone changes the signature of a function (adding a parameter, etc.) but fails to update the base or derived counterpart(s). Normally the virtual-ness would silently stop working, but this trick makes the compiler generate an error.
Tim Sylvester
Great! I didn't know about this extension. I'll probably use this for my own projects since I use Visual Studio, but for this particular project I'll have to stick to g++ :(
Jonesinator
+1  A: 

The problem with the it's-always-a-warning approach is that virtual also signifies an intention by the person who made the original class. By marking it as virtual, the developer is letting you know that derived classes should override the virtual method, not merely that they can (which is possible without the virtual keyword).

The override keyword in other languages (like C#) is meant to address this problem: override says "I understand that my derived class should override this method, and here's my implementation". If you are mistaken in your assumption (e.g. the method was not intended to be overridden), the compiler will catch the error.

John Feminella
"not merely that they can (which is possible without the virtual keyword)" - how do you override a method that isn't declared as `virtual` in your base class? Note that shadowing is not the same as overriding!
Pavel Minaev
You're right, it's shadowing and not overriding. But from the perspective of the implementer of the derived class, the result is the same. That's why you want a distinction between virtual and override, which is the point I was making.
John Feminella
"By marking it as virtual, the developer is letting you know that derived classes should override the virtual method" ?? I beg your pardon, but I think a `pure` word is missing there. If I write a virtual method, I provide a suitable behavior for most of the specializations.
Matthieu M.
+3  A: 

I don't know of any g++ flag to produce a warning on this (not to say there isn't one), but I'd say this is a pretty rare error. Most people write the base class first, as an interface using pure virtual functions. If you had said:

void func() = 0;

then you would get a syntax error.

anon
+1  A: 

man gcc

-Woverloaded-virtual (C++ and Objective-C++ only) 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();

   will fail to compile.
_ex_