命名空间 & 源文件#
观察以下代码:
// 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_
如有纰漏,欢迎指正。