Доминирование (C ++)

редактировать

В язык программирования C ++, доминирование относится к конкретному аспекту C ++ поиск имени при наличии наследования. Когда компилятор вычисляет набор объявлений, на которые может ссылаться конкретное имя, объявления в очень предковых классах, в которых «преобладают» объявления менее предковых классов, скрываются для целей поиска имени. В других языках или контекстах тот же принцип может упоминаться как «маскировка имени » или «затенение ».

Алгоритм вычисления поиска имени описан в разделе 10.2 [class.member.lookup] стандарта C ++ 11. Описание Стандарта не использует слово «доминирование», предпочитая описывать вещи в терминах наборов деклараций и сокрытия. Однако Индекс содержит запись «доминирование, виртуальный базовый класс» со ссылкой на раздел 10.2.

Содержание
  • 1 Пример без алмазного наследования
  • 2 Пример с алмазным наследованием
  • 3 Пример с виртуальным наследованием
  • 4 См. Также
  • 5 Ссылки
Пример без алмазного наследования
void ф (двойной, двойной); // в глобальной области видимости struct Grandparent {void f (int); void f (двойной, двойной); }; struct Parent: public Grandparent {void f (int); // скрывает все перегрузки Grandparent :: f}; struct Child: public Parent {void g () {f (2.14, 3.17); } // преобразуется в Parent :: f};

В приведенном выше примере Child :: gсодержит ссылку на имя f. Однако программа в целом содержит четыре объявления с именем f. Чтобы выяснить, какой fимеется в виду, компилятор вычисляет набор перегрузки, содержащий все объявления, которые не скрыты в точке вызова. Объявление fв глобальной области видимости скрыто Grandparent :: f, и, в свою очередь, Grandparent :: fскрыто Parent :: f. Таким образом, единственным объявлением, которое учитывается при разрешении перегрузки, является Parent :: f- и результатом в этом случае является диагностика, потому что сайт вызова предоставляет два аргумента, где Parent :: fОжидает только одного.

Новички в программировании на C ++ часто удивляются, что объявление Parent :: fдоминирует и скрывает все более древние объявления, независимо от подписи; то есть Parent :: f (int)доминирует и скрывает объявление Grandparent :: f (double, double), даже если две функции-члены имеют очень разные сигнатуры.

Также важно отметить, что в C ++ поиск имени предшествует разрешению перегрузки . Если Parent :: fимеет несколько перегрузок (например, f (int)и f (double, double)), компилятор будет выбирать между ними при перегрузке -время разрешения; но на этапе поиска по имени нас интересует только выбор из трех областей: Grandparent :: f, Parent :: fи :: f. Тот факт, что Grandparent :: f (double, double)был бы лучшей перегрузкой, чем f (int), не является частью рассмотрения компилятора.

Пример с наследованием ромба
struct Grandparent {void f (int); void f (двойной, двойной); }; Структура Мать: публичный дедушка {недействительность f (int); // скрывает все перегрузки Mother :: Grandparent :: f}; struct Отец: public Grandparent {}; struct Child: public Мать, Отец {// Мать :: Бабушка и дедушка - это не тот же подобъект, что и Отец :: Бабушка и дедушка void g () {f (2.14, 3.17); } // двусмысленность между Mother :: f и Father :: Grandparent :: f};

В приведенном выше примере компилятор вычисляет набор перегрузки для f, который содержит как Mother :: f, так и Father :: Grandparent :: f. Компилятор выдает диагностическое сообщение, указывающее на то, что программа имеет неправильный формат, поскольку имя fнеоднозначно.

Пример с виртуальным наследованием
struct Grandparent {void f (int); void f (двойной, двойной); }; struct Mother: публичный виртуальный дедушка {void f (int); // скрывает все перегрузки Mother :: Grandparent :: f}; struct Отец: общедоступный виртуальный дедушка {}; struct Child: public Mother, Father {// Mother :: Grandparent - это тот же подобъект, что и Father :: Grandparent void g () {f (2.14, 3.17); } // преобразуется в Mother :: f};

В этом последнем примере имя fеще раз однозначно относится к Mother :: f, потому что Mother :: fскрывает fобъявлен в его подобъекте Grandparent. Стандарт вызывает этот удивительный случай в информативном примечании (§10.2, абзац 10):

Когда используются виртуальные базовые классы, скрытое объявление может быть достигнуто по пути через решетка подобъектов, которая не проходит через объявление сокрытия. Это не двусмысленность.

Даже если бы сам Дочернийфактически унаследовал от дедушки и бабушки, не было бы двусмысленности при поиске имени. Однако, если Дочернийдолжен наследовать не виртуально от Дедушка и бабушка(т. Е. struct Child: public Mother, Father, Grandparent), тогда имя снова будет неоднозначно (между f, объявленными в двух подобъектах Grandparent).

См. Также
Ссылки
  1. ^ Рабочий проект N3797, стандарт для языка программирования C ++. Датировано 13.10.2013.
Последняя правка сделана 2021-05-17 11:43:40
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте