7

How make a class private inside a namespace in C++ and prevent other to access the class from outside the namespace, for instance:

namespace company{
    class MyPublicClass{ ... }  // This should be accessible 
    class MyPrivateClass{ ... } // This should NOT be accessible
}
Daniel Santos
  • 14,328
  • 21
  • 91
  • 174

3 Answers3

12

You can use unnamed namespace. Names that appear in an unnamed namespace have internal linkage but names that appear in a named namespace and don't have any storage class specifier, by default, have external linkage.

For example we have a file named source1.cpp:

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

MyPublicClass has external linkage and MyPrivateClass has internal linkage. So there is no problem with source1 and it can be compiled as a library ,but if we have other file named source2.cpp:

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

source2 can't be linked with the compiled source1 and we can not refer to MyPrivateClass.

rahnema1
  • 15,264
  • 3
  • 15
  • 27
  • 1
    Had a problem with duplicate class and method names in multiple modules (Classes in each module with same name and same method but not declared in header, so no external visibility; Linker silently drops all but one implementation) and your tip solved this problem. Thank you! – Andreas H. Feb 27 '18 at 08:16
  • Does not work for template classes, because you should put them in header files. – Somnium Sep 17 '19 at 10:07
  • @Somnium explicit instantiation declaration and definition are useful for such cases. – rahnema1 Sep 17 '19 at 11:09
  • Yes, in some cases it is good solution, however, when writing a general purpose library then it's not possible to use explicit instantiation. In such case namespace named like `internal` could be used (like other answer suggests). – Somnium Sep 17 '19 at 15:41
  • @Somnium The original header can be included in a second header where you place the explicit instantiation declaration. You can then use the second header in your project. – rahnema1 Sep 18 '19 at 00:30
10

You can't have access specifiers for namespaces, but you can for classes:

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

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

You access the classes just like for a namespace with the scope operator:

company::MyPublicClass my_public_object;

If the "public" class should have access to the "private" class, then the "private" class have to be a friend of the `public" class.


There is also another way, and that is to simply not have the MyPrivateClass definition in a public header file. Either define the class in the source file, or in a private header file only included internally.

Which way to choose depends on your design and use-cases.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 3
    The falls apart if you want to add to the namespace elsewhere. Since you cannot "merge" multiple class definitions, in the same way that multiple namespace definitions combine, – nate Aug 05 '16 at 17:49
  • @nate If you're wanting to make a class private to a namespace chances are the intent is to limit its use so stuffing it into a class definition is probably not going to have a significant impact on usability (outside the scope of the intent here). – Captain Obvlious Aug 05 '16 at 18:34
  • @CaptainObvlious That is quite possible, I just was pointing out a potential pitfall of this approach. I have taken this approach in the past to allow me to specialize templates on a "namespace". – nate Aug 05 '16 at 18:37
6

You cannot.

C++ namespaces don't provide any scoped accessors, neither do class declarations (vs C# for example).

The usual way is to introduce an internal namespace to indicate public usage isn't intended.

You may restrict access using friend specifiers.

You can also use some tricks, to make it harder accessing an interface publicly like explained here: How can I remove/refactor a «friend» dependency declaration properly?

Community
  • 1
  • 1
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190