Разрешение перегрузки C ++

Учитывая следующий пример, почему я должен явно использовать оператор b->A::DoSomething() а не только b->DoSomething() ?

Должно ли не отображаться перегрузочное разрешение компилятора, какой метод я имею в виду?

Я использую Microsoft VS 2005. (Примечание: использование виртуального не помогает в этом случае.)

 class A { public: int DoSomething() {return 0;}; }; class B : public A { public: int DoSomething(int x) {return 1;}; }; int main() { B* b = new B(); b->A::DoSomething(); //Why this? //b->DoSomething(); //Why not this? (Gives compiler error.) delete b; return 0; } 

9 Solutions collect form web for “Разрешение перегрузки C ++”

Две «перегрузки» не совпадают. По умолчанию компилятор учитывает наименьшую возможную область имен до тех пор, пока не найдет совпадение имен. Последовательность аргументов выполняется позже . В вашем случае это означает, что компилятор видит B::DoSomething . Затем он пытается сопоставить список аргументов, который терпит неудачу.

Одним из решений было бы вывести перегрузку из A в область B :

 class B : public A { public: using A::DoSomething; // … } 

Разрешение перегрузки – одна из самых уродливых частей C ++

В основном компилятор находит совпадение имен «DoSomething (int)» в области B, видит, что параметры не совпадают, и останавливается с ошибкой.

Его можно преодолеть, используя A :: DoSomething в classе B

 class A { public: int DoSomething() {return 0;} }; class B : public A { public: using A::DoSomething; int DoSomething(int x) {return 1;} }; int main(int argc, char** argv) { B* b = new B(); // b->A::DoSomething(); // still works, but... b->DoSomething(); // works now too delete b; return 0; } 

Нет, это поведение присутствует, чтобы убедиться, что вы не поймаете наследование от далеких базовых classов по ошибке.

Чтобы обойти это, вам нужно сообщить компилятору, какой метод вы хотите вызвать, разместив A :: DoSomething в classе B.

См. Эту статью для быстрого и простого обзора этого поведения.

Наличие метода в производном classе скрывает все методы с тем же именем (независимо от параметров) в базовых classах. Это делается для того, чтобы избежать таких проблем:

 class A {} ; class B :public A { void DoSomething(long) {...} } B b; b.DoSomething(1); // calls B::DoSomething((long)1)); 

чем позже кто-то изменяет class A:

 class A { void DoSomething(int ) {...} } 

теперь вдруг:

 B b; b.DoSomething(1); // calls A::DoSomething(1); 

Другими словами, если это не сработало так, то несвязанное изменение в classе, который вы не контролируете (A), может бесшумно повлиять на работу вашего кода.

Это как-то связано с тем, как работает разрешение имен. В основном мы сначала находим область действия, из которой приходит имя, а затем мы собираем все перегрузки для этого имени в этой области. Тем не менее, область действия в вашем случае – class B, а в classе B, B :: DoSomething скрывает A :: DOSomething:

3.3.7. Сокрытие имени [basic.scope.hiding]

… [надрез] …

3 В определении функции члена объявление локального имени скрывает объявление члена classа с тем же именем; см. basic.scope.class . Объявление члена в производном classе ( class.derived ) скрывает объявление члена базового classа с тем же именем; см. class.member.lookup .

Из-за скрытия имени A :: DoSomething даже не рассматривается для разрешения перегрузки

Когда вы определяете функцию в производном classе, тогда она скрывает все функции с этим именем в базовом classе. Если функция базового classа является виртуальной и имеет совместимую сигнатуру, функция производного classа также переопределяет базовую функцию classа. Однако это не влияет на видимость.

Вы можете сделать функцию базового classа видимой с помощью объявления using:

 class B : public A { public: int DoSomething(int x) {return 1;}; using A::DoSomething; }; 

Это не перегрузка! Это СКРЫТЬ!

При поиске дерева наследования для используемой функции C ++ использует имя без аргументов, как только оно обнаруживает какое-либо определение, которое оно останавливает, затем анализирует аргументы. В приведенном примере он останавливается в classе B. Чтобы иметь возможность делать то, что вам нужно, class B должен быть определен следующим образом:

 class B : public A { public: using A::DoSomething; int DoSomething(int x) {return 1;}; }; 

Функция скрыта функцией с тем же именем в подclassе (но с другой подписью). Вы можете отобразить его, используя инструкцию using, как при использовании A :: DoSomething ();

  • Функция триггера jquery, когда элемент находится в viewport
  • Как вернуть строковое значение из функции Bash
  • Является ли часть возвращаемого типа сигнатурой функции?
  • Зачем использовать именованные функциональные выражения?
  • Почему C ++ не поддерживает функции, возвращающие массивы?
  • Как сделать .lib-файл, когда есть .dll-файл и заголовочный файл
  • Написание собственной функции квадратного корня
  • Что такое «статическая» функция?
  • Передача целочисленного значения по ссылке в Python
  • Почему размер массива не такой же, как и у основного?
  • Разница между . и: в Луа
  • Давайте будем гением компьютера.