«Неполный тип» в классе, который имеет член того же типа самого класса - PullRequest
36 голосов
/ 15 июня 2011

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

class A {
    private:
        A member;
}

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

Ответы [ 8 ]

40 голосов
/ 15 июня 2011

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

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

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

class Foo;

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

Foo* foo;

Но не:

Foo foo;

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

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

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

class A
{
  private:
    boost::shared_ptr<A> member;
};
25 голосов
/ 15 июня 2011

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

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

A a;

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

5 голосов
/ 15 июня 2011

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

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

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

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

2 голосов
/ 15 июня 2011

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

1 голос
/ 15 июня 2011

Этот тип ошибки возникает, когда вы пытаетесь использовать класс, который еще не был полностью определен.

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

1 голос
/ 15 июня 2011

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

Может содержать указатель на А., если хотите.

0 голосов
/ 31 августа 2016

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

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

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

0 голосов
/ 10 февраля 2015

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

...