views:

52

answers:

3

I have an MFC C++ program that contains two classes, as follows;

struct MyStruct
{
'
'
};

class   Class1
{ 
public:
   virtual MyStruct *MyFunc(LPCTSTR x);
   virtual void MyFunc(MyStruct *x);
'
'
};

class Class2 : public Class1
{
public:
  virtual void MyFunc(MyStruct *x);
'
'
};

main()
{
'
'
  CString Str = _T("WTF");
  Class2 a;
  a.MyFunc(Str);
'
'
}

When I compile this under VS2003 code I get error C2664: 'MyFunc' : cannot convert parameter 1 from 'class CString' to 'struct MyStruct *' whereas I would have expected the compiler to pick up the globally defined conversion from CString to LPCTSTR and call the base member MyStruct *MyFunc(LPCTSTR x); Note that if I remove virtual void MyFunc(MyStruct *x); from the definition of Class2 it compiles just fine.

I'm probably missing something pretty simple here, but I can't figure out why this doesn't work. Any ideas greatly appreciated.

+4  A: 

Add

using Class1::MyFunc;

in Class2. Classes are nested scopes and name lookup stop when a match is found. The same problem can occur with nested namespaces (with the same solution), but is less common in practice.

AProgrammer
A: 

you should add to Class2

virtual MyStruct *MyFunc(LPCTSTR x)
{
    return Class1::MyFunc(x);
}

or specify explicitly the base class method when you call it:

a.Class1::MyFunc(Str);
sergiom
The solution is good, but the statement incorrect. What is there is called method hiding. If a function name is found in the current scope the compiler doesn't search it anymore, even if the signature doesn't match.
PierreBdR
Didn't know that. I removed the incorrect statement. :)
sergiom
+3  A: 

This is by design to handle what is called the "fragile base class" problem.

Let's assume you have classes like this:

struct A
{
    void MyFunc(long)  {...}
}

struct B : A
{
    void MyFunc(long) { ... }
}
....
B  b;
b.MyFunc(5);

Here's we would call B:MyFunc(long) because ints silently convert to longs.

But say someone later changed struct A to:

struct A
{
    void MyFunc(long)  {...}
    void MyFunc(int)   {...}
}

Now, if override worked like you assumed, that the call to b.MyFunc(5) would change to call to A::MyFunc(int) --- even though neither your calling code nor struct B, the class you are actual using, changed. This was deemed worse a little confusion.

James Curran
Very informative, thanks.
Nikola Smiljanić
Thanks, makes perfect sense once you know why.
Shane MacLaughlin