Пространства имен C ++: перекрестное использование - PullRequest
2 голосов
/ 18 декабря 2008

Рассмотрим следующий пример. Он состоит из двух заголовочных файлов, объявляющих два разных пространства имен:

// a1.h
#pragma once
#include "a2.h"

namespace a1 
{
    const int x = 10;
    typedef a2::C B;
}

а второй

// a2.h    
#pragma once
#include "a1.h"

namespace a2 {
  class C {
  public:
    int say() {
      return a1::x; 
    }
  };
}

И один исходный файл, main.cpp:

#include <iostream>
#include "a1.h"
#include "a2.h"

int main()
{
  a2::C c;
  std::cout << c.say() << std::endl;
}

Таким образом, он не компилируется (пробовал GCC и MSVC). Ошибка в том, что a1 пространства имен не объявлены (C2653 в Windows). Если вы измените порядок включения в main.cpp таким образом:

#include "a2.h"
#include "a1.h"

вы получаете симметричное сообщение об ошибке, т.е. a2 пространство имен не объявлено.

В чем проблема?

Ответы [ 3 ]

11 голосов
/ 18 декабря 2008

Вам необходимо использовать предварительную декларацию в заголовочных файлах, потому что у вас есть циклическая ссылка. Примерно так:

// a1.h
#pragma once

namespace a2 {
    class C;
}

namespace a1 
{
    const int x = 10;
    typedef a2::C B;
}
3 голосов
/ 18 декабря 2008

Просто предположение, но ваша включаемая ссылка круглая. Это означает, что компилятор не может понять, какой заголовок компилировать первым. a1 ссылается на a2, который ссылается на a1.

Если возможно, объединяйте / реорганизуйте файлы так, чтобы была некруглая цепь включений.

Надеюсь, это поможет!

1 голос
/ 18 декабря 2008

Когда вы сначала включаете a1.h, он сразу же пытается включить a2.h, прежде чем объявить что-либо

a2.h ссылается на что-то в пространстве имен a1, которое еще не было объявлено

Когда вы сначала включаете a2.h, он сразу же пытается включить a1.h, прежде чем что-либо объявить

a1.h ссылается на что-то в пространстве имен a2, которое еще не было объявлено

Удаление typedef из a1.h, который вы не используете, и исключение a2.h удаляет цикл.

Или, как другим комментатором, форвард объявляет класс C.

// a1.h
#pragma once
//#include "a2.h"

namespace a1 
{
    const int x = 10;
//    typedef a2::C B;
}
...