Я наткнулся на следующий код в статья
struct entire_program
{
struct B;
struct A
{
B *bbb;
void Aa() { B bb; bb.Bb(); };
};
struct B
{
A aaa;
void Bb() { A aa; aa.Aa(); };
};
};
Почему мне разрешено вызывать метод Bb()
в этом случае, но если я изменю struct entire_program
в namespace entire_program
это генерирует ошибку компилятора?
Я уже читаю этот вопрос, то, что я спрашиваю: возможно ли вызывать методы, которые еще не определены в классах / структурах / объединениях почему пространства имен не работают одинаково? Меня интересует мотивация такого поведения.
Похожий вопрос на Programmers.SE (для тех, кто интересуется стилем кодирования, представленным в статье)
Именно так классы и пространства имен работают в C ++. Классы иметь выдвигать в качестве кандидатов полный набор имен (членов класса), потому что в противном случае вы бы возложили огромную нагрузку на упорядочение членов вашего класса и, например, не могли бы сначала удобно заказать ваш общедоступный интерфейс.
Пространства имен, с другой стороны, работают почти так же, как функции C, и обрабатываются последовательно в порядке, указанном в исходном файле. Специальные функции не нужны, так как вы всегда можете объявить свою функцию перед вызовом в пространстве имен / глобальной области видимости.
Круговая зависимость возможна как внутри классов, так и в пространствах имен. Это просто вопрос правильного определения вещей в ситуациях круговой зависимости.
В вашем случае код скомпилирован с struct entire_program
из-за особой обработки определений функций-членов в классе: им разрешено «видеть» все определения включающего класса (классов) как выше, так и ниже текущей точки. Но они не могут видеть полное определение окружающего пространства имен. С пространствами имен компилятор видит только то, что было объявлено выше текущей точки.
Классы и пространства имен — это совершенно разные вещи, поэтому проблема свободного переключения между ними обычно не возникает на практике. Но только в иллюстративных целях это может быть достигнуто во многих случаях, включая ваш искусственный пример.
namespace entire_program
{
struct B;
struct A
{
B *bbb;
void Aa();
};
struct B
{
A aaa;
void Bb() { A aa; aa.Aa(); }
};
}
inline void entire_program::A::Aa()
{
B bb; bb.Bb();
}
Моя реализация выше имеет тот же эффект, что и ваша, но она не зависит от особого подхода к функциям-членам. Вы можете свободно переключаться между struct entire_program
а также namespace entire_program
, если вы так желаете. Просто помните, что определение пространства имен не имеет ;
после закрытия }
,