Почему С++ не требует форвардных объявлений для членов класса?
У меня создалось впечатление, что все, что должно быть в С++, должно быть объявлено до использования.
На самом деле, я помню, что я читал, что это причина, по которой использование типов auto
в возвращаемых типах недопустимо С++ 0x без чего-то вроде decltype
: компилятор должен знать объявленный тип до, оценивая тело функции.
Представьте мое удивление, когда я заметил (после долгого времени), что следующий код на самом деле совершенно легален:
[Изменить: Изменен пример.]
class Foo
{
Foo(int x = y);
static const int y = 5;
};
Итак, теперь я не понимаю:
Почему компилятор не требует прямого объявления внутри классов, когда он требует их в других местах?
Ответы
Ответ 1
В стандарте говорится (раздел 3.3.7):
Потенциальная область имени, объявленного в классе, состоит не только из декларативного региона, следующего за точкой имен декларации, но также и из всех тел функций, элементов или нестационарных элементов несимметричных данных и по умолчанию аргументы в этом классе (включая такие вещи в вложенных классах).
Это, вероятно, достигается за счет задержки обрабатывающих тел встроенных функций-членов до тех пор, пока не будет проведен анализ всего определения класса.
Ответ 2
Определения функций внутри тела класса обрабатываются так, как если бы они были фактически определены после определения класса. Таким образом, ваш код эквивалентен:
class Foo
{
Foo();
int x, *p;
};
inline Foo::Foo() { p = &x; }
Ответ 3
На самом деле, я думаю, вам нужно обратить вспять вопрос, чтобы понять его.
Почему С++ требует прямого объявления?
Из-за того, как работает С++ (включая файлы, а не модули), в противном случае нужно было бы дождаться всей единицы перевода, прежде чем вы сможете точно оценить, что это за функции. Здесь есть несколько недостатков:
- время компиляции займет еще один хит
- было бы почти невозможно предоставить какую-либо гарантию для кода в заголовках, так как любое введение более поздней функции могло бы аннулировать все это.
Почему класс отличается?
Класс по определению содержится. Это небольшая единица (или должна быть...). Поэтому:
- существует небольшая проблема времени компиляции, вы можете дождаться окончания класса, чтобы начать анализ
- нет никакого риска зависимого ада, поскольку все зависимости четко идентифицированы и изолированы.
Поэтому мы можем отбросить это раздражающее правило декларации forward для классов.
Ответ 4
Просто гадание: компилятор сохраняет тело функции и фактически не обрабатывает его до тех пор, пока объявление класса не будет завершено.
Ответ 5
в отличие от пространства имен, область видимости класса не может быть повторно открыта. он связан.
Представьте себе реализацию класса в заголовке, если все должно быть объявлено заранее. я предполагаю, что, поскольку он связан, логичнее было записать язык как есть, вместо того, чтобы требовать, чтобы пользователь писал вперед в классе (или требуя определений отдельно от объявлений).