Declaration matching
10/Nov 2010
I encountered an interesting problem today. Consider the following piece of code:
namespace Test
{
struct Lol {};
struct Cat {};
struct Foo
{
virtual void Do(Lol&);
virtual void Do(Cat&);
};
struct Bar : public Foo
{
virtual void Do(Lol&);
void DoSomethingElse()
{
Cat cat;
Do(cat);
}
};
}
Question: what happens when you execute Bar::DoSomethingElse?
Answer: nothing, as trying to compile this piece of code will result in the following error: ‘Test::Bar::Do’ : cannot convert parameter 1 from ‘Test::Cat’ to ‘Test::Lol &’. At first, I was really surprised, I expected it to call Foo::Do. As it turns out, that’s a tricky case of mixing virtuals & method hiding. According to C++ standard, two function declarations of the same name refer to the same function if they are in the same scope and take same parameters. Function member of a derived class is not in the same scope as a function member in a base class. So, what happens here, when we declara Do in Bar class, we also hide all previous declarations of function with this name. From now on, only Bar::Do(Lol&) is visible. It kinda makes sense when you think about it, but at first it was really counterintuitive for me. Solution? Add this to Bar:
using Foo::Do;
Even safer way - rename one of functions. It’s moments like this that make me realize how many dark corners C++ has.
Old comments
Thomas 2010-11-21 22:55:17
at least you will get a warning i guess…
islet8 2010-11-13 07:10:05
I won’t use function override and overload at the same time, it’ll make trouble for other coders and readers.C++ has too many tricks to make us working inefficiently.
lzprgmr 2010-11-12 05:04:51
In fact, it has nothing to do with virtual — remove the virtual keyword you will get the same result.
admin 2010-11-12 05:20:25
That’s true, but if you’re using same method name/arguments and no virtual keyword, you most probably want to hide base methods.
Michal 2010-11-11 12:11:45
See also: Effective C++ Item 33
Bardzo ciekawy blog. Pozdrowienia :)