4

This doesn't work:

class Foo
{
public:
    virtual int A(int);
    virtual int A(int,int);
};
class Bar : public Foo
{
public:
    virtual int A(int);
};

Bar b;
int main()
{
    b.A(0,0);
}

It seems that by overriding Foo::A(int) with Bar::A(int) I have somehow hidden Foo::A(int,int). If I add a Bar::A(int,int) things work.

Does anyone have a link to a good description of what's going on here?

BCS
  • 75,627
  • 68
  • 187
  • 294
  • Possible duplicate: http://stackoverflow.com/questions/411103/function-with-same-name-but-different-signature-in-derived-class – CB Bailey Sep 26 '09 at 00:39

5 Answers5

5

Essentially, name lookup happens before overload resolution so the function A in your derived class overrides the virtual function in the base class but hides all other functions with the same name in any base classes.

Possible solutions include adding a using Foo::A; directive into your derived class to make all the base class members called A visible in the derived class or using different names for functions with different signatures.

See here as well.

Community
  • 1
  • 1
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • It's nice to get my suspicions confirmed. Do you know of a link to a full description of this corner of C++? – BCS Sep 26 '09 at 00:40
  • 1
    Name hiding is described in 3.3.7 [basic.scope.hiding] of the standard, name lookup is the whole of 3.4 [basic.lookup] and there's an entire chapter (13 [over]) on overloading and overload resolution. The basic rule for your situation is just as I've described, though. – CB Bailey Sep 26 '09 at 00:48
2
// I think this kind of approach is best to avoid this kind of problems.

class Foo
{
private:
    virtual int A_impl(int);     // note the private declaration 
    virtual int A_impl(int,int); // of the actual implementation.
                                 // clients have access through the
                                 // non-virtual interface.

public:
    inline int A(int x) 
    {                            // the non virtual interface will always be visible. 
        return A_impl(x);        // and consistent.
    }
    inline int A(int x, int y) 
    {
        if (x != y) {            // also permits global parameter validation
            return A_impl(x, y); // and it's easier to set breakpoints on a
        }                        // single entry point.
        return 0;
    }
};
class Bar : public Foo
{
private:
    virtual int A_impl(int);
};

Bar b;
int main()
{
    b.A(0,0);                    // never again stuff like: ((A*)&b)->A(0,0)
}
tika
  • 21
  • 1
2

There's a discussion on there here: http://bojolais.livejournal.com/222428.html

The crux is: In C++, when you have a class with an overloaded method (member function, whatever you want to call it), and you then extend and override that method, you must override all of the overloaded method

A workaround is to change the call to:

b.Foo::A(0, 0);
nall
  • 15,899
  • 4
  • 61
  • 65
0

To add to the above responses,

You could also define the overloaded function in the scope of Bar which always calls the same function in the scope of Foo if that is the intended result. This makes it easier to see that the code functions as expected.

Community
  • 1
  • 1
Jis Ben
  • 155
  • 1
  • 7
0

The easiest way of thinking about this is to remember that overloading always occurs WITHIN a single scope, while overriding appears between scopes. When figuring out which function to call, the compiler FIRST looks to find the closest scope that has the the name and then resolves overloading between definitions in that scope.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226