2016-12-06 2 views
0

Utilities.hПочему я страдаю Циркулярной зависимостью здесь?

#ifndef _UTILITIES_ 
#define _UTILITIES_ 

#include "MyFirstCairoPlugin.h" 

class PLUG_CLASS_NAME; 

class Utilities 
{ 
private: 
    PLUG_CLASS_NAME *pPlug; 

public: 
    Utilities(PLUG_CLASS_NAME *plug); 
    ~Utilities(); 
}; 

#endif // !_UTILITIES_ 

Utilities.cpp

#include "Utilities.h" 

Utilities::Utilities(PLUG_CLASS_NAME *plug) : pPlug(plug) { 
    IColor color = IColor(100, 100, 100, 255); 
} 
Utilities::~Utilities() { 

} 

И здесь я имею проблемы, используя этот Classe из MyFirstCairoPlugin.h:

#ifndef _MYFIRSTCAIROPLUGIN_ 
#define _MYFIRSTCAIROPLUGIN_ 

#include "IPlug_include_in_plug_hdr.h" 
#include "resource.h" 

#include "Utilities.h" 

//class Utilities; 

class MyFirstCairoPlugin : public IPlug 
{ 
private: 

public: 
    Utilities *pUtilities; 

    MyFirstCairoPlugin(IPlugInstanceInfo instanceInfo); 
    ~MyFirstCairoPlugin(); 
}; 

#endif // !_MYFIRSTCAIROPLUGIN_ 

Если я не де -комментарий //class Utilities; (форвардная декларация), он не может использовать Утилиты (даже если я включил его выше, с #include "Utilities.h"). Это дает мне «типичную» ошибку круговой зависимости `:

syntax error: missing ';' before '*' (compiling source file ..\..\..\IPlug_AddOns\Utilities.cpp) 

Где я ошибаюсь?

+1

Почему 'utilities.h' нужно' #include 'MyFirstCairoPlugin.h? '? –

+0

Поскольку 'PLUG_CLASS_NAME' является макросом и« определяет »имя класса' MyFirstCairoPlugin', который находится внутри 'MyFirstCairoPlugin.h' – markzzz

+0

' MyFirstCairoPlugin.h', не нужно включать 'utilities.h', если вы отправляете объявление' Утилиты ' '. – Arunmu

ответ

1

Utilities.h включает MyFirstCairoPlugin.h, MyFirstCairoPlugin.h включает Utilities.h, который представляет собой круг, логически приводящий к зависимости круга.

Вот что вы должны сделать вместо этого:

Если класс нужен другой класс прямо в объявлении, или если это явно самая существенная часть его, включите его. Пример: класс «Изображение» может включать класс «Цвет» Если класс несколько использует другой класс, например, сохраняя его в указателе или используя его в вызове какого-либо метода, используйте форвардное объявление. Если это вообще не нужно для другого класса, значит, он тоже этого не делает. Для второго случая файл реализации будет включать в себя зависимый класс.

В вашем случае MyFirstCairoPlugin хранит указатель на Utilities, поэтому он должен сделать прямое объявление Utilities, но не включать его. Кстати, этот указатель не должен быть общедоступным.

Вот как это должно выглядеть следующим образом:

#ifndef _MYFIRSTCAIROPLUGIN_ 
#define _MYFIRSTCAIROPLUGIN_ 

#include "IPlug_include_in_plug_hdr.h" //<--- no idea what that is about 
#include "resource.h" 

class Utilities; 

class MyFirstCairoPlugin : public IPlug 
{ 
private: 

public: 
    Utilities* pUtilities; //<-- shouldn't be public, you should always use encapsulation 
... 

Utilities с другой стороны, даже не использовать MyFirstCairoPlugin, поэтому у нас есть третий случай здесь. Почему вы включили MyFirstCairoPlugin в первую очередь? Если этот макрос может быть MyFirstCairoPlugin, тогда нет проблем, он уже имеет декларацию вперед. Однако не делал бы этого над макросом. Скорее используйте утилиты, являющиеся классом шаблонов. Кстати, «Утилиты» - довольно широкое название, похоже, что это может легко привести к конфликтам имен.

может выглядеть следующим образом:

#ifndef _UTILITIES_ 
#define _UTILITIES_ 

template<class T> 
class Utilities 
{ 
private: 
    T* pPlug; 

public: 
    Utilities(T* plug); 
... 

редактировать: кажется, вы, кажется, недовольны шаблонами, вот еще одна возможность:

Создать абстрактный класс (/ интерфейс), из которых MyFirstCairoPlugin будет подкласс, предоставляющий все методы, необходимые для реализации Утилитов. Скажем, это называется «Плагин». Кажется, у вас уже есть такой класс, но, поскольку я понятия не имею, что такое IPlug, я перехожу с другим именем.

Утилиты для сборки вокруг плагина вместо MyFirstCairoPlugin или PLUG_CLASS_NAME. Затем просто подайте ему экземпляр MyFirstCairoPlugin, который затем является допустимым экземпляром плагина. Пока методы Plugin являются абстрактными и виртуальными, вызывающие методы указателя на плагин будут вызывать методы MyFirstCairoPlugin, и все будут счастливы.

+0

Я включаю 'MyFirstCairoPlugin' внутри Утилиты, потому что PLUG_CLASS_NAME это макрос, который «определяет» имя класса MyFirstCairoPlugin, который находится внутри MyFirstCairoPlugin.h. – markzzz

+0

@paizza Это звучит как действительно странная конструкция зависимостей. Не делай этого. Если бы я видел ваши классы, не зная, я понятия не имел, где вы определили этот макрос. Никогда бы не догадался, что класс, который его использует, делает это. Неоправданно увеличивает сцепление. Сделано редактирование моего сообщения, используйте шаблонное решение. – Aziuth

+0

Я попробую, но у меня есть проблемы с разбивкой .h и .cpp с шаблоном http://stackoverflow.com/questions/40993286/whats-wrong-with-this-use-of-template – markzzz

0

Посмотрите, как он включен шаг за шагом:

  • в Utilities.cpp, вы включаете Utilities.h
  • теперь вы #define _UTILITIES_
  • тогда вы включаете в там MyFirstCairoPlugin.h
  • включить Utilities.h снова
    • но из-за #ifndef _UTILITIES_, определение класса не включено - _UTILITIES_ уже определен (см. Второй шаг)!

Так class Utilities еще не определен, и вам необходимо опережающее объявление.

Смежные вопросы