Разрешение перегрузки 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 ();

  • Поддерживает ли Ninject Func (автоматически сгенерированный завод)?
  • 'foo' не был объявлен в этой области c ++
  • Передача целочисленного значения по ссылке в Python
  • Как изменить реализацию (обход) функции, объявленной извне
  • Вложенная функция в C
  • Почему в параметрах C ++ последнее значение должно быть добавлено последними?
  • Когда функция слишком длинная?
  • Выполнить функцию jQuery после выполнения другой функции
  • Последняя непустая ячейка в столбце
  • Передача строки с пробелами в качестве аргумента функции в bash
  • Как создать пользовательскую функцию EL для вызова статического метода?
  • Interesting Posts

    В C #, что происходит, когда вы вызываете метод расширения на нулевом объекте?

    Вычисление среднего арифметического (один тип среднего) в Python

    Смотрите и очистите кеши / буферы Postgres?

    Текст Android TextView не обернут

    Как можно добавить разделитель между элементами в ItemsControl

    Помощь в скорости RAM? И стоит ли это двухканальный?

    Разрешение запрещается при доступе к общей папке VirtualBox, когда член группы vboxsf

    Какие недостатки существуют при использовании памяти, которая быстрее, чем у материнской платы?

    В чем разница между командами «su -s» и «sudo-s»?

    Как я могу обновить внешний вид JFreeChart после того, как он станет видимым?

    Переместить все файлы из подкаталогов в текущий каталог?

    Как проверить, не поврежден ли корпус или не удался жесткий диск?

    Как прослушать завершение загрузки WebView URL-адреса?

    Каков наилучший способ распылить краску внутри моего дела?

    Может ли XP загружать драйверы предварительной установки из любого другого места, кроме дискеты?

    Давайте будем гением компьютера.