命名空間與源文件#
觀察以下程式碼:
// 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_
如有細節錯誤,歡迎指正。