2014-02-11 4 views
0

У меня есть два класса с отдельными заголовками: class Renderer и class Texture. Экземпляр Texture предназначен для управления некоторыми данными, которые находятся в пуле памяти Renderer, и поэтому экземпляр Texture не может существовать независимо от экземпляра Renderer. Чтобы получить дескриптор экземпляра Texture, вы просто вызываете Renderer::loadTexture с правильным именем файла, а Renderer ищет свою базу данных для Texture объектов с соответствующим именем файла и создает новую текстуру, если совпадений не найдено.Циклическая зависимость класса delclarations

//renderer.h 
#include "texture.h" 
class renderer 
{ 
public: 
    Texture* loadTexture(std::string fileName); 
private: 
    std::map<std::string, Texture*> textureDb; 
}; 

//texture.h 
class Texture 
{ 
public: 
    Texture(std::string imageFileName); 
}; 

Мне пришло в голову, что было бы логично, чтобы конструкторы class Texture частного и объявить Texture * Renderer::loadTexture(std::string filename) как друга class Renderer:

//renderer.h 
#include "texture.h" 
class renderer 
{ 
public: 
    Texture* loadTexture(std::string fileName); 
private: 
    std::map<std::string, Texture*> textureDb; 
}; 

//texture.h 
class texture; 
#include "renderer.h" 
class Texture 
{ 
private: 
    Texture(std::string imageFileName); 
    Texture(const Texture &); 
    friend Texture* loadTexture(std::string); 
}; 

Однако это составляет только если texture.h является всегда включается до включения renderer.h, поскольку class Texture требует, чтобы class Renderer был уже определен. Какой был бы лучший способ предотвратить это? Включите защитные устройства в обоих файлах, но для краткости здесь опущены.

ответ

1

Прежде всего, исходя из приведенного выше кода, вперед-декларировать, где это возможно. Это должно немного помочь.

// Renderer.h 
class Texture; 

class Renderer { 
    ... 
}; 

// Renderer.cpp 
#include "Renderer.h" 
#include "Texture.h" 

... 

// Texture.h 
//class Renderer; // looks like this isn't needed 

class Texture { 
    ... 
}; 

// Texture.cpp 
#include "Renderer.h" 
#include "Texture.h" 

... 

С опережающего описания, вы должны иметь достаточно, чтобы объявить указатели на текстуры в заголовке класса Renderer. Похоже, это все, что вам нужно в этот момент; нажмите остальные для Renderer.cpp.

Дальше избегайте друзей; однако в этом случае это может быть приемлемым.

И, наконец, круговые зависимости никогда не бывают хорошими. Посмотрите, можете ли вы немного изменить свой дизайн. Посмотрите, можете ли вы ввести интерфейс или абстрактный базовый класс, чтобы нарушить круговую зависимость. Похоже, что Renderer не должен вообще зависеть от Texture.

Вместо этого следует переписывать Renderer зависеть от какой-то интерфейс ITexture, а затем пусть Texture реализовать ITexture:

class ITexture 
{ 
    // no data members 
    // no method bodies 
    // only pure virtual method declarations 
}; 

class Renderer 
{ 
public: 
    ITexture* loadTexture(std::string fileName); 
private: 
    std::map<std::string, ITexture*> textureDb; 
}; 

class Texture : public ITexture 
{ 
    ... 
}; 
+0

«Смотрите, если вы можете изменить дизайн немного.» Я принял это предложение буквально: теперь класс Texture зависит от класса Renderer, но не наоборот, и я написал систему управления ресурсами, которая автоматически обрабатывает все отношения собственности и загрузку данных. – jms

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