简体   繁体   中英

Anonymous Namespace Class Definition

I was looking over some (C++) code and found something like this:

//Foo.cpp
namespace
{
    void SomeHelperFunctionA() {}
    void SomeHelperFunctionB() {}
    void SomeHelperFunctionC() {}

    //etc...    

    class SomeClass //<---
    {
        //Impl
    };
}

SomeHelperFunction[AZ] are functions that are only needed in that translation unit, so I understand why they're in an anonymous namespace . Similarly, SomeClass is also only required in that translation unit, but I was under the impression that you could have classes with identical names in different translation units without any sort of naming collisions provided that you didn't have a global class declaration (eg, in a commonly included header file).

I should also mention that this particular translation unit does not include any headers that might declare a class with an identical name ( SomeClass ).

So, given this information, could someone please shed some light on why the original programmer might have done this? Perhaps just as a precaution for the future?

I'll be honest, I've never seen classes used in anonymous namespaces before.

Thanks!

An anonymous namespace is like the static keyword when it is applied at the global level.

An anonymous namespace makes it so you can't call anything inside the namespace from another file.

Anonymous namespaces allow you to limit the scope of what's within to the current file only.

The programmer would have done this to avoid naming conflicts. No global names will conflict in this way at linking time .

Example:

File: test.cpp

namespace 
{
  void A()
  {
  }
  void B()
  {
  }
  void C()
  {
  }
}

void CallABC()
{ 
  A();
  B();
  C();
}

File: main.cpp

void CallABC();//You can use ABC from this file but not A, B and C

void A()
{
//Do something different
}

int main(int argc, char** argv)
{
  CallABC();
  A();//<--- calls the local file's A() not the other file. 
  return 0;
}

The above will compile fine. But if you tried to write an CallABC() function in your main you would have a linking error.

In this way you can't call A() , B() and C() functions individually, but you can call CallABC() that will call all of them one after the other.

You can forward declare CallABC() inside your main.cpp and call it. But you can't forward declare test.cpp's A(), B() nor C() inside your main.cpp as you will have a linking error.

As for why there is a class inside the namespace. It is to make sure no external files use this class. Something inside the.cpp probably uses that class.

If someone links this code and has the definition of an identical named class included and this file is linked before the other implementation you would have a name conflict.

In the C++ ISO standard (Section 2.3), you will find a rule called The One Definition Rule .

Due to the complex relationship in C++ between compilation and linking, this is not a very simple rule. Most of the details are here .

But it applies to the functions that are members of a class, because they are (at the linking level) simply functions with long names.

It applies in a slightly different way to templates, because the linker will happily discard extra definitions of template classes or functions that appear in separate translation units (source files). This means that if you provide two different definitions of the same template, your program has undefined behaviour (best case scenario: one of the definitions will be silently chosen at random).

I was under the impression that you could have classes with identical names in different translation units without any sort of naming collisions provided that you didn't have a global class declaration

Well, that's not the case. Remember that those "common" global class definitions are in header files. Those are literally included, copying that common global class definition to all translation units. If you use another way of including exactly the same class definitions in multiple translation units (eg. macro expansion), it's fine too. But if you have different definitions for the same class name, you risk undefined behavior. Link failures if you're lucky.

To answer your question directly, I think that this is to avoid linker "multiple definition" errors for static members of SomeClass. That is, suppose SomeClass is defined in a cpp file without an anonymous namespace and there are some static fields and/or static methods in it and these static members are defined next to the class definition in this very cpp-file. Then these static members get the external linkage (are present in the symbol table of the corresponding.o file as GLOBAL).

Now you have another cpp-file and you want to create another SomeClass (unrelated to that one in the first cpp-file and you may be even unaware of the existence of the first SomeClass in that first cpp-file) for your own purposes and again without an anonymous namespace. And you define a static member with the same name as a static member of the first SomeClass. And here you are: you end up with a linkage conflict.

So the author of the first cpp-file should have hidden the first SameClass inside an anounimous namespace, as the class was clearly supposed to be an implementation detail, rather than a class re-used by other people. And so its static members should not have external linkage.

So overall, what I try to say is that non-constexpr/non-inline static members of a class are just like global variables or non-inline functions. And so their linkage can be made internal using an anonymous namespace just like it can be done for global variables and functions using static keyword or again an anonymous namespace.

// .cpp file
namespace 
{
    struct A
    {
        static int i;
    };
}

int A::i;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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