Click here to Skip to main content
Click here to Skip to main content

How to make sure that you override an existing function

, 17 Nov 2003
Rate this:
Please Sign up or sign in to vote.
An article on how you can make sure that you override an existing function in a base class, so that if the base class function is changed without your knowledge, you get an error.

Introduction

Experienced C++ programmers often have the habit of expecting that when something compiles, it is typesafe and it is therefore correct. Even though it may not always be true, this habit grows because it is very often true. A couple of days ago I ran into one of those situations where a compiling program, which I expected to work (because it compiled and it passed my testing) didn't do what I would have expected in a particular situation. I debugged it to find out what the problem was. It turned out that I had added a parameter to a member function of a certain class, but that I had forgotten to add that same parameter to a member function in a derived class that was supposed to be overriding the member function of the base class. Normally I would have noticed this, because the member function in the derived class actually called the member function of the base class that it was supposed to override. However, I didn't notice it this time because I had added a default value to the new parameter. This way, all code that used the member function would still work, I thought. But exactly this expectation caused the override in the derived class to silently cease being an override, which was very annoying indeed!

I'll give you an example of the situation I ran into. Say you've got the following code:

class A
{
public:  
    virtual void foo()   
    {     
        std::cout << "A::foo" << endl;   
    }
};

class B : public A
{
public:  
    virtual void foo()   
    {    std::cout << "B::foo" << endl;  
    }
};

int main()
{  
    A* a = new B;  a->foo(); // prints "B::foo".
}

You get into a situation where foo needs an extra parameter, and you change it like this:

class A
{
public:  
    virtual void foo(int n = 3)  
    {    
        std::cout << "A::foo(" << n << ")" << endl;  
    }
};
class B : public A
{
public:  
    virtual void foo()  
    {    std::cout << "B::foo" << endl;  
    }
};

int main()
{  
    A* a = new B;  a->foo(); // prints "B::foo".
}

Because you're smart, you've added a default value to the new parameter, so that all the code using A wouldn't have to be changed. Surprisingly, the program now prints "A::foo(3)" instead of "B::foo" as it did before. How could this happen? Well, obviously you forgot to change B as well, and unfortunately the compiler didn't give you a warning about this. And how could it? It doesn't know that B's foo is supposed to override A's foo!

After thinking about what happened for a while, I decided to do something about it. I wrote a macro that I could use in derived classes, which would make absolutely sure that overriding member functions were actually overriding a base class member with the exact same signature. I'm making it available for the community so that they don't have to fall into the same trap that I fell into.

Using the code

Using this macro is pretty easy. Let's say you have a class A, and a class B derived from it. Say class A has a member function A::foo that you want to override in class B. Normally, you would write:

class B
{  
    // ...  void foo(int,double);  
    // ...
};

However, when you want to do override checking, you write:

#include "override.h"
// ...
class B
{  
    // ...  
    OVERRIDE(A,void,foo,(int,double));  
    // ...
};

Now, when the signature of foo in A changes so that A::foo(int,double) does not exist anymore, you will get an error stating this. Also, if B suddenly isn't derived from A anymore, you will get an error.

Let's put this into practice in the example that I gave in the introduction. If you would have used my OVERRIDE macro, you would have written your original code like this:

class A
{
public:  
    virtual void foo()  
    {    
        std::cout << "A::foo" << endl;  
    }
};
class B : public A
{
public:  
    OVERRIDE(A,void,foo,())  
    {    
        std::cout << "B::foo" << endl;  
    }
};

int main()
{  
    A* a = new B;  a->foo(); // prints "B::foo".
}

Now let's see what would have happened if you'd made the same change that was made in the introduction, that is, if you added a parameter to A's foo function. You'd then get this code:

class A
{
public:  
    virtual void foo(int n = 3)  
    {    
        std::cout << "A::foo(" << n << ")" << endl;  
    }
};
class B : public A
{
public:  OVERRIDE(A,void,foo,())  
         {    
             std::cout << "B::foo" << endl;  
         }
};

int main()
{  
    A* a = new B;  a->foo(); // prints "B::foo".
}

If you hadn't used OVERRIDE, this would have compiled just fine, and you would only have noticed your mistake after running the program. Now however, due to the OVERRIDE macro, your compiler generates an error, alerting you to your mistake!

For completeness, I'll give you a list of the parameters of the macro:

  1. The base class whose member function we want to override
  2. The return type of the member function
  3. The name of the member function that we're overriding
  4. The list of parameters of the member function, in parentheses!

It is important to know that the checking does generate some code, and even though the code is never called, you might want to disable the checks when you're doing a release build. You can do this by defining WITHOUT_OVERRIDE_CHECKING in your project settings.

Caveats

The trickery that this macro pulls does not work on all compilers, unfortunately. The reason for this is that some compilers (the Comeau compiler, for instance) do not allow you to take the address of a member function that is protected or private. On these compilers, the checks will work fine for overriding public member functions, but they will not work for protected or private member functions. To get around this, you must define WITHOUT_OVERRIDE_CHECKING when using these compilers, so that the checks are not compiled.

History

  • Version 0.1, 24 October 2003: Initial release.
  • Version 0.2, 16 November 2003: Major overhaul, moved macro usage to class definition, added support for protected functions.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Bart Samwel
Web Developer
Netherlands Netherlands
Bart Samwel is a professional C++ programmer. He is currently employed by Centric, a large IT company in The Netherlands. (Obligatory disclaimer: his articles here are a private matter, his employer has no responsibility for them.) Earlier, he has worked at Leiden University, where he has developed the Open Kernel Environment. Bart's home page can be found here.

Comments and Discussions

 
GeneralWorks brilliantly in practice PinmemberDavid Pritchard23-Feb-04 1:06 
GeneralProblem with downloaded file(s). PinmemberWREY17-Nov-03 10:02 
GeneralRe: Problem with downloaded file(s). PinmemberBart Samwel17-Nov-03 22:34 
GeneralWITHOUT_OVERRIDE_CHECKING not needed Pinmembernadavba6-Nov-03 2:58 
GeneralRe: WITHOUT_OVERRIDE_CHECKING not needed PinmemberBart Samwel6-Nov-03 3:10 
GeneralProblem and sub-optimal solution PinmemberDavid Pritchard5-Nov-03 0:49 
GeneralRe: Problem and sub-optimal solution Pinmembernadavba6-Nov-03 0:10 
GeneralRe: Problem and sub-optimal solution PinmemberBart Samwel6-Nov-03 1:05 
GeneralRe: Problem and sub-optimal solution Pinmembernadavba6-Nov-03 1:27 
GeneralRe: Problem and sub-optimal solution PinmemberBart Samwel6-Nov-03 2:09 
GeneralRe: Problem and sub-optimal solution Pinmembernadavba6-Nov-03 2:43 
GeneralRe: Problem and sub-optimal solution PinmemberBart Samwel6-Nov-03 3:08 
GeneralRe: Problem and sub-optimal solution Pinmembernadavba6-Nov-03 3:23 
GeneralRe: Problem and sub-optimal solution PinmemberBart Samwel6-Nov-03 4:06 
GeneralRe: Problem and sub-optimal solution PinmemberDavid Pritchard6-Nov-03 14:20 
GeneralYou OVERRIDE macro seems something verbose, maybe some improvement for it. Pinmember_Chen_Jun_4-Nov-03 16:01 
GeneralRe: You OVERRIDE macro seems something verbose, maybe some improvement for it. PinmemberBart Samwel4-Nov-03 23:15 
GeneralThank you, but more to say. Pinmember_Chen_Jun_5-Nov-03 15:33 
GeneralRe: Thank you, but more to say. PinmemberBart Samwel6-Nov-03 0:29 
GeneralAnother solution PinmemberGary DesRoches29-Oct-03 9:12 
GeneralRe: Another solution PinmemberBart Samwel29-Oct-03 11:56 
GeneralRe: Another solution PinmemberGary DesRoches29-Oct-03 12:02 
GeneralRe: Another solution PinmemberAndreMK30-Oct-03 9:25 
GeneralRe: Another solution PinmemberBart Samwel30-Oct-03 11:43 
GeneralRe: Another solution PinmemberAndreMK31-Oct-03 4:20 
GeneralRe: Another solution PinmemberBart Samwel31-Oct-03 4:36 
GeneralRe: Another solution PinmemberAndreMK31-Oct-03 19:32 
GeneralRe: Another solution PinmemberBart Samwel2-Nov-03 1:21 
GeneralRe: Another solution PinmemberAndreMK2-Nov-03 3:08 
GeneralRe: Another solution PinmemberBart Samwel4-Nov-03 23:22 
GeneralRe: Another solution PinmemberBart Samwel31-Oct-03 5:22 
GeneralI'm curious PinmemberHans Dietrich28-Oct-03 21:32 
GeneralRe: I'm curious PinmemberBart Samwel28-Oct-03 22:09 
GeneralChanging Signature == Changing Interface PinmemberChris Meech28-Oct-03 7:56 
GeneralRe: Changing Signature == Changing Interface PinmemberBart Samwel28-Oct-03 9:49 
GeneralRe: Changing Signature == Changing Interface PinmemberDavid Pritchard4-Nov-03 13:04 
GeneralRe: Changing Signature == Changing Interface Pinmemberpeterchen18-Nov-03 1:07 
GeneralRe: Changing Signature == Changing Interface PinmemberBart Samwel18-Nov-03 1:22 
GeneralRe: Changing Signature == Changing Interface Pinmemberpeterchen18-Nov-03 2:12 
GeneralRe: Changing Signature == Changing Interface PinmemberBart Samwel18-Nov-03 3:50 
Generalvirtual PinmemberKarstenK28-Oct-03 5:33 
GeneralRe: virtual PinmemberBart Samwel28-Oct-03 5:58 
GeneralRe: virtual PinmemberConstantin Chifor28-Oct-03 22:29 
GeneralRe: virtual PinmemberBart Samwel28-Oct-03 22:35 
GeneralRe: virtual PinmemberConstantin Chifor17-Nov-03 22:16 
GeneralRe: virtual PinmemberBart Samwel17-Nov-03 22:46 
GeneralRe: virtual PinmemberBart Samwel28-Oct-03 6:02 
GeneralRe: virtual PinmemberDavid Pritchard4-Nov-03 13:08 
GeneralRe: virtual PinmemberDavid Pritchard4-Nov-03 13:18 
GeneralRe: virtual PinmemberBart Samwel4-Nov-03 13:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141220.1 | Last Updated 18 Nov 2003
Article Copyright 2003 by Bart Samwel
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid