简体   繁体   中英

Correct way to define C++ namespace methods in .cpp file

Probably a duplicate, but not an easy one to search for...

Given a header like:

namespace ns1
{
 class MyClass
 {
  void method();
 };
}

I've see method() defined in several ways in the .cpp file:

Version 1:

namespace ns1
{
 void MyClass::method()
 {
  ...
 }
}

Version 2:

using namespace ns1;

void MyClass::method()
{
 ...
}

Version 3:

void ns1::MyClass::method()
{
 ...
}

Is there a 'right' way to do it? Are any of these 'wrong' in that they don't all mean the same thing?

Version 2 is unclear and not easy to understand because you don't know which namespace MyClass belongs to and it's just illogical (class function not in the same namespace?)

Version 1 is right because it shows that in the namespace, you are defining the function.

Version 3 is right also because you used the :: scope resolution operator to refer to the MyClass::method () in the namespace ns1 . I prefer version 3.

See Namespaces (C++) . This is the best way to do this.

5 years later and i thought I'd mention this, which both looks nice and is not evil

using ns1::MyClass;

void MyClass::method()
{
  // ...
}

I'm using version 4 (below) because it combines most of the advantages of version 1 (terseness of the resoective definition) and version 3 (be maximally explicit). The main disadvantage is that people aren't used to it but since I consider it technically superior to the alternatives I don't mind.

Version 4: use full qualification using namespace aliases:

#include "my-header.hpp"
namespace OI = outer::inner;
void OI::Obj::method() {
    ...
}

In my world I'm frequently using namespace aliases as everything is explicitly qualified - unless it can't (eg variable names) or it is a known customization point (eg swap() in a function template).

Googles C++ Style Guide dictates your version 1, without indentation though.

命名空间的 Google C++ 风格指南

Version 3 makes the association between the class and the namespace very explicit at the expense of more typing. Version 1 avoids this but captures the association with a block. Version 2 tends to hide this so I'd avoid that one.

I choose Num.3 (aka the verbose version). It's more typing, but the intent is exact to you and to the compiler. The problem you posted as-is is actually simpler than the real world. In the real world, there are other scopes for definitions, not just class members. Your definitions aren't very complicated with classes only - because their scope is never reopened (unlike namespaces, global scope, etc.).

Num.1 this can fail with scopes other than classes - anything that can be reopened. So, you may declare a new function in a namespace using this approach, or your inlines could wind up being substituted via ODR. You will need this for some definitions (notably, template specializations).

Num.2 This is very fragile, particularly in large codebases - as headers and dependencies shift, your program will fail to compile.

Num.3 This is ideal, but a lot to type - what your intent is to define something . This does exactly that, and the compiler kicks in to make sure you've not made a mistake, a definition is not out of synch with its declaration, etc..

It turns out it's not only "coding-style matter". Num.2 leads to linking error when defining and initializing a variable declared extern in header file. Take a look at example in my question. Definition of constant within namespace in cpp file

All the ways are right, and each one has its advantages and disadvantages.

In the version 1, you have the advantage of not having to write the namespace in front of each function. The disadvantage is that you'll get a boring identation, specially if you have more than one level of namespaces.

In version 2, you make your code cleaner, but if you have more than one namespace being implemented in the CPP, one may access the other one's functions and variables directly, making your namespace useless (for that cpp file).

In version 3, you'll have to type more and your function lines may be bigger than the screen, which is bad for design effects.

There is also another way some people use it. It is similar to the first version, but without the identation problems.

It's like this:

#define OPEN_NS1 namespace ns1 { 
#define CLOSE_NS1 }

OPEN_NS1

void MyClass::method()
{
...
}

CLOSE_NS1

It's up to you to chose which one is better for each situation =]

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