Исправление круговой зависимости - PullRequest
1 голос
/ 11 февраля 2012

Я уверен, что это какой-то недостаток дизайна с моей стороны, главным образом потому, что я пришел из Java. Но это то, что есть.

Вот общие настройки:

У меня есть класс, скажем A с #include "B.h"

#include "B.h"

class A {

    // stuff
private:
    B _b;

}

Дополнительно у меня есть класс B с #include "C.h"

#include "C.h"

class B {

    // more stuff

private:
    C::EnumType _cEnum;
}

И, наконец, у меня есть класс C с #include "A.h"

#include "A.h"

class C {
public:
    C(A a);
    enum EnumType {
        // enum stuff
    };

    // more stuff

}

Как я могу это исправить? Я пробовал некоторые дела с предварительными декларациями, но, похоже, это не сработало, хотя я не утверждаю, что сделал это правильно. Пространства имен возможно?

Ответы [ 3 ]

3 голосов
/ 11 февраля 2012

В C вам не нужно включать A. Только два других заголовка нуждаются в директивах include, которые вы там поместили.

class A;

class C {
public:
    C(A a);
    enum EnumType {
        // enum stuff
    };

    // more stuff
};

Поместите определение C::C в файл .cpp, в который затем можно включить A.h. Только определение C::C нуждается в типе параметра, чтобы иметь определение.

2 голосов
/ 11 февраля 2012

Я пытался поработать с предварительными декларациями, но, похоже, это не сработало

Вы не показали нам, что "не работает", или вкаким образом это «не сработало», но в вашем коде есть одно место, где вы можете заменить полное определение типа на прямое объявление, а два - там, где вы не можете.

Где вы не можете

Нестатические члены данных должны быть полных типов:

[C++11: 9.2/10]: Не static (9.4) члены данных не должны иметьнеполные типы.В частности, класс C не должен содержать нестатического члена класса C, но он может содержать указатель или ссылку на объект класса C.

Итак,B in A и C::EnumType in B не могут быть объявлены вперед.

BTW: Это не относится к static элементам данных, которые может быть объявленным вперед:

[C++11: 9.4.2/2]: Объявление члена данных static в его определении класса не является определением и может иметь неполный тип, отличный от cv-уточнено void.

Где вы можете

Однако то же самое не относится к типам параметров в объявлении функции-члена, поэтому вы можете заранее объявить A в C(A a):

class A;

class C {
public:
    C(A a);
    enum EnumType {
        // enum stuff
    };

    // more stuff
};

#include как можно меньше в заголовках.

Почему вам не нужно

IЯ уверен, что это какой-то недостаток дизайна с моей стороны, главным образом потому, что я пришел из Java-фона

Я не вижу, что в Java есть что-тоЭто связано с тем, что все эти классы зависят друг от друга.Возможно C::EnumType должно быть вместо B::EnumType?Постарайтесь сделать ваши занятия более самостоятельными.Предварительные декларации все хорошо, но жизнь была бы намного проще, если бы вы решили коренную проблему тесной связи вашего дизайна.

0 голосов
/ 11 февраля 2012

@ Lightness говорит об этом - вам не нужно включать ah в модуль компиляции C, если вы объявляете класс A, используя определение «forward».Просто поставьте «класс А»;в заголовок, который говорит компилятору (и компоновщику) выяснить, что такое A в более позднее время.Единственным недостатком этого является то, что файл C больше не знает, что находится внутри A, поэтому вы должны использовать ссылки или указатели.

Альтернативой является просто разделение C на 2 части.Есть ли причина, по которой enum встроен в него, а не является частью B?Если C и B разделяют определения перечисления, то его следует разделить на отдельный класс или просто перечислить перечисление верхнего уровня.

Когда я получаю подобные циклические определения, я дважды проверяю, что эточто я делаю.Я всегда нахожу, что я сделал вещи слишком сложными для себя.

...