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

How to make sure that you override an existing function

By , 17 Nov 2003
 

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

About the Author

Bart Samwel
Web Developer
Netherlands Netherlands
Member
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.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralWorks brilliantly in practicememberDavid Pritchard23 Feb '04 - 0:06 
GeneralProblem with downloaded file(s).memberWREY17 Nov '03 - 9:02 
GeneralRe: Problem with downloaded file(s).memberBart Samwel17 Nov '03 - 21:34 
GeneralWITHOUT_OVERRIDE_CHECKING not neededmembernadavba6 Nov '03 - 1:58 
GeneralRe: WITHOUT_OVERRIDE_CHECKING not neededmemberBart Samwel6 Nov '03 - 2:10 
GeneralProblem and sub-optimal solutionmemberDavid Pritchard4 Nov '03 - 23:49 
GeneralRe: Problem and sub-optimal solutionmembernadavba5 Nov '03 - 23:10 
GeneralRe: Problem and sub-optimal solutionmemberBart Samwel6 Nov '03 - 0:05 
GeneralRe: Problem and sub-optimal solutionmembernadavba6 Nov '03 - 0:27 
GeneralRe: Problem and sub-optimal solutionmemberBart Samwel6 Nov '03 - 1:09 
GeneralRe: Problem and sub-optimal solutionmembernadavba6 Nov '03 - 1:43 
GeneralRe: Problem and sub-optimal solutionmemberBart Samwel6 Nov '03 - 2:08 
GeneralRe: Problem and sub-optimal solutionmembernadavba6 Nov '03 - 2:23 
GeneralRe: Problem and sub-optimal solutionmemberBart Samwel6 Nov '03 - 3:06 
GeneralRe: Problem and sub-optimal solutionmemberDavid Pritchard6 Nov '03 - 13:20 
GeneralYou OVERRIDE macro seems something verbose, maybe some improvement for it.member_Chen_Jun_4 Nov '03 - 15:01 
GeneralRe: You OVERRIDE macro seems something verbose, maybe some improvement for it.memberBart Samwel4 Nov '03 - 22:15 
GeneralThank you, but more to say.member_Chen_Jun_5 Nov '03 - 14:33 
GeneralRe: Thank you, but more to say.memberBart Samwel5 Nov '03 - 23:29 
GeneralAnother solutionmemberGary DesRoches29 Oct '03 - 8:12 
GeneralRe: Another solutionmemberBart Samwel29 Oct '03 - 10:56 
GeneralRe: Another solutionmemberGary DesRoches29 Oct '03 - 11:02 
GeneralRe: Another solutionmemberAndreMK30 Oct '03 - 8:25 
GeneralRe: Another solutionmemberBart Samwel30 Oct '03 - 10:43 
GeneralRe: Another solutionmemberAndreMK31 Oct '03 - 3:20 
GeneralRe: Another solutionmemberBart Samwel31 Oct '03 - 3:36 
GeneralRe: Another solutionmemberAndreMK31 Oct '03 - 18:32 
GeneralRe: Another solutionmemberBart Samwel2 Nov '03 - 0:21 
GeneralRe: Another solutionmemberAndreMK2 Nov '03 - 2:08 
GeneralRe: Another solutionmemberBart Samwel4 Nov '03 - 22:22 
GeneralRe: Another solutionmemberBart Samwel31 Oct '03 - 4:22 
GeneralI'm curiousmemberHans Dietrich28 Oct '03 - 20:32 
GeneralRe: I'm curiousmemberBart Samwel28 Oct '03 - 21:09 
GeneralChanging Signature == Changing InterfacememberChris Meech28 Oct '03 - 6:56 
GeneralRe: Changing Signature == Changing InterfacememberBart Samwel28 Oct '03 - 8:49 
GeneralRe: Changing Signature == Changing InterfacememberDavid Pritchard4 Nov '03 - 12:04 
GeneralRe: Changing Signature == Changing Interfacememberpeterchen18 Nov '03 - 0:07 
GeneralRe: Changing Signature == Changing InterfacememberBart Samwel18 Nov '03 - 0:22 
GeneralRe: Changing Signature == Changing Interfacememberpeterchen18 Nov '03 - 1:12 
GeneralRe: Changing Signature == Changing InterfacememberBart Samwel18 Nov '03 - 2:50 
GeneralvirtualmemberKarstenK28 Oct '03 - 4:33 
GeneralRe: virtualmemberBart Samwel28 Oct '03 - 4:58 
GeneralRe: virtualmemberConstantin Chifor28 Oct '03 - 21:29 
GeneralRe: virtualmemberBart Samwel28 Oct '03 - 21:35 
GeneralRe: virtualmemberConstantin Chifor17 Nov '03 - 21:16 
GeneralRe: virtualmemberBart Samwel17 Nov '03 - 21:46 
GeneralRe: virtualmemberBart Samwel28 Oct '03 - 5:02 
GeneralRe: virtualmemberDavid Pritchard4 Nov '03 - 12:08 
GeneralRe: virtualmemberDavid Pritchard4 Nov '03 - 12:18 
GeneralRe: virtualmemberBart Samwel4 Nov '03 - 12:38 

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

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