Понимание «проблемы взаимной рекурсии»; для возвращаемого типа функций

Я знаю проблему рекурсивного определения типов в C ++ для переменных-членов:

#include "B.h"class A
{
B b;
};

#include "A.h"class B
{
A b;
};

Компилятор жалуется на это, потому что невозможно выделить память таким рекурсивным способом.

Чего я не понимаю, так это того, что это применимо и к определениям функций:

#include "B.h"class A
{
B foo();
};

#include "A.h"class B
{
A bar();
};

Компиляторы выдают ту же ошибку:

error: ‘A’ does not name a type
error: ‘B’ does not name a type

Это почему? Мне не имеет смысла, что компилятор должен зарезервировать место для возвращаемого типа. Должен ли я решить эту проблему с помощью указателей и предварительной декларации? По моему опыту (исходя из Java), довольно часто программисты делают эти рекурсивные определения для разработки программного обеспечения. Кажется, это так сложно реализовать в C ++.

-2

Решение

Что касается определения функций, все, что вам нужно, это соответствующее предварительное объявление:

class A;
class B;

class A
{
B foo();
};

class B
{
A bar();
};

Это будет компилироваться без проблем. Не стесняйтесь разделить это на два отдельных заголовочных файла с соответствующим предварительным объявлением вместо #include,

Обратите внимание, что причина, по которой вы не можете объявлять членов класса таким же образом, заключается в том, что это будет эффективно содержать класс в себе. К сожалению, если бы это было возможно, конечным результатом была бы массивная черная дыра, которая поглотит всю жизнь, какой мы ее знаем, и мы, конечно, не хотим, чтобы это произошло …

В любом случае, другой момент, о котором вам нужно помнить, это то, что вы находитесь под влиянием вашего фона Java. Классы работают в C ++ принципиально иначе, чем в Java, несмотря на обманчиво похожий синтаксис. Вам лучше забыть все, что вы знаете о том, как работают классы в Java. Иначе ты будешь сбиваться с пути, вот так. В Java подобный набор объявлений не приводит к тому, что класс эффективно содержит себя, но в C ++ это делает. Это потому, что в Java каждый экземпляр класса действительно является указателем на класс, но в C ++ это сам класс, во плоти и крови.

В C ++ реальным эквивалентом этого вида рекурсивного объявления класса будет:

class A
{
std::shared_ptr<B> b;
};

class B
{
std::shared_ptr<B> A;
};

(игнорируя на данный момент необходимые предварительные декларации, которые применимы и здесь).

И это будет работать в C ++ так же хорошо, как и в Java ( std::shared_ptr<> part является эквивалентом подсчета ссылок на объекты Java, в некотором роде). это это то, что эквивалентно вашей аналогичной конструкции в Java.

2

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

Тебе необходимо предварительная декларация:

class B;    // forward declaration

class A
{
B foo();
};

class B
{
A bar();
};

Объявление выше говорит компилятору, что class B существует, но не то, на что это похоже. Этого достаточно, чтобы использовать его в качестве параметра или возвращаемого типа функции или метода. Затем вы можете уточнить фактическое определение.

2

Что я не понимаю, так это то, что это похоже на функцию
определения также:

Функции могут быть встроены компилятором, и единственный способ сделать это, когда вы знаете точную структуру возвращаемого типа. И кроме того, компилятор должен знать, как создать тип возвращаемого значения функции


Примечание. Компилятору не нужно знать полное определение возвращаемого типа объявления функции, однако он должен знать об этом при определении.

//file A.h
class B;  //forward declaration

class A
{
B foo();   //declaration
};

//file A.cpp
#include "B.h"
B A::foo(){ ....  }  //definition

//file B.h
class A; //forward declaration
class B
{
A bar();  //declaration, works
A moo() { .... } //Declaration + Definition, Fails to see full definition of `A`
};

//file B.cpp
#include "A.h"
A B::boo() { ... }
1
По вопросам рекламы [email protected]