C ++ Почему циклическая зависимость возможна внутри класса, но не пространства имен или глобальной области видимости?

Я наткнулся на следующий код в статья

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 (для тех, кто интересуется стилем кодирования, представленным в статье)

2

Решение

Именно так классы и пространства имен работают в C ++. Классы иметь выдвигать в качестве кандидатов полный набор имен (членов класса), потому что в противном случае вы бы возложили огромную нагрузку на упорядочение членов вашего класса и, например, не могли бы сначала удобно заказать ваш общедоступный интерфейс.

Пространства имен, с другой стороны, работают почти так же, как функции C, и обрабатываются последовательно в порядке, указанном в исходном файле. Специальные функции не нужны, так как вы всегда можете объявить свою функцию перед вызовом в пространстве имен / глобальной области видимости.

2

Другие решения

Круговая зависимость возможна как внутри классов, так и в пространствах имен. Это просто вопрос правильного определения вещей в ситуациях круговой зависимости.

В вашем случае код скомпилирован с 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, если вы так желаете. Просто помните, что определение пространства имен не имеет ; после закрытия },

1

По вопросам рекламы [email protected]