Multiple header files

Модератор: Модераторы разделов

Аватара пользователя
VoidExp
Сообщения: 208
Статус: Lead guitar adept
ОС: Ubuntu

Multiple header files

Сообщение VoidExp »

Привет всем! На днях столкнулся с одной проблемой программирования на С++... Вот ситуация:
допустим есть два класса, находящиеся соответственно в фалах headerone.h и headertwo.h, и у каждого объявлена переменная другого:

Код: Выделить всё

//headerone.h
#include "headertwo.h"

class MyClassOne
{
    public:
    void SomeFunction();
    private:
    MyClassTwo* objPtr;
};

Код: Выделить всё

//headertwo.h
#include "headerone.h"

class MyClassTwo
{
public:
    void AnotherFunction();
private:
    MyClassOne* objPtr;
};


Компилятор при подобной ситуации выдает ошибку. Как можно решить эту проблему?
Спасибо сказали:
Аватара пользователя
Uncle_Theodore
Сообщения: 3339
ОС: Slackware 12.2, ArchLinux 64

Re: Multiple header files

Сообщение Uncle_Theodore »

Ну, самое простое, сделай базисный класс MyBasicClass
и наследуй MyClassOne и MyClassTwo из него. Потом делай приватные указатели на базисный класс. Типа вот так

class MyClassOne : public MyBasicClass
{
public:
void SomeFunction();
private:
MyBasicClass* objPtr;
}
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Multiple header files

Сообщение v04bvs »

VoidExp писал(а):
13.10.2007 18:54
Привет всем! На днях столкнулся с одной проблемой программирования на С++... Вот ситуация:
допустим есть два класса, находящиеся соответственно в фалах headerone.h и headertwo.h


Код: Выделить всё

//headerone.h
  #include "headertwo.h"

  class MyClassOne
  {
      public:
      void SomeFunction();
      private:
      MyClassTwo* objPtr;
  };

Код: Выделить всё

//headertwo.h
 class MyClassOne;

  class MyClassTwo
  {
  public:
      void AnotherFunction();
  private:
      MyClassOne* objPtr;
  };
Спасибо сказали:
Аватара пользователя
Uncle_Theodore
Сообщения: 3339
ОС: Slackware 12.2, ArchLinux 64

Re: Multiple header files

Сообщение Uncle_Theodore »

v04bvs, что-то, я не въехал в то, что Вы хотели сказать...
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Multiple header files

Сообщение v04bvs »

Uncle_Theodore писал(а):
13.10.2007 19:33
v04bvs, что-то, я не въехал в то, что Вы хотели сказать...

Я отредактировал код в цитате. Сейчас попробую сделать получше.
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: Multiple header files

Сообщение sergio »

Uncle_Theodore писал(а):
13.10.2007 19:33
v04bvs, что-то, я не въехал в то, что Вы хотели сказать...

Там не отформачено просто. Дело v04bvs говорит.
Написать в начале каждого файла class ДругойКласс ; и всех дел. Там же указатели только.
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали:
Аватара пользователя
VoidExp
Сообщения: 208
Статус: Lead guitar adept
ОС: Ubuntu

Re: Multiple header files

Сообщение VoidExp »

Короче, ситуация такая... Пишу игровой движок, есть класс Root и в нем приватная переменная Scene* cScene. Потом в другом заголовочном файле вставляется заголовок Root-а, и там в качестве аргумента для конструктора есть указатель на Root. То есть получается рекурсивное объявление... Сами понимаете, scene и root совсем разные объекты, так что наследование тут будет неэффективным
Спасибо сказали:
Аватара пользователя
Uncle_Theodore
Сообщения: 3339
ОС: Slackware 12.2, ArchLinux 64

Re: Multiple header files

Сообщение Uncle_Theodore »

sergio писал(а):
13.10.2007 19:40
Uncle_Theodore писал(а):
13.10.2007 19:33
v04bvs, что-то, я не въехал в то, что Вы хотели сказать...

Там не отформачено просто. Дело v04bvs говорит.
Написать в начале каждого файла class ДругойКласс ; и всех дел. Там же указатели только.

А, понял. Да, может получиться. :)
Спасибо сказали:
Аватара пользователя
sarutobi
Сообщения: 676
Статус: Добрость и скромнота
ОС: Debian 5, FreeBSD 6.2/8.0

Re: Multiple header files

Сообщение sarutobi »

То что предлагает v04bvs - классическое решение проблемы. Если в классе используются только указатели - то руководства С++ и здравый смысл настойчиво рекомендуют forward declaration в хидере класса с последующим подключением необходимых хидеров в коде.
VoidExp, для Вашей ситуации может оказаться полезным объявление класса Root синглтоном - не потребуется тащить его через все конструкторы.
Fire and water, earth and sky - mistery surrounds us, legends never die!
Спасибо сказали:
Аватара пользователя
VoidExp
Сообщения: 208
Статус: Lead guitar adept
ОС: Ubuntu

Re: Multiple header files

Сообщение VoidExp »

Возникло недоразумение: выше приведенное решение почему-то не работает, вроде работает вот это:

Код: Выделить всё

//core.h
#include "scene.h"
namespace zEngine
{
   class Scene;
   class Root
   {
    public:
      //some stuff
    private:
      Scene* cScene;
   };
}


Код: Выделить всё

//scene.h
namespace zEngine
{
   class Root;
   class Scene
   {
    public:
      //some stuff
      void SetUp(Root* bindingRoot);
    private:
      Root* cRoot;
   };
}


Кто-нить может объяснить почему?? :) А то чет я не вникаю в механизм, а проект намечается большой =)
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: Multiple header files

Сообщение sergio »

VoidExp писал(а):
13.10.2007 21:24
Возникло недоразумение: выше приведенное решение почему-то не работает, вроде работает вот это:

А чем оно отличается от приведенного выше?
После
#include "scene.h"
уже лишнее
class Scene;

Объявление структуры-класса нужно когда
- надо знать ее размер
- обращаться к ее членам
Размер указателя известен и так. Поэтому для указателя дефинишн структуры не нужен, достаточно указать компилятору что эта "Блабла" - имя типа. Отсюда class Blah.
В срр файлы (где обыкновенно уже нужен доступ к членам...) включаем хедеры полностью.
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали:
Аватара пользователя
VoidExp
Сообщения: 208
Статус: Lead guitar adept
ОС: Ubuntu

Re: Multiple header files

Сообщение VoidExp »

Отличается тем что в первом файле объявления Scene нету, а в моем примере есть. И почему-то (сам не понял почему) работает моё решение...
Спасибо сказали:
Alexey-S
Сообщения: 46
ОС: WinXP Mandriva

Re: Multiple header files

Сообщение Alexey-S »

В языке Java практикуется использование описание интерфейса - interface. В C++ это класс с абстрактными функциями (методами).
Вы создаете для каждого класса свой интерфейс. Интерфейс не имеет параметров и реализаций методов.
В вашем случае, для Root создаём итерфейс IRoot с методом initScene(IScene* pScene).
Для ответного класса Scene создаем интрфейс IScene с методом initRoot(IRoot* pRoot).

Тем самым вы отвязываете жесткую зависимость классов друг от друга.
Поле этого смотрим коментарий sergio, или читаем кондуит по C++.

Удачи Вам, начинающий в C++.
Спасибо сказали:
Аватара пользователя
VoidExp
Сообщения: 208
Статус: Lead guitar adept
ОС: Ubuntu

Re: Multiple header files

Сообщение VoidExp »

Ну, это уже дело вкуса и подходов к программированию. По моему это имеет смысл для огромных (вроде Qt) проектов, где используется массивные реализации интерфесов, шаблонов и т.п. Это делает библиотеку громоздкой, мне же хочется реализовать движок с чистой и понятной структурой. Можете объяснить пожалуйста, почему в каждом файле должно быть взаимное объявления классов?
То есть в файле Root.h так:

Код: Выделить всё

namespace zEngine
{
   class Scene;
   class Root {//interface};
}


А в файле Scene.h так:

Код: Выделить всё

namespace zEngine
{
   class Root;
   class Scene {//interface}/
}


Еще один вопрос (я думаю что вы довольно-таки неплохо разбираетесь в С++ ;) ): возможно-ли объявить Root и Scene вне пространства имен? То есть так: class zEngine::Root & class zEngine::Scene? Я пробовал, но g++ ругается... Не знаю для чего это понадобится в будущем, но все-таки желательно иметь предствление =)
Спасибо сказали:
Аватара пользователя
sarutobi
Сообщения: 676
Статус: Добрость и скромнота
ОС: Debian 5, FreeBSD 6.2/8.0

Re: Multiple header files

Сообщение sarutobi »

VoidExp,
>хочется реализовать движок с чистой и понятной структурой.
как раз концепция интерфейсов и обеспечивает чистую и понятную структуру. Вместо того чтобы явно указывать класс в качестве параметра функции, указывается интерфейс. Интерфейс описывает минимально необходимую в данном случае функциональность (например интерфейс элемента сцены для рендера описывает только положение элемента и его перемещения, а интерфейс физики - только действие сил). Реальный же объект имеет право реализовать сколь угодно много интерфейсов (т.е. произвольный игровой объект может реализовать интерфейс физики и положения одновременно). Это обеспечивает "маскировку" объекта под требуемую функциональность.

>Можете объяснить пожалуйста, почему в каждом файле должно быть взаимное объявления классов?
при компиляции программы компилятору необходимо знать, какие типы данных используются в каждой единице трансляции. Без этого постоянно будут проявляться ошибки - тип данных ХХХ не определен. Если подключать хидер в хидере, токомпилятору становятся доступны все параметры включаемой единицы трансляции. Если же (как в Вашем случае) в хидере элемента указаны только указатели на другие элементы - компилятору достаточно знать только о наличии таких типов объектов - в каком namespace они объявлены. В этом случае гораздо эффективнее будет forward declaration.

>возможно-ли объявить Root и Scene вне пространства имен? То есть так: class zEngine::Root & class zEngine::Scene

если я правильно понял вопрос - то нет. правильный forward declaration будет всегда содержать объявление всех необходимых namespaces со всеми требуемыми классами. запись namespace::Class в forward declaration в хидере недопустима.
Fire and water, earth and sky - mistery surrounds us, legends never die!
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: Multiple header files

Сообщение sergio »

VoidExp писал(а):
14.10.2007 10:36
возможно-ли объявить Root и Scene вне пространства имен? То есть так: class zEngine::Root & class zEngine::Scene? Я пробовал, но g++ ругается... Не знаю для чего это понадобится в будущем, но все-таки желательно иметь предствление =)

Нельзя объявить просто
some_namespace::MyClass ;
Потому что следующий вопрос компилятора будет "а что такое это слово "some_namespace"," :)
Сперва надо объявить нэймспейс.
Члены нэймспейса должны быть объявлены внутри нэймспейса (точнее - видимой его части; нэймспейс можен быть размазан по сотне хедеров, как std).
Отсюда имеем:

Код: Выделить всё

namespace zEngine  {  class Scene;  }


теперь можем

Код: Выделить всё

zEngine::Scene* ptr;


или

Код: Выделить всё

using zEngine::Scene;
Scene* p1;
Scene* p2;
Scene* p3;
Scene* p4;


Примерно так и выглядит форвард-декл:

Код: Выделить всё

namespace zEngine  {
  class Scene;
  class Root;
  template <typename T> class Morph;
  void blah(void);
}

- см. iosfwd в вашей /usr/include/c++ :)
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали:
Аватара пользователя
VoidExp
Сообщения: 208
Статус: Lead guitar adept
ОС: Ubuntu

Re: Multiple header files

Сообщение VoidExp »

Большое всем спасибо за информацию! Работа над проектом продолжается ;)
Спасибо сказали: