views:

1802

answers:

10

I have a base class with an optional virtual function

class Base {
    virtual void OnlyImplementThisSometimes(int x) {}
};

When I compile this I get a warning about the unused param x. Is there some other way I should have implemented the virtual function? I have re-written it like this:

class Base {
    virtual void OnlyImplementThisSometimes(int x) 
    {
        x = 0;
    }
};

I also have the problem that if I'm not careful, the subclass I make can implement the wrong function and then I don't notice because of overloading: e.g.

class Derived : public Base {
    void OnlyImplementThisSometimes(int x, int y) { // some code }
};

Derived d;
Base *b = dynamic_cast<Base *>(&d);
b->OnlyImplementThisSometimes(x); // calls the method in the base class

The base class method was called because I implemented the derived function with an "int y" param but there is no warning about this. Are these just common pitfalls in C++ or have I misunderstood virtual functions?

+6  A: 

Why define it in the base class? If the base class isn't going to use the method, then just define it as a virtual method in your derived class.

Or the default implementation could throw an exception

Chris Thompson
+4  A: 

If you provide a default implementation of a virtual function, it should be a correct implementation for all derived classes that don't override that function. If you can't provide a correct implementation, then my advice would be to make a pure virtual function and leave it up to the derived class to provide an implementation. Derived classes that do not allow the method to be called can throw an exception to ensure that it is not used by mistake.

tvanfosson
And if you can think of an implementation which is *normally* correct, but not quite always, then you can provide an implementation of a pure virtual function, and in the normal case the derived class just calls it.
Steve Jessop
+16  A: 

Ignoring the design issues you can get around the compiler warning about an unused variable by omitting the variable name, for example:

virtual void OnlyImplementThisSometimes(int ) { }

Mistakenly implementing the wrong method signature when trying to override the virtual function is just something you need to be careful about in C++. Languages like C# get around this with the 'override' keyword.

nrl
The other way to do this (same effect) is to comment out the variable name inline, eg: int /*x*/. If the variable name is descriptive (which it should be), this will assist readers.
Nick
+2  A: 

This is somewhat common in my code. For example, I have classes that are designed for single-threaded operation and multi-threaded. There are a lot of common routines and data. I put all of that in the base class (which has a couple of pure virtual as well).

I implement two empty virtual functions in the base class: Init() and Cleanup(). The single threaded derived class does not impliment them, but the mulit-threaded one does.

I have a factory function create the approprite derived class then return a pointer. The client code only knows about the base class type and it calls Init() and Cleanup(). Both scenarios do the right thing.

Of course, there may be other good suggestions on how to do this, but this idiom works well for a lot of my code.

Foredecker
I believe, overriding a pure virtual function in the derived class and making it just do nothing results in clearer and easier to use code than doing this in the base class and not overriding in the derived class. It's less likely to misuse, because the user of the class has to think about it.
mxp
+2  A: 

In addition to simply omitting the variable name, in many compilers you can tell the compiler, that you are aware that it is unused and SHUTUP by doing this

int func(int x)
{
   (void) x;
}
EvilTeach
Strictly speaking, that doesn't tell the compiler that it's unused and SHUTUP. It uses it.
Steve Jessop
+2  A: 

It's not a bad practice and it's a common idiom for specifying parts of a class that are optional to implement.

Currently I'm using it for a user input system, because it would be tedious for a user of that class to implement every single method even it he most likely won't use it anyway.

class mouse_listener{
public:
 virtual ~mouse_listener() {}

 virtual void button_down(mouse_button a_Button) {}
 virtual void button_up(mouse_button a_Button) {}
 virtual void scroll_wheel(mouse_scroll a_Scroll) {}
 virtual void mouse_move_abs(math::point a_Position) {}
 virtual void mouse_move_rel(math::point a_Position) {}
};
Jasper Bekkers
+2  A: 

Btw, if you know your base class, there's never any need to do dynamic up-casts, i.e. from derived to base.

Base *b = &d;

Will do just as well, dynamic_cast<> should instead be used when you down-cast, i.e. from base to derived:

if((Derived *d = dynamic_cast<Derived *>(b)) != 0)
{
  // use d
}

(And of course in the case of down-cast, static_cast<> will usually work as well.)

Andreas Magnusson
I can think of at least one case where dynamic up casts are needed: if you derive from a template parameter and you need to call specific functions based on the base type. In my case it was something like this: if(fixture *f = dynamic_cast<fixture*>(this)){f->set_up();}
Jasper Bekkers
Because of the way the framework is set up, I don't know at that point in time whether the test case derives from fixture or not: the test case itself derives from a template argument.
Jasper Bekkers
+8  A: 

We define a macro _unused as:

#define _unused(x) ((void)x)

Then define the function as:

virtual void OnlyImplementThisSometimes(int x) { _unused( x );}

This not only keeps the compiler from complaining, but makes it obvious to anyone maintaining the code that you haven't forgotten about x -- you are intentionally ignoring it.

Graeme Perrow
A: 

The simplest answer to this is shown below:

class Base {
    virtual void OnlyImplementThisSometimes(int x) { x;}
};

A simple reference to the variable which does absolutely nothing will remove all warnings (from VC++ at highest level anyway).

Tim Ring
First, this still warns in GCC with -Wall ("statement has no effect"). Second, it's not the simplest answer - omitting the parameter name is.
Steve Jessop
A: 

Try this:

class Base {
    virtual void OnlyImplementThisSometimes(int x) = 0;
};

It's been a while since I've done stuff like that but I believe that is how you declare a virtual function.

Also as others have said, variable names are optional in function declarations like this.