2015-07-17 2 views
1

У меня есть базовый класс, унаследованный многими подклассами. Мне нужно определить новую подпись для абстрактного метода, который в основном является оберткой. Я попробовал этотВнедрение обертки для абстрактного метода в базовом классе

class B { 
public: 
    virtual void f() = 0; 
    void f(string msg) { /* print msg and call f() */ } 
}; 

class D : public B { 
public: 
    void f() override { /* implementatation */} 
}; 

int main() { 
    D d; 
    d.f("msg"); 
} 

Но он не компилируется и дать следующую ошибку

error: no matching function for call to 'D::f(string) 

Мои вопросы:

  1. Почему не D::f(string) могут быть решены?
  2. Почему любая из следующих проблем устраняет проблему?
    • переименование f(string) к f2(string) (некрасиво)
    • определение D::f(string x) { B::f(x)} (некрасиво, как это должно быть определено в каждом подклассов)
    • удаления абстрактный метод, B::f() (не приемлемо)

Любое лучшее решение?

+1

Выведенная 'ф 'override скрывает базу' f (std :: string) '. Попробуйте помещать 'using B :: f;' в ваш производный класс, чтобы привести их из 'B' – Alejandro

+0

@ Ответы Alejandro принадлежат как ответы, а не как комментарии. – Barry

+0

Учитывая, что один 'f' вызывает другой' f', у них есть несколько разные роли. Поэтому переименование их, чтобы отличать инициатора более высокого уровня от реализации, может быть полезно просто для ясности (в дополнение к решению проблемы). – TheUndeadFish

ответ

4

Вопрос заключается в том, что вы спряталсяB::f(std::string) здесь:

class D : public B { 
public: 
    void f() override; 
}; 

При вызове D.f("msg"), поиск имени будет найти один f() в D и налюбоваться. We first найти функции кандидата затем выполнить разрешение перегрузки. Поскольку этот случай не принимает аргументов, вы получаете ошибку компиляции.

Если вы хотите использовать другую перегрузку f, вам нужно, чтобы привести его в D, а также, например, так:

class D : public B { 
public: 
    using B::f; 
    void f() override; 
}; 

Теперь мы имеем D::f() (переопределенную виртуальную функцию) и D::f(std::string) (который мы принесенный с B).

Альтернативным, тривиальным решением было бы просто переименовать одну или другую функцию, чтобы у вас не было этой проблемы для начала.

+0

Гораздо лучше, чем я собирался писать в любом случае! Отличный ответ – Alejandro

+0

Любая причина, по которой компилятор перестает искать подходящую функцию после того, как найдет несоответствующий кандидат? Для меня имеет смысл продолжить поиск по всем кандидатам до сообщения об ошибке. Я что-то пропустил? – nmoses

+0

@nmoses Порядок здесь (1) найти кандидатские функции (2) обрезать жизнеспособные кандидатские функции (3) выбрать лучшего жизнеспособного кандидата. Шаг (1) - это просто поиск по имени. Когда мы найдем 'D :: f()', мы закончили с этим шагом. Затем шаг (2) удаляет его, поскольку он не является жизнеспособным. – Barry

1

Вы используете 0oidoims? Такие, как:

class B { 
public: 
    virtual void f() = 0; 
    void f(string msg) { 
    /* print msg and call f() */ 
    std::cout << msg; 
    f(); 
    } 
    virtual ~B() {} 
}; 

Тогда вы должны, насколько это возможно попытаться вызвать функцию невиртуальный члена из базового класса (по ссылке или указателю), такие как:

D d; 
B& b = d; 
b.f("msg"); 
Смежные вопросы