3

I have a head cold so it may be that I am simply too congested to understand what is going on here but I can't figure out how the following doesn't compile?

#include <string>
#include <iostream>

class Base {

public:
    virtual void foo(const std::string & data) {
        foo(data.data(), data.size());
    }
    virtual void foo(const void * bytes, int size) = 0;

};

class Derived : public Base{

public:
    virtual void foo(const void * bytes, int size) {
        std::cout << "Num Bytes: " << size << std::endl;
    }
};

int main() {
    Derived x;
    std::string blah = "Hello";
    x.foo(blah);
    return 0;
}

The error I get is:

./foo.cpp: In function ‘int main()’:
./foo.cpp:25:15: error: no matching function for call to ‘Derived::foo(std::__cxx11::string&)’
     x.foo(blah);
               ^
./foo.cpp:17:18: note: candidate: virtual void Derived::foo(const void*, int)
     virtual void foo(const void * bytes, int size) {
                  ^
./foo.cpp:17:18: note:   candidate expects 2 arguments, 1 provided

If I rename the first instance of foo to fooString then everything works so it seems the second instance of foo is somehow hiding the first. However, given that the second instance has two arguments instead of one I can't figure out how it would be ambiguous.

UPDATE: It also works fine without the inheritance (if it is all one class) so I suspect I am misunderstanding some rule of inheritance.

Pace
  • 41,875
  • 13
  • 113
  • 156

2 Answers2

2

Your virtual void foo(const void * bytes, int size) function inside Derived class expects two parameters but when calling this function x.foo(blah); from main you are passing only one parameter blah.

You need to pass two parameters in to the function call as your foofunction inside Derived class expects.

Alternatively if you want to call the foo function of Base class, try x.Base::foo(blah);

Yousaf
  • 27,861
  • 6
  • 44
  • 69
1

The problem with your code is not that the functions are ambiguous! Instead, the problem is that the overwrite in Derived actually hides the base class function(s)! If you want to avoid this hiding, you can make the base class versions available with a using-declaration:

class Derived: public Base {
    // ...
public:
     using Base::foo;
     void foo(void const* bytes, int size) override {
        // ...
     }
};

Alternatively you can explicitly call the base class function using qualification at the call site:

x.Base::foo(blah);

To avoid the need of having derived classes do something special when they override a virtual function you are best off using the approach of having the virtual functions be protected and have public function delegating to these (this approach is consistently used for virtual functions in the standard C++ library), e.g.:

class Base {
protected:
    virtual void do_foo(std::string const& s) {
        this->foo(s.c_str(), s.size());
    }
    virtual void do_foo(void const* bytes, int size) = 0;
public:
    void foo(std::string const& s) { this->do_foo(s); }
    void foo(void const* bytes, int size) { this->do_foo(bytes, size); }
};

... and then override do_foo() appropriately in derived classes.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380