Проблема с объявлением объектов в C ++ - PullRequest
2 голосов
/ 18 марта 2011

У меня есть простой код ниже:

class B;
class A{
    B b;
};

class B{
public:
    B(){

    }
};

В определении класса A у меня есть свойство типа B. Используя MS Visual Studio для компиляции, я получил следующую ошибку:

error C2079: 'A::b' uses undefined class 'B'

По некоторым причинам я не могу поставить определение класса B перед определением класса A. Есть идеи?

Ответы [ 4 ]

12 голосов
/ 18 марта 2011

Компилятор уже говорит вам, что не так: A имеет данные-члены b неопределенного типа.Ваша предварительная декларация:

class B;

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

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

class B{
public:
    B(){

    }
};

class A{
    B b;
};

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

Дальнейшее редактирование : альтернативой может быть изменение данных вашего члена на указатель или ссылку.Обратите внимание, что это не тривиальное изменение синтаксиса: оно влияет на жизненный цикл ваших объектов, поскольку объект, на который указывает A :: b, может затем пережить разрушение A.

Если вы хотитеявляется композиция (B является частью A и умирает с A), использование указателя сделает вашу жизнь сложнее с небольшими преимуществами.

Больше правок (!) : только что понял, что я неправильно прочиталконец вашего вопроса;По каким причинам вы не можете объявить B перед A?

Если их невозможно обойти, возможно, вам придется пойти по указателю.Эти причины могут быть признаком того, что ваши объекты слишком тесно связаны!(возможно, B должен быть внутренним классом A? Или просто быть объединенным в один объект?)

1 голос
/ 18 марта 2011

C ++ имеет понятие «неполный» класс, и это то, что вам нужно знать.

Использование неполного класса позволяет вам во многих ситуациях использовать класс, просто зная, что он один, не зная, что в нем.

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

Вам нужен полный класс, чтобы:

  • Имейте экземпляр одного.
  • Получите из него
  • Вызовите любой метод для него.
  • удалить указатель на него.

Вам нужен только неполный класс, чтобы:

  • Удерживать указатель или ссылку на него.
  • Передать указатель или ссылку на функцию, которая принимает указатель или ссылку. (Это может быть функция, которая удаляет указатель, если он полностью определен в этой точке).

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

1 голос
/ 18 марта 2011

Вы можете делать все, что пожелаете, если изменить ссылку на b на указатель на B.

class A{
    B* bPtr;
};

class B{
public:
    B(){

    }
};

В принципе, вам не нужно явное объявление - то есть предварительное объявление - это все, что нужно - когда вам не нужен фактический размер класса или доступ к типам и функциям-членам внутри класса.

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

Имея объявление класса A, использующее указатель на B, выможно обойтись без предварительной декларации.

edit

Некоторые ссылки могут объяснить концепцию для вас:

http://www.goingware.com/tips/parameters/notrequired.html

http://www -subatech.in2p3.fr / ~ фотоны / subatech / soft / carnac / CPP-INC-1.shtml

http://www.codeguru.com/forum/showthread.php?t=358333 (см. Сообщение № 2)

http://en.wikipedia.org/wiki/Forward_declaration

1 голос
/ 18 марта 2011
class A;

class B {
  A * getA();
};

class A {
  B b;
};

Это типичный способ решить эту проблему.Вы должны иметь определение B, чтобы иметь B b; члена.

Вам нужно предварительное объявление для объявления ссылки / указателя на B, вам нужно полное определение, чтобы делать что-то еще с B (например, определение переменной, вызов функции-члена и т. Д.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...