Компилятор корректен, чтобы не диагностировать проблемы с вашим кодом.Код, как вы его создали, не является двусмысленным.По сути, имя является неоднозначным, если оно одинаково хорошо соответствует более чем одной переменной (или члену класса в вашем случае).
При оценке e->I
первым найденным кандидатом является I
, то естьчлен (через наследование) класса SW2
.Члены I
, которые SW2
наследуют от его базовых классов, не так хорошо соответствуют, как члены, определенные непосредственно Sw2
.
Аналогично, pc1->I
однозначно является членом SW1
, d->I
- то же самое, а pc2->I
- однозначно членом базового класса SW2
.
Неоднозначностьпроизойдет при оценке e->I
, если SW2
не имеет своего собственного члена с именем I
(то есть struct SW2: HW, Other {};
(. В этом случае при оценке e->I
разрешение имени ищет в SW2
члена с именемI
и не находит его. При разрешении имени учитываются два базовых класса HW
и Other
, каждый из которых имеет член с именем I
. Они одинаково хорошо совпадают, поэтому выражение e->I
является неоднозначным - и компилятор выдаст диагностику, то есть ошибку (не просто предупреждение). В этом случае программист может явно устранить неоднозначность, используя оператор области действия (::
). Например, e->HW::I
или e->Other::I
, которая полностью определяет имя.
Вы правы, что такое многократное использование имени в иерархии классов является плохой идеей. И то и другое, потому что может быть трудно правильно разрешитьнеясность таким образом, который имеет смысл для компилятора, и потому что простые смертные часто будут испытывать затруднения при следовании логике.