Вопрос: Возможно ли получить доступ к определенному классу из заголовка, скрывая другие пространства имен / классы, определенные в этом заголовке?
Например, скажем, у меня есть файл заголовка — outcome.hpp:
// outcome.hpp
namespace sports { namespace outcome {
class Injury {};
class Success {};
}}
В другом заголовочном файле — api.hpp — Я хочу использовать sports::outcome::Injury
без sports::outcome::Success
доступны для файлов, которые включают api.hpp. Это возможно? Если так, как я могу этого достичь?
Постскриптум В фактическом коде api.hpp содержит шаблонные методы, которые будут вызывать методы Injury
класс, поэтому предварительное объявление недостаточно.
В своем невежестве я пытался добиться этого, поместив include
во внутреннем пространстве имен. Вот SSCCE:
// api.hpp
namespace sports { namespace api {
namespace internal {
#include "outcome.hpp" // I'm trying to hide symbols within this header
using sports::outcome::Injury;
}
class Boxing {
private:
internal::Injury sustained;
};
}
Я праздновал преждевременно, когда это сработало:
// This cpp file compiles file \o/
#include "api.hpp"int main(int argc, char *argv[]) {
sports::api::Boxing b;
// sports::outcome not accessible
}
Вещи распадаются, если контейнер из стандартной библиотеки используется в качестве члена класса в outcome.hpp. Например, используя эту версию:
// outcome.hpp
#include <vector>
namespace sports { namespace outcome {
class Injury {
private:
std::vector x;
};
// ...
}}
Компиляция завершается со следующими ошибками:
В файле из /usr/include/c++/4.6/ext/new_allocator.h:34:0, из /usr/include/c++/4.6/x86_64-linux-gnu/./bits/c++allocator.h:34, из /usr/include/c++/4.6/bits/allocator.h:48, из /usr/include/c++/4.6/vector:62, из result.hpp: 1, из api.hpp: 5, из main.cpp: 1: /usr/include/c++/4.6/new:93:54: ошибка: 'void * sports :: api :: internal :: operator new (sports :: api :: internal :: std :: size_t)' не может быть объявлен в пространстве имен /usr/include/c++/4.6/new:94:56: ошибка: 'void * sports :: api :: internal :: operator new [] (sports :: api :: internal :: std :: size_t)' может не может быть объявлено в пространстве имен /usr/include/c++/4.6/new:95:35: ошибка: «void sports :: api :: internal :: operator delete (void *)» не может быть объявлена в пространстве имен /usr/include/c++/4.6/new:96:37: ошибка: «void sports :: api :: internal :: operator delete [] (void *)» не может быть объявлено в пространстве имен /usr/include/c++/4.6/new:97:62: ошибка: 'void * sports :: api :: internal :: operator new (sports :: api :: internal :: std :: size_t, const sports :: api :: internal :: std :: nothrow_t) 'нельзя объявить в пространстве имен /usr/include/c++/4.6/new:98:64: ошибка: 'void * sports :: api :: internal :: operator new [] (sports :: api :: internal :: std :: size_t, const sports :: api :: internal :: std :: nothrow_t) 'нельзя объявить в пространстве имен /usr/include/c++/4.6/new:99:58: ошибка: 'void sports :: api :: internal :: оператор delete (void *, const sports :: api :: internal :: std :: nothrow_t)' не может быть объявлено в пространстве имен /usr/include/c++/4.6/new:100:60: ошибка: 'void sports :: api :: internal :: operator delete [] (void *, const sports :: api :: internal :: std :: nothrow_t ) 'не может быть объявлено в пространстве имен /usr/include/c++/4.6/new:103:57: ошибка: 'void * sports :: api :: internal :: operator new (sports :: api :: internal :: std :: size_t, void *)' не может быть объявлено в пространстве имен /usr/include/c++/4.6/new:104:59: ошибка: 'void * sports :: api :: internal :: operator new [] (sports :: api :: internal :: std :: size_t, void * ) 'не может быть объявлено в пространстве имен /usr/include/c++/4.6/new:107:52: ошибка: «void sports :: api :: internal :: operator delete (void *, void *)» не может быть объявлен в пространстве имен /usr/include/c++/4.6/new:108:52: ошибка: «void sports :: api :: internal :: operator delete [] (void *, void *)» не может быть объявлена в пространстве имен
Я явно делаю это неправильно. Советы и хорошие отзывы будут с благодарностью.
Вы можете импортировать имя из пространства имен в другое пространство имен с помощью объявления using.
namespace sports {
using sports::outcome::Injury;
};
В твоем примере много чего не так. Особенно включается плохо, и вам не хватает охранников.
// file1.h
#ifndef FILE1_h
#define FILE1_h
namespace sports { namespace outcome {
class Injury;
}}
#endif
// api.h
#ifndef API_H
#define API_H
#include <file1.h>
namespace sports {
using sports::outcome::injury;
}
#endif
Файл, который включает api.h
теперь имеет доступ к:
sports::injury x;
Файл, который просто включает file1.h
имеет доступ только к:
sports::outcome::injury x;
Если я правильно понимаю ваше намерение, вы хотите что-то вроде «частного» или «внутреннего» пространства имен? ИМХО, это невозможно в C ++.
Вы можете использовать класс для этого и разместить там определения внутренних классов как вложенные классы, ваше пространство имен api может быть реализовано аналогично, предоставляя другим классам открытые определения типов, при условии, что api является другом внутреннего класса.
namespace sports
{
class api;
class outcome
{
friend class api;
// Internal class definitions
class Boxing
{
};
};
class api
{
public:
typedef outcome::Boxing Boxing;
}
}