views:

618

answers:

3

I am currently doing some socket programming using C/C++. To be able to use a somewhat cleaner interface, and a more OO structure, I decided to write a few simple wrapper classes around parts of the C socket API, but while doing so I stumbled upon a problem:

Given the following code:

// Global method
int foo(int x)
{
    return x;
}

// Class that calls the global method
class FooBar
{
public:
    void foo() { return; };
    void baz() { foo(1); }
};

g++ gives the following error message:

test.cpp: In member function ‘void FooBar::baz()’:
test.cpp:10: error: no matching function for call to ‘FooBar::foo(int)’
test.cpp:9: note: candidates are: void FooBar::foo()

Renaming the class method solves the problem.

Why is it that there is some kind of naming conflict even though the method signatures are different? What is the best way to fix this?

Thanks /Erik

+3  A: 

You must use the scope resolution try:

::foo(1);

jab
+7  A: 

The problem is that it first looks in the scope of your class, and finds a foo function. The lookup will stop then, and the compiler tries to match arguments. Since it only has the one foo function in that scope in your class, calling the function fails.

You need to explicitly state that you want to call the free function:

::foo(1);

Another solution is to declare the function within baz:

void baz() { int foo(int); foo(1); }

The scope that the foo function is assumed to be defined in is the surrounding namespace of your class.

Johannes Schaub - litb
+1  A: 

The solution is:

void baz() { ::foo(1); }

"Why is it that there is some kind of naming conflict even though the method signatures are different? "

Because C++ always, always, looks up names first. When it finds a name in a relevant scope, it then checks what signatures are available for that name in that scope. So the foo() member function hides the foo(int) free function anywhere that it's in scope (that is, in other member functions of the class).

The following code won't compile, for the same reason:

struct A {
    virtual void foo(int) = 0;
    // attempt to provide a useful helper
    virtual void foo() { foo(23); }
};

struct B : public A {
    void foo(int i) {
        std::cout << i << "\n";
    }
};

int main() {
    B b;
    b.foo(); // oops, can't find foo(), because class B hid it
    A &a = b;
    a.foo(); // that works. So much for Liskov's substitution principle.
}

B, as written, is broken because it removes functionality from its base class (although only when referred to as B, not when referred to as A). litb provides a link in a comment below explaining how to unbreak it.

Steve Jessop
i was tempted to give them http://burks.bton.ac.uk/burks/language/cpp/cppfaq/strangei.htm#[23.3] :)
Johannes Schaub - litb