Saturday, March 1, 2008

C++ inheritance oddity

There are plenty of things that can make C++ a complicated language. But in general the creators of C++ would have gone though a painstaking process to ensure that the language as intuitive and useable as possible (without sacrificing on functionality of course). However, when I came accross the following C++ behaviour I was confused.

Lets just say that I have a base class and a derived class. The base class has 3 member functions, each called doSomething() as below.

The functionality of the doSomething() methods isn't important right now, but assume that the methods are implemented. What is important is that you can create an object of type DerivedClass and it can use the 3 doSomething() methods defined in the base class. This is all straightforward inheritance stuff you say, and you'd be right, but wait, the craziness is about to begin...

Now, lets say I want to redefine one of the doSomething() methods, but I want to do it in the derived class, i.e. I want to do the following:
Again, assume that the DerivedClass's doSomething() method is implemented. Now, assume I make an object of type DerivedClass. If I call the bare doSomething() method everything is ok, but if I try to call doSomething(int x) or doSomething(double x) the program won't compile!!

This is because if you re-implement any of the functions in a base class, all other functions with the same name are now un-callable.

So what, you say. Sure re-implementing non-virtual functions in derived classes is a bad idea anyway. But this behaviour is the same even if the three doSomething() functions are virtual. I'll say that again: this behaviour is the same even if the three doSomething() functions are virtual. So the following will see the exact same behaviour.

The derived object is only able to call the doSomething() method that it defines itself, and not the other 2 defined in the base class. This seemed really strange to me, as I would have assumed that if I the doSomething() functions that accept the int and double could be called. After all, they are all virtual functions, which means that they are supposed to be selectively re-definable!!

The reason for this strangeness is so that you do not get caught out inheriting from distant base classes by mistake. But, I'd still prefer if it was not the case as it seems kind of counter intuitive.

There is a simple way around this, and it is to add in a using BaseClass::doSomething; in the derived class definition. This will work for both the virtial and non-virtual cases above, and will allow the DerivedClass to re-implement some of the doSomething() functions and still allow the other ones to be used.

Lurning Man

No comments: