У меня есть следующий код:
struct CommonVariables
{/*some common variables that need to be proceed*/};
struct CommonHandler
{
static void foo(const CommonVariables& vars) {/*processed vars*/}
void bar(const CommonVariables& vars) {/*processed vars*/}
};
struct AnotherVariables
{/*another variables*/};
struct AnotherHandler
{
static void foo(const AnotherVariables& vars) {/*processed vars*/}
void bar(const AnotherVariables& vars) {/*processed vars*/}
};
struct Derived : CommonHandler, AnotherHandler
{};
И когда я пытаюсь вызвать Derived :: foo (/ любой тип переменной /) или Derived d; d.bar (/ любой тип переменной /), компилятор выдает мне ошибку: "ссылка на 'foo (или bar)' неоднозначна".
Еще ниже у меня почти такая же ситуация:
struct DifferentHandler
{
static void foo(const CommonVariables& vars) {}
static void foo(const AnotherVariables& vars) {}
void bar(const AnotherVariables& vars) {}
void bar(const CommonVariables& vars) {}
};
И вызов DifferentHandler :: foo (/ любого типа переменной /) или 'bar' работает просто отлично.
Существует множество решений для обхода первого блока кода (черты шаблона и т. д.). Что я конкретно хочу, это перегрузить методы с помощью наследования. И я не понимаю, почему вызовы из Derived неоднозначны (поскольку входные параметры имеют разные типы, с точки зрения компилятора эти функции разные. Как в DifferentHandler)
ПРИМЕЧАНИЕ: я пробовал MinGW5.8 (в Qt Creator) и MSVC2015 в VS2015. Оба компилятора сгенерировали одну и ту же ошибку.
2 ответа
Ну вот:
struct Derived : CommonHandler, AnotherHandler
{
using CommonHandler::foo;
using CommonHandler::bar;
using AnotherHandler::foo;
using AnotherHandler::bar;
};
Исправляет вашу проблему.
Причина, по которой оригинальный код не работает, находится в стандарте C ++. Вот интересные цитаты:
В 10/2:
Говорят, что члены базового класса наследуются производным классом. Унаследованные члены могут упоминаться в выражениях так же, как и другие члены производного класса, если только их имена не являются скрытыми или неоднозначными (10.2).
Продолжаем чтение до 10.2:
Поиск имени члена определяет значение имени (id-выражения) в области видимости класса (3.3.7). Поиск имени может привести к неоднозначности, в этом случае программа плохо сформирована ....
... состоит из двух наборов компонентов: набор объявлений, набор членов named f ...
Если имя перегруженной функции найдено однозначно, разрешение перегрузки (13.3) также имеет место перед контролем доступа
В основном, он сначала идет по имени, а позже применяется для разрешения. Представление их производному классу через объявление using
помещает их все в область действия производного класса, где вступают в силу нормальные правила разрешения.
В C ++, если функция-член производного класса имеет то же имя, что и функция-член базового класса, тогда версия производного класса скрывает базовую версию - даже если сигнатуры функций отличаются, и в противном случае вы ожидаете, что они перегружены. (Если функция-член базового класса является виртуальной, то сигнатура производного класса должна точно соответствовать *, или она (обычно непреднамеренно) скрывает версию базового класса - по этой причине C ++ 11 добавил override
псевдо -ключевое слово).
Например:
struct base {
void foo(std::string s) {}
};
struct derived : base {
void foo(int i) {}
};
int main() {
derived d;
d.foo("hello"); // Error -- cannot convert const char* to int
}
Решение состоит в том, чтобы использовать директиву using
, чтобы перевести функцию-член базового класса в область видимости производного класса, т.е.
struct derived : base {
using base::foo;
void foo(int i) {}
};
(Альтернативой является использование неясного
derived d;
d.base::foo("hello"); // works
Синтаксис, чтобы указать, что вы хотите вызвать версию базового класса, но это редко встречается в реальном мире.)
Похожие вопросы
Новые вопросы
c++
C ++ - это язык программирования общего назначения. Первоначально он был разработан как расширение C и имеет аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде (который будет скомпилирован с помощью компилятора C ++). Используйте тег, зависящий от версии, для вопросов, связанных с конкретной редакцией стандарта [C ++ 11], [C ++ 14], [C ++ 17] или [C ++ 20] и т. Д.