[英]Hiding a C++ class in a header without using the unnamed namespace
我正在编写一个 C++ 头文件,在其中定义了一个
class A {
// ...
};
我想对外界隐藏(因为它可能会在此标头的未来版本中更改甚至删除)。
在同一个头文件中还有一个类 B,它有一个类 A 的对象作为成员:
class B {
public:
// ...
private:
A a_;
};
向外界隐藏A类的正确方法是什么?
如果我将 A 的定义放在未命名的命名空间中,编译器会发出警告,因此我认为,由于内部链接问题,我应该做其他事情。
在 C++ 中正确的方法是PIMPL
idiom。 另一种解决方案是将要隐藏的类放入嵌套命名空间中,通常称为detail
。 但这不会使它完全私有,因为用户仍然会接触到它的依赖项,并且可以直接使用它。
你可以做一个内部类:
class B
{
class A { /* ... */ };
A a_;
}
记录此类不是公共 API 的一部分,不应使用。
在 C++ 中,您必须信任与您的库代码链接的程序,因为您别无选择。 C++ 具有有限的“访问控制”功能,其中许多功能可以被绕过或滥用,因此您最好尊重并建立信任来对待您的 API 客户端。
如果您将 API 设计为易于正确使用且难以误用,那么您将帮助您的客户,如果您的客户滥用您的界面,这几乎不是您的错。
无论如何,未命名的命名空间是无用的,因为它只能保护多个定义。 您可以做的是使用 pImpl Idiom,如其他答案中所述,或者使用detail
命名空间。 适用于 Boost:
namespace detail{
class A{
// ...
};
}
class B{
public:
// ...
private
A a_;
};
任何在detail
命名空间中弄乱东西的人都是在自找麻烦。 或者也许更模糊它
namespace _b_impl_detail{
// ...
};
任何现在触碰里面任何东西的人都应该被射中脚。 :)
不是class B
持有A
对象,而是持有A*
(或shared_ptr<A>
或unique_ptr<A>
等)。 这样class B
只需要class A
class A
的前向声明, class A
class A
可以在class B
的源文件中完全定义。
如果 A 是 B 的实现细节,则根本不要将其定义放在标题中。 反而:
class B {
...
class A * myA;
};
然后把A的定义放在B实现(即.cpp)文件中。
我想在https://stackoverflow.com/a/5780976/1525238上添加一个小增量,这有助于我更好地解决我的特殊用例,即“main”类是模板,“helper/inner”类也必须是模板1 。
我使用了一个名为detail
的嵌套命名空间,将所有“helper”内容设为私有,并使“main”类成为“helper”类的friend
:
template<__MAIN_TEMPLATE_PARAMS__> class Main;
namespace detail {
template<__HELPER_TEMPLATE_PARAMS__> class Helper {
/* All Main templates are friends */
template<__MAIN_TEMPLATE_PARAMS__> friend class Main;
/* Private stuff, not reachable from the outside */
static void privateThing(){
...
}
};
}
template<__MAIN_TEMPLATE_PARAMS__> class Main {
void usePrivateThing(){
detail::Helper<__DESIRED_HELPER_TEMPLATE_PARAMS__>::privateThing();
}
};
上面的私有内容是static
,只是为了使代码更短。 它们很可能与Helper
实例相关联。
回想起来,当然可以有更优雅的解决方案,涉及更少的黑魔法,但这在很大程度上取决于特定的应用程序。 我仍然发现上面是一个合法的,很好的friend
类用例。
1这是因为我需要使用一个需要部分特化的模板辅助函数,这在 c++ 中是不允许的,没有特别的原因,但技术上可以使用包装类。 为简单起见,上面省略了部分专业化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.