【问题标题】:How make a class private inside a namespace in C++?如何在 C++ 中的命名空间内将类设为私有?
【发布时间】:2016-12-12 05:05:22
【问题描述】:

如何在 C++ 的命名空间内将一个类设为私有,并防止其他人从命名空间外访问该类,例如:

namespace company{
    class MyPublicClass{ ... }  // This should be accessible 
    class MyPrivateClass{ ... } // This should NOT be accessible
}

【问题讨论】:

  • 放到私有头文件中?
  • 我认为命名空间不能做到这一点。也许你想要的是 C++ 模块。或者只使用嵌套类。

标签: c++ namespaces private


【解决方案1】:

你不能拥有命名空间的访问说明符,但你可以拥有

class company {
    // Private (default)
    class MyPrivateClass { ... };

public:
    class MyPublicClass { ... };
};

您可以像使用范围运算符访问命名空间一样访问类:

company::MyPublicClass my_public_object;

如果“public”类应该可以访问“private”类,那么“private”类必须是“public”类的friend


还有另一种方法,那就是在公共头文件中根本没有MyPrivateClass 定义。要么在源文件中定义类,要么在只包含在内部的私有头文件中。

选择哪种方式取决于您的设计和用例。

【讨论】:

  • 如果你想添加到其他地方的命名空间,它就会崩溃。由于您不能“合并”多个类定义,就像多个命名空间定义组合一样,
  • @nate 如果你想让一个类私有到一个命名空间,可能是为了限制它的使用,所以将它填充到类定义中可能不会对可用性产生重大影响(这里的意图范围之外)。
  • @CaptainObvlious 这很有可能,我只是指出了这种方法的潜在缺陷。我过去曾采用这种方法来允许我在“命名空间”上专门化模板。
【解决方案2】:

你不能。

C++ 命名空间不提供任何作用域访问器,类声明也不提供(例如与 C# 相比)。

通常的方法是引入internal 命名空间来指示public 的使用不是有意的。

您可以使用friend 说明符限制访问。

您还可以使用一些技巧,使公开访问接口变得更加困难,如下所述:How can I remove/refactor a «friend» dependency declaration properly?

【讨论】:

    【解决方案3】:

    您可以使用unnamed namespace。出现在未命名命名空间中的名称具有内部链接,但出现在命名命名空间中且没有任何存储类说明符的名称默认具有外部链接。

    例如我们有一个名为source1.cpp的文件:

    //source1.cpp
    namespace company{
        class MyPublicClass{ ... };
        namespace{
            class MyPrivateClass{ ... };
        }
    }
    void f1(){
    company::MyPrivateClass m;
    }
    

    MyPublicClass 具有外部链接,MyPrivateClass 具有内部链接。所以source1没有问题,可以编译成库,但是如果我们有其他文件名为source2.cpp

    //source2.cpp
    void f2(){
    company::MyPrivateClass m;
    }
    

    source2无法与编译后的source1关联,也无法引用MyPrivateClass

    【讨论】:

    • 在多个模块中存在重复的类和方法名称的问题(每个模块中的类具有相同的名称和相同的方法,但未在标头中声明,因此没有外部可见性;链接器静默丢弃所有实现,但只有一个实现)你的小费解决了这个问题。谢谢!
    • 不适用于模板类,因为您应该将它们放在头文件中。
    • @Somnium 显式实例化声明和定义对于这种情况很有用。
    • 是的,在某些情况下这是一个很好的解决方案,但是,当编写一个通用库时,就不可能使用显式实例化。在这种情况下,可以使用命名为 internal 的命名空间(如其他答案所示)。
    • @Somnium 原始标题可以包含在您放置显式实例化声明的第二个标题中。然后,您可以在项目中使用第二个标头。
    猜你喜欢
    • 2015-10-01
    • 2014-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-17
    • 1970-01-01
    • 2013-09-08
    相关资源
    最近更新 更多