1.1.1. #运算符
#字符在#define宏定义中是一个将参数名转换为字符串的运算符,#放在宏参数的前面。例如:
#include
#include
#define DECLARE_NON_COPIABLE_BEGIN(CName) /
class CName /
{/
public: /
virtual std::string ToString( void )const{return "class "#CName;} /
private: /
CName(const CName&); /
CName& operator=(const CName&);
#define DECLARE_NON_COPIABLE_END(CName) };
DECLARE_NON_COPIABLE_BEGIN(Socket)
public:
Socket( void ) { }
DECLARE_NON_COPIABLE_END(Socket)
int main( void )
{
Socket sock;
std::cout<
return 0;
}
先定义了一对宏,DECLARE_NON_COPIABLE_BEGIN和DECLARE_NON_COPIABLE_END,在前一个宏中将拷贝构造函数和复制运算符定义为private,避免对象进行复制(例如文件、Socket等资源),并定义了一个默认的ToString函数返回类的名称,类名称字符串就是通过#运算符生成的。接下来使用定义的宏定义了一个Socket类,来展示这对宏的用法。当然这种实现方式不一定是最好的,还可以通过定义一个基类来实现这种方式,在讲到拷贝构造函数时会展示另一种方案。
1.1.2. ##运算符
在#define定义的宏中,##运算符用于将参数与标识符连接,构成新的标识符,但##运算符放在一个标识符的最前面,也不能放到标识符的最后。例如:
#include
#define DECLARE_BIT(n) const unsigned int BIT ## n = 1<
DECLARE_BIT(0); // 等价于:const unsigned int BIT0 = 1<<0;
DECLARE_BIT(1);
DECLARE_BIT(2);
DECLARE_BIT(3);
DECLARE_BIT(4);
DECLARE_BIT(5);
DECLARE_BIT(6);
DECLARE_BIT(7);
int main( void )
{
std::cout<<"bit0:"<
return 0;
}
上面的代码先定义了一个宏DECLARE_BIT,该宏用于定义整数中各位的权值,然后使用该宏定义了一系列位的权值。这样的代码更利益于维护,比如我们随时可以修改实现的机制,此处是通过定义常量实现的,我们随时可以修改常量的类型,而且只需修改一行代码。
注意:需要注意的是C++标准并没有定义##运算符与#运算符的处理顺序,所以不要定义依赖于这两个运算符解析顺序的宏,避免在不同编译器下产生不同的结果,这样的BUG往往非常难以定位。