Циклическая зависимость, заголовки и шаблоны

У меня проблемы с включенной моделью реализации шаблонов и циклической зависимостью файлов * .h и * .hpp.

Представим себе следующие последовательности наследования классов:

 A->B->C, 
 A->A1,
 B->B1, C->C1

где A, A1 - абстрактные классы.

A.h (абстрактный класс)

#ifndef A_H
#define A_H

template <class A>
{
  //some code
  virtual A() = 0;
};

#include "A.hpp"

#endif

A.hpp

#ifndef A_HPP
#define A_HPP
#include "B.h" //Circular dependency
#include "C.h" //Circular dependency

void create Object(A ** a, unsigned int code)
{
  switch (code)
  {
    case 0: *a = new B(); break;
    case 1: *a = new C();

  };
}

#endif

B.h

#ifndef B_H
#define B_H

#include "A.h"

template <class T>
class B : public A <T>
{
  //Some code
};

C.h

#ifndef C_H
#define C_H

#include "C.h"

template <class T>
class C : public B <T>
{
  //Some code
};

A1.h (абстрактный класс)

#ifndef A1_H
#define A1_H

#include "A.h"

template <class T>
class A1 : public A <T>
{
  //Some code
};

#include "A.hpp"

#endif

A1.hpp

#ifndef A1_HPP
#define A1_HPP
#include "B1.h" //Circular dependency
#include "C1.h" //Circular dependency

void create Object(A1 ** a1, unsigned int code)
{
  switch (code)
  {
    case 0: *a = new B1(); break;
    case 1: *a = new C1();

  };
#endif

B1.h

#ifndef B1_H
#define B1_H

#include "B.h"

template <class T>
class B1 : public B <T>
{
  //Some code
};

C1.h

#ifndef C1_H
#define C1_H

#include "C.h"

template <class T>
class C1 : public C <T>
{
  //Some code
};

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

A.hpp

#ifndef A_HPP
#define A_HPP

template <class T>
class A;
template <class T>
class B;

//some code
#endif

1. л.с.

#ifndef A1_HPP
#define A1_HPP

template <class T>
class A;
template <class T>
class B;

//some code
#endif

person CrocodileDundee    schedule 03.02.2011    source источник
comment
Там, где это возможно, следует использовать форвардные объявления вместо включения заголовков. Я не могу сказать, где вы можете заменить директивы include на форвардные объявления, не увидев вашего кода.   -  person Kiril Kirov    schedule 03.02.2011
comment
возможный дубликат двух классов и встроенных функций   -  person Fred Nurk    schedule 03.02.2011


Ответы (3)


Вам необходимо:

  1. Определите каждый класс в его заголовке
  2. Включите в каждый заголовок необходимые ему зависимости.
  3. Не ** требовать **, чтобы зависимость успешно определила класс, а также объявить его вперед.

Если вы сделаете все вышеперечисленное, вы позволите другому коду включать заголовки в любом порядке, но они все равно будут работать в своей «цикличности». Нет, моя проверка правописания не знала этого слова, потому что я его только что придумал.

Другими словами, вам нужно делать такие вещи:

foo.h:

  #ifndef FOO_H
  #define FOO_H

  #include "bar.h"

  class bar;       // THIS IS THE CRITICAL LINE

  class foo {
    // ... uses bar
  }
  #endif /* FOO_H */

bar.h

  #ifndef BAR_H
  #define BAR_H

  #include "foo.h"

  class bar;       // THIS IS THE CRITICAL LINE

  class bar {
    // ... uses foo
  }
  #endif /* BAR_H */
person Wes Hardaker    schedule 03.02.2011

A.hpp и A1.h не должны содержать ничего, связанного с B или C.

person Chris K    schedule 03.02.2011

Почему реализация A вообще должна знать о B & C? Если реализация родителя зависит от деталей конкретного потомка, похоже, что наследование не используется должным образом.

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

Можете ли вы показать нам конкретно, почему вам нужно включить B & C в заголовок / реализацию A?

person Mark B    schedule 03.02.2011
comment
Я обновил исходный код, смотрите выше. В абстрактных классах A и A1 мне нужно создавать новые объекты ... - person CrocodileDundee; 03.02.2011