Подтвердить что ты не робот

"Неполный тип" в классе, который имеет один и тот же тип самого класса

У меня есть класс, который должен иметь частный член того же класса, что-то вроде:

class A {
    private:
        A member;
}

Но это говорит мне, что член является неполным типом. Зачем? Это не говорит мне неполный тип, если я использую указатель, но лучше не использовать указатель. Любая помощь приветствуется

4b9b3361

Ответ 1

В то время, когда вы объявляете своего участника, вы по-прежнему определяете класс A, поэтому тип A по-прежнему undefined.

Однако, когда вы пишете A*, компилятор уже знает, что A означает имя класса, поэтому тип "указатель на A" определен. Вот почему вы можете вставить указатель на тип, который вы определяете.

Такая же логика применяется и для других типов, поэтому, если вы просто пишете:

class Foo;

Вы объявляете класс Foo, но вы его никогда не определяете. Вы можете написать:

Foo* foo;

Но не:

Foo foo;

С другой стороны, какую структуру памяти вы ожидаете для своего типа A, если компилятор разрешил рекурсивное определение?

Однако его иногда логически справедливо, чтобы иметь тип, который каким-то образом ссылается на другой экземпляр того же типа. Обычно люди используют указатели для этого или даже лучше: умные указатели (например, boost::shared_ptr), чтобы избежать необходимости ручного удаления.

Что-то вроде:

class A
{
  private:
    boost::shared_ptr<A> member;
};

Ответ 2

Это рабочий пример того, чего вы пытаетесь достичь:

class A {
public:
    A() : a(new A()) {}
    ~A() { delete a; a = nullptr; }
private:
    A* a;
};

A a;

Счастливое переполнение стека!

Ответ 3

A является "неполным" до конца его определения (хотя это не включает тела функций-членов).

Одна из причин этого заключается в том, что до тех пор, пока не закончится определение, нет способа узнать, насколько велика A (которая зависит от суммы размеров членов и нескольких других вещей). Ваш код - отличный пример: ваш тип A определяется размером типа A.

Очевидно, что объект типа A может не содержать объект-член, который также имеет тип A.

Вам нужно будет сохранить указатель или ссылку; желая сохранить либо, возможно, подозревается.

Ответ 4

Вы не можете включить A в A. Если вы смогли это сделать, и вы заявили, например, A a;, вам нужно будет бесконечно ссылаться на a.member.member.member.... Вы не имеете столько оперативной памяти.

Ответ 5

Как экземпляр class A также содержит другой экземпляр class A?

Он может содержать указатель на A, если вы хотите.

Ответ 6

Этот тип ошибки возникает, если вы пытаетесь использовать класс, который еще не был полностью ОПРЕДЕЛЕН.

Попробуйте вместо этого использовать A* member.

Ответ 7

Проблема возникает, когда компилятор сталкивается с объектом A в коде. Компилятор протирает руку и задает объект A. При этом он увидит, что A имеет член, который снова имеет тип A. Поэтому для завершения создания A теперь нужно создать экземпляр другого A, а в делая это, он должен создать экземпляр другого А и т.д. Вы можете видеть, что это закончится рекурсией без ограничений. Следовательно, это не допускается. Компилятор гарантирует, что он знает все типы и требования к памяти всех членов, прежде чем он начнет создавать экземпляр объекта класса.

Ответ 8

Простым способом понять причину отсутствия класса A является попытка взглянуть на него с точки зрения компилятора.

Кроме всего прочего, компилятор должен иметь возможность вычислить размер объекта A. Знание размера - это очень основное требование, которое проявляется во многих контекстах, таких как выделение пространства в автоматической памяти, вызов оператора new и оценка sizeof(A). Однако для вычисления размера A требуется знание размера A, потому что A является членом A. Это приводит к бесконечной рекурсии.

Способ компилятора справиться с этой проблемой состоит в том, чтобы считать A неполным, пока его определение не будет полностью известно. Вам разрешено объявлять указатели и ссылки на неполный класс, но вы не можете объявлять значения.