命名空間與源文件#
觀察以下程式碼:
// current_thread.h
#ifndef _CURRENT_THREAD_H_
#define _CURRENT_THREAD_H_
namespace mymuduolib {
namespace currentthread {
extern __thread int t_cached_tid;
void cachedTid();
} // namespace currentthread
} // namespace mymuduolib
#endif // _CURRENT_THREAD_H_
在源文件中實現頭文件中的定義,可以在實現的名稱前加上 mymuduolib::currentthread:: 前綴以指定命名空間:
// current_thread.cpp
#include "current_thread.h"
#include <unistd.h>
#include <sys/syscall.h>
__thread int mymuduolib::currentthread::t_cached_tid = 0;
void mymuduo::currentthread::cachedTid() {
    if (t_cached_tid == 0) {
        // get the current id through Linux system call
        t_cached_tid = static_cast<pid_t>(::syscall(SYS_gettid));
    }
}
如果不添加命名空間前綴,就相當於有兩個 t_cached_tid 和 cachedTid(),一個在 mymuduo::currentthread:: 命名空間,另一個在 :: 命名空間,且 mymuduo::currentthread:: 命名空間中的定義未給出實現,如果此時在某個模組中使用 using namespace mymuduolib::currentthread; 則會調用 mymuduolib::currentthread:: 命名空間下的 cachedTid()。(當然這段程式碼如果不添加命名空間前綴是無法通過編譯的,因為函數中的變數 t_cached_tid 就會出現指定不明的問題)。
也可以將實現程式碼放在與頭文件相同的命名空間下:
// current_thread.cpp
#include "current_thread.h"
#include <unistd.h>
#include <sys/syscall.h>
namespace mymuduolib {
namespace currentthread {
__thread int t_cached_tid = 0;
void cachedTid() {
    if (t_cached_tid == 0) {
        // get the current id through Linux system call
        t_cached_tid = static_cast<pid_t>(::syscall(SYS_gettid));
    }
}
    
} // namespace mymuduolib
    
} // namespace currentthread
但是這裡不能只使用 using namespace mymuduolib::currentthread;,因為函數和變數實現的作用域需要明確指定,如未指定相當於之後的實現內容是獨立於該命名空間。
但類中成員在實現時,可以使用 using namespace 的命名空間:
// poller.h
#ifndef _POLLER_H_
#define _POLLER_H_
namespace mymuduolib {
namespace net {
class Poller {
    Poller();
};
}
} // namespace net
#endif // _POLLER_H_
在源文件中:
// poller.cpp
#include "poller.h"
// mymuduolib::net::Poller::Poller() {}
using namespace mymuduolib::net;
Poller::Poller() {}
命名空間與前置宣告#
前置宣告可以避免循環依賴的問題,當前置宣告遇到命名空間時有一個容易踩的坑。
觀察以下錯誤程式碼:
// addr.h
#ifndef _ADDR_H_
#define _ADDR_H_
namespace net {
class Addr {};
} // namespace net
#endif // _ADDR_H_
// http_connect.h
#ifndef _HTTP_CONNECT_H_
#define _HTTP_CONNECT_H_
class Addr;
namespace net {
class HttpConnect {
public:
    HttpConnect(const Addr &);
};
} // namespace net
#endif // _HTTP_CONNECT_H_
// http_connect.cpp
#include "http_connect.h"
#include "addr.h"
using namespace net;
HttpConnect::HttpConnect(const Addr &) {}
// main.cpp
#include "http_connect.h"
int main() {
    net::HttpConnect(Addr());
}
錯誤訊息:
http_connect.cpp:6:1: 錯誤:no declaration matches ‘net::HttpConnect::HttpConnect(const net::Addr&)’
    6 | HttpConnect::HttpConnect(const Addr &) {}
      | ^~~~~~~~~~~
In file included from http_connect.cpp:1:
http_connect.h:8:7: 附注:备选为: ‘constexpr net::HttpConnect::HttpConnect(net::HttpConnect&&)’
    8 | class HttpConnect {
      |       ^~~~~~~~~~~
http_connect.h:8:7: 附注:         ‘constexpr net::HttpConnect::HttpConnect(const net::HttpConnect&)’
http_connect.h:10:5: 附注:         ‘net::HttpConnect::HttpConnect(const Addr&)’
   10 |     HttpConnect(const Addr &);
      |     ^~~~~~~~~~~
http_connect.h:8:7: 附注:‘class net::HttpConnect’ defined here
    8 | class HttpConnect {
      |       ^~~~~~~~~~~
看到這個錯誤你可能會說是 using namespace 所導致的,其實並不是,使用 net::HttpConnect::HttpConnect(const net::Addr&) 也是一樣的結果。
這裡其實是前置宣告上的問題,我們需要將前置宣告 class Addr 放置 namespace net 命名空間內,因為前置宣告的 class Addr 在 :: 作用域中是不存在的。
// http_connect.h
#ifndef _HTTP_CONNECT_H_
#define _HTTP_CONNECT_H_
namespace net {
class Addr;
class HttpConnect {
public:
    HttpConnect(const Addr &);
};
} // namespace net
#endif // _HTTP_CONNECT_H_
如有細節錯誤,歡迎指正。