A few days ago, we posted two C++ quizzes based on a question posted in a forum. Let’s review the first question
The guy was frustrated because he expected two things:
- The code would compile without errors.
- Line 30 would end up by calling Baz::DoStuff() which in turn would have printed that same in the output console.
Instead, he got the following compile-time error at that same line
e:\foo.cpp(30): error C2660: ‘Bar::DoStuff’ : function does not take 0 arguments
The root of this compilation error is at line 11: as we are closing the definition of class Bar without saying anything about method DoStuff without arguments but, instead, having overloaded DoStuff in line 10 with a version that takes an argument of type int, what we just did was hide the original Foo::Stuff() declaration. With that said, the compilation error makes sense.
|The fact that Foo::Stuff() is a pure virtual method is not a necessary condition for this to happen at all. It would have happened with virtual and non-virtual methods as well.|
I have the feeling that Java and C# developers may have experienced this when coding artifacts in C++ as, in those languages, this notion of hiding declarations is not available (there’s an alternative consisting in declaring members as private, so subclasses won’t get them visible, but in that case the decision of what is hidden belongs to the coder of the superclass. In C++, the decision is to be taken by the coder of the derived class.
How could my friend overcome this error in order to get the application working as he expected? By including a using declaration in the definition of Bar like the one at line 5 here:
Now the application runs as initially intended.
In quiz 2, the C++ principle we just reviewed applies as well, but if hiding was not what we wanted to do, this issue could turn into something more dangerous because the application will compile anyway and the undesired behavior will have to be discovered at runtime.
Despite the fact that Foo::DoStuff(char) isn’t visible in line 30, the ‘a’ received as argument is implicitly converted to the int type, producing:
Again, the solution here is based on a using declaration as before:
Once declared, we just compile, run and… voilà
As a conclusion, hiding a base class method is neither a bad thing nor something to avoid as long as it’s exactly what you wanted to get.