Обновить

Комментарии 6

вроде читаешь про простой поиск имён, а по факту там вообще ничего простого. Особенно момент, где одна переменная может спокойно «перекрыть» кучу всего и ты потом сидишь и думаешь, почему код ведёт себя странно. Про наследование вообще боль, когда одна функция в Derived внезапно прячет все перегрузки из Base. Вроде мелочь, а на практике легко словить баг и долго его искать. Хорошо разложено, стало понятнее, почему иногда компилятор чудит, хотя он на самом деле просто следует правилам.

Даже если компилятор разрешает это:

namespace N {
    int value = 10;
}

int main() {
    int N = 5;
    std::cout << N << "\n";
    std::cout << N::value << "\n";
    return 0;
}

Это всё равно ужасно

Это пример, он очень простой и очень явный. Так бывает в 0.00001% багов. Но покопайтесь в кодовой базе проекта старше хотя бы пяти лет и там такого неявного добра навалом с горочкой, просто оно более менее оперативно правится. А если не правится, да фиг с ним, не мешает же.

Это можно проанализировать и попытаться вылечить Perl/Python-ом. Достаточно откомпилировать gcc -fdump-ipa-all -fdump-tree-gimple main.cpp
будет что то вроде a-main.cpp.007t.gimple

int main ()
{
  int D.53373;

  {
    int N;

    N = 5;
    _1 = std::basic_ostream<char>::operator<< (&cout, N);
    std::operator<< <std::char_traits<char> > (_1, "\n");
    value.0_2 = value;
    _3 = std::basic_ostream<char>::operator<< (&cout, value.0_2);
    std::operator<< <std::char_traits<char> > (_3, "\n");
    D.53373 = 0;
    return D.53373;
  }
  D.53373 = 0;
  return D.53373;
}

Далее можно уже провести предметный разбор безотносительно к именам. Резольвинг имён - это костыль тянущийся ещё с момента создания первых языков программирования, когда редактируется не программа а текст её представляющий. Поэтому необходима статическая проверка на вот такие вот коллизии, наверняка есть инструменты на этот счёт по анализу непосредственно результатов кодогенерации.

На первый взгляд кажется, что никакой проблемы быть не должно. В конечном итоге член x объявлен только в A, и никакого второго x в B или C нет.

Но у вас же не virtual-наследование, так что у нас две копии A::x, и нужно знать, к какой обращаемся. В случае virtual-наследования найдётся без дополнительных фокусов.

Update: увидел, что ниже virtual-наследование тоже описано.

  • A, как прямой базовый класс C

  • A, как базовый класс B, который сам является базовым классом A

Во втором случае B не является базовым классом A, а A ровно такой же прямой базовый класс, только для B

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации