2016-12-26 2 views
3

У меня голова холодная, поэтому может быть, что я просто слишком перегружен, чтобы понять, что здесь происходит, но я не могу понять, как следующее не компилируется ?Перегрузка функции C++ (понимание того, почему этот случай неоднозначен)

#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; 
} 

Ошибки я получаю:

./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 

Если переименовать первый экземпляр foo к fooString то все работает так, что кажется, что второй экземпляр foo каким-то образом скрывается первый. Однако, учитывая, что второй экземпляр имеет два аргумента вместо одного, я не могу понять, как он будет неоднозначным.

ОБНОВЛЕНИЕ: Он также отлично работает без наследования (если это все один класс), поэтому я подозреваю, что не понимаю какое-либо правило наследования.

+3

http://stackoverflow.com/questions/4146499/why-does-a-virtual-function-get-hidden –

+0

@latedeveloper благодарит, это объясняет это красиво. – Pace

+0

, который работает 'x.Base :: foo (blah);' –

ответ

1

Вашего virtual void foo(const void * bytes, int size) функции внутри Derived класса два параметра, но при вызове этой функции x.foo(blah); из main вы передаете только один параметр blah.

Вам необходимо передать два параметра в функцию вызова, как функция foo внутри Derived класс ожидает.

В качестве альтернативы, если вы хотите, чтобы вызвать foo функции Base класса, попробуйте x.Base::foo(blah);

1

Проблему с кодом не, что функции неоднозначны! Вместо этого проблема заключается в том, что перезапись в Derived фактически скрывает функцию базового класса! Если вы хотите, чтобы избежать этого скрываясь, вы можете сделать версии базового класса доступны с using -declaration:

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

В качестве альтернативы вы можете явно вызвать функцию базового класса, используя квалификацию на месте вызова:

x.Base::foo(blah); 

Чтобы избежать необходимости иметь производные классы сделать что-то особенное, когда они переопределять virtual функции вы лучше с использованием подхода, наличия в virtual функции быть protected и имеют public функция делегирования этих (этот подход последовательно используется для virtual функций в стандартной библиотеке C++), например .:

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); } 
}; 

... и затем переопределить do_foo() надлежащим образом в производных классах.