Разрешение перегрузки C ++
Учитывая следующий пример, почему я должен явно использовать оператор b->A::DoSomething()
а не только b->DoSomething()
?
Должно ли не отображаться перегрузочное разрешение компилятора, какой метод я имею в виду?
- strdup () - что он делает в C?
- Почему размер массива не такой же, как и у основного?
- Как программно создать функцию R?
- Имя таблицы как параметр функции PostgreSQL
- Использование нескольких .cpp-файлов в c ++-программе?
Я использую 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; }
- Использование boost-streamа и нестатической функции classа
- Ошибка: не удалось найти функцию ... в R
- Отправить форму при нажатии Enter с помощью AngularJS
- Встроенная функция связи
- Макро против функции в C
- Как просмотреть исходный код для функции?
- Почему std :: function не равнозначно сопоставимо?
- Почему C-массив имеет неправильное значение sizeof (), когда он передается функции?
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 ();