Click here to Skip to main content
Licence 
First Posted 27 Oct 2003
Views 96,585
Bookmarked 19 times

How to make sure that you override an existing function

By | 17 Nov 2003 | Article
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

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

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralWorks brilliantly in practice PinmemberDavid Pritchard0:06 23 Feb '04  
GeneralProblem with downloaded file(s). PinmemberWREY9:02 17 Nov '03  
GeneralRe: Problem with downloaded file(s). PinmemberBart Samwel21:34 17 Nov '03  
GeneralWITHOUT_OVERRIDE_CHECKING not needed Pinmembernadavba1:58 6 Nov '03  
GeneralRe: WITHOUT_OVERRIDE_CHECKING not needed PinmemberBart Samwel2:10 6 Nov '03  
GeneralProblem and sub-optimal solution PinmemberDavid Pritchard23:49 4 Nov '03  
GeneralRe: Problem and sub-optimal solution Pinmembernadavba23:10 5 Nov '03  
GeneralRe: Problem and sub-optimal solution PinmemberBart Samwel0:05 6 Nov '03  
GeneralRe: Problem and sub-optimal solution Pinmembernadavba0:27 6 Nov '03  
GeneralRe: Problem and sub-optimal solution PinmemberBart Samwel1:09 6 Nov '03  
GeneralRe: Problem and sub-optimal solution Pinmembernadavba1:43 6 Nov '03  
GeneralRe: Problem and sub-optimal solution PinmemberBart Samwel2:08 6 Nov '03  
GeneralRe: Problem and sub-optimal solution Pinmembernadavba2:23 6 Nov '03  
GeneralRe: Problem and sub-optimal solution PinmemberBart Samwel3:06 6 Nov '03  
GeneralRe: Problem and sub-optimal solution PinmemberDavid Pritchard13:20 6 Nov '03  
GeneralYou OVERRIDE macro seems something verbose, maybe some improvement for it. Pinmember_Chen_Jun_15:01 4 Nov '03  
GeneralRe: You OVERRIDE macro seems something verbose, maybe some improvement for it. PinmemberBart Samwel22:15 4 Nov '03  
GeneralThank you, but more to say. Pinmember_Chen_Jun_14:33 5 Nov '03  
GeneralRe: Thank you, but more to say. PinmemberBart Samwel23:29 5 Nov '03  
GeneralAnother solution PinmemberGary DesRoches8:12 29 Oct '03  
GeneralRe: Another solution PinmemberBart Samwel10:56 29 Oct '03  
GeneralRe: Another solution PinmemberGary DesRoches11:02 29 Oct '03  
GeneralRe: Another solution PinmemberAndreMK8:25 30 Oct '03  
GeneralRe: Another solution PinmemberBart Samwel10:43 30 Oct '03  
GeneralRe: Another solution PinmemberAndreMK3:20 31 Oct '03  

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.

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