У меня следующая ситуация:
namespace MyFramework {
class A {
void some_function_I_want_B_to_use() {}
};
class B {
B() {
some_function_I_want_B_to_use() {}
}
};
}
где я хочу some_function_I_want_B_to_use
не быть видимым за пределами MyFramework
пространство имен, но я хочу, чтобы оно было видимым для всех внутри MyFramework (в качестве альтернативы можно также видеть только класс B). У меня есть несколько таких методов, это единственный способ скрыть их от публичного API MyFramework, чтобы все классы были внутри MyFramework
друзья? Я также рассматривал возможность размещения всех классов «более низкого уровня» внутри B, но я не хочу идти по этому пути, пока не буду уверен, что это обеспечит возможность доступа ко всем методам A изнутри B, но не из за пределами MyFramework.
Иными словами, у меня есть фреймворк, созданный в одном пространстве имен, и у каждого класса есть методы, которые полезны для широкой публики при использовании фреймворка. Однако каждый класс также имеет несколько методов, которые усложняют общедоступный API, но необходимы для правильной работы инфраструктуры.
Идиома, часто называют Компиляция Firewall, это то, что вы ищете. Целый Qt реализуется с использованием этой идиомы.
// A.hpp
namespace MyFramework {
class A {
private:
class Private;
Private* implementation;
};
}
// A_Private.hpp
#include "A.hpp"
namespace MyFramework {
class A::Private {
public:
void some_function_I_want_B_to_use() {}
};
}
// A.cpp
#include "A_Private.hpp"
namespace MyFramework {
A::A() {
implementation->some_function_I_want_B_to_use();
}
}
// B.hpp
#include "A.hpp"
namespace MyFramework {
class B {
B();
A a;
};
}
// B.cpp
#include "A_Private.hpp"
namespace MyFramework {
B::B() {
a.implementation->some_function_I_want_B_to_use();
}
}
НОТА: Конечно A_Private.hpp
не входит в include
каталог вашего фреймворка, окончательный дистрибутив, т.е. он остается частный пакет как вам требуется.
Пример очень простой. Конечно, это можно сделать более продвинутым и надежным. Дополнительно, Pimpl имеет много других преимуществ. Для всей этой информации обратитесь к:
Я хочу
some_function_I_want_B_to_use
не быть видимым за пределамиMyFramework
пространство имен, но я хочу, чтобы оно было видно любомуMyFramework
,
Таким образом, вы хотите что-то похожее на пакеты в Java.
К сожалению, для вас это не возможно с пространствами имен. Каждый класс, включенный в пространство имен, доступен из внешнего пространства имен: пространства имен открыты.
Решение обычно состоит в том, чтобы добавить другое пространство имен для деталей реализации:
namespace MyFramework
{
// Implementation details
// Should not be used by the user
namespace detail
{
class A
{
public:
void func();
};
}
class B
{
public:
B()
{
A a;
a.func();
}
};
}
Не забудьте добавить комментарий о detail
пространство имен не должно использоваться пользователем.
Общее соглашение, например, в Boost — это вложенное пространство имен detail
,
Если хотите обеспечивать соблюдение доступность вы всегда можете вместо этого использовать вложенный class
называется detail
, Класс обеспечивает проверку доступности, но ему не хватает расширяемости, как в пространстве имен. Тем не менее, detail
сфера будет редко, если когда-либо потребуется расширение.
Итак, во всем своем безобразии,
namespace my_framework {
class detail
{
private:
static void some_function_I_want_B_to_use() {}
public:
class A
{};
class B
{
B() { some_function_I_want_B_to_use(); }
};
};
typedef detail::A A; // "using detail::A"typedef detail::B B; // "using detail::B"} // namespace my_framework
Попутно обратите внимание, что класс B (прямо из вопроса) имеет собственный конструктор по умолчанию, поэтому его экземпляры не могут быть созданы.