繁体   English   中英

在不使用未命名命名空间的情况下在标头中隐藏 C++ 类

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM