Я ждал, чтобы поместить свой ответ в другой пост, в более правильно классифицированную проблему.Ваш вопрос соответствует концепции, я попытался объяснить подробно.но, так как я не знаю, как ссылка отвечает, я просто скопирую / вставлю полный сценарий здесь ... Пожалуйста, пройдите по нему, вы поймете все, что можно понять о вашей проблеме, вы спросили
Допустим, компилятор должен разрешить вызов следующим образом: *
A a = new AA ();// Предположим, что AA является некоторым подклассом класса A
a-> someFunc ();// и мы вызываем метод "someFunc ()" для
*.
Теперь компилятор методично выполнит следующие шаги.
1.) Во-первых, компилятор знает объявленный тип переменной a, поэтому он проверит, есть ли у объявленного типа объекта a (lets call this, class A for time being
) метод с именем someFunc () и что он должен бытьpublic. Этот метод может быть либо объявлен в class A
, либо он может быть производным от одного из базовых классов класса A, но это не имеет значения для компилятора, и он просто проверяет его существование с помощью своегоспецификатор доступа: public
.
- Нет необходимости говорить, что любая ошибка на этом шаге вызовет ошибку компилятора.
2.) Во-вторых, после проверки метода наБудучи частью класса А., компилятор должен разрешить вызов правильного метода, поскольку многие методы могут быть там с одинаковыми именами (благодаря перегрузке функции). Этот процесс разрешения правильного метода называется overloading resolution
. Компилятор достигает этогопо мамесвязывание подписей вызываемого метода со всеми перегруженными методами, которые являются частью класса.Таким образом, из всех someFunc() s
будет найдена и рассмотрена только правильная функция someFunc () (сопоставляющая сигнатуры вызываемому методу).
3.) Теперь наступает сложная часть, может случиться так, чтоФункция someFunc () может быть переопределена в одном из подклассов класса A (lets call this class AA and needless to say it is some subclass of A
), и эта переменная a (объявленная как тип A) может фактически ссылаться на объект класса AA (это допустимо вC ++ для включения полиморфизма).Теперь, если объявлено, что метод someFunc () имеет тип virtual
, в базовом классе (т. Е. Классе A) и someFunc () был переопределен подклассом (ами) A (либо в AA, либо в классах между A и AA), правильная версия someFunc () должна быть найдена компилятором.
Теперь представьте, что вы компилятор, и у вас есть задача выяснить, есть ли у класса AA
этот метод.Очевидно, что класс AA будет иметь этот метод, поскольку он является подклассом A, и открытый доступ A в классе A уже был проверен на шаге 1 компилятором !!!,Но в качестве альтернативы, как упомянуто в предыдущем абзаце, someFunc () может быть переопределен классом AA (или любым другим классом между A и AA), что и нужно отлавливать компилятору.Следовательно, вы (поскольку вы играете в компиляторе) могли бы сделать систематическую проверку, чтобы найти самый нижний (самый низкий в дереве наследования) переопределенный метод someFunc (), начиная с класса A и заканчивая в классе AA.В этом поиске вы будете искать те же сигнатуры методов, которые были проверены при разрешении перегрузки.Этот метод будет методом, который будет вызван.
Теперь вы можете задаться вопросом: «Какого чёрта», этот поиск выполняется каждый раз? ... Ну не совсем. Компилятор знает, что каждый раз обнаруживает это, и поэтому поддерживает структуру данных с именем Virtual Table
для каждого типа класса. Представьте себе виртуальную таблицу как отображение из сигнатур методов (которые являются общедоступными) в указатели функций. Эта виртуальная таблица создается компилятором во время процесса компиляции и сохраняется в памяти во время выполнения программы. В нашем примере класс A и класс AA будут иметь свои собственные виртуальные таблицы. И когда компилятор должен найти someFunc () в классе AA (поскольку фактический объект, на который указывает переменная a, имеет тип AA), он просто найдет указатель на функцию через виртуальную таблицу класса AA. Это так же просто, как хэширование в таблице и операция с постоянным временем.
Привет
Avid