一、宏定义的用法
1.单纯的文本替换
例1:

#define a 2+3
cout<<a*a<<endl;//等价于2+3*2+3=5+6=11

输出多少?
例2:

#define s(r) 3.14*r*r
cout<<s(10+5)<<endl;//等价于3.14*10+5*10+5=86.4

输出多少?
2.高级用法:
(1)多行宏定义

#define s (name,type)\//\表示代码隔行连接
class name\
{\
public:\
    inline : name() {};\
    inline:~name() {};\
private:\
    type id:\
};

如果要写宏不止一行,则在结尾加反斜线符号使得多行能连接上,如:

#define HELLO "hello \
the world"

注意第二行要对齐,否则,如:

#define HELLO "hello the wo\
  rld"
printf("HELLO is %s\n", HELLO);

//输出结果为: HELLO is hello the wo  rld 
也就是行与行之间的空格也会被作为替换文本的一部分
而且由这个例子也可以看出:宏名如果出现在源程序中的“”内,则不会被当做宏来进行宏代换。
宏可以嵌套,但不参与运算:

(2)set函数与get函数

#define propertybuilderbyname(type,name,access_permission)
acess_permission:\
type m_##name:\
/*
和 # 运算符一样,## 运算符也可以用在替换文本中,
而它的作用是起到粘合的作用,即将两个语言符号组合成一个语言符号,
所以又称为“预处理器的粘合剂(Preprocessor Glue)”
*/
public:
	inline void set ##name(type v) {
		\
			m##name = v; \
			cout << "new value is" << v << endl; \
	}\
		inline type get##name() {
			\
				return m_##name;\
		}
		_declspe(property(get = get##name, put = set##name))type name;\
class dateset
		{
		private:
		public:
			propertybuilderbyname(short,age,private)
			propertybuilderbyname(int,score,private)
			propertybuilderbyname(string,name,private)
			propertybuilderbyname(int,id,private)
		};

这样定义之后调用时

dataset ds;
ds.age=10;//set函数
cout<<ds.age<<endl;//get函数

(3)系统自带宏定义

C++内置的宏定义
这四个都是预编译宏,不是包含在头文件中的
__FILE__是当前编译的文件的文件名 是一个字符串
__TIME__是当前编译的文件的编译时间 格式是hh:mm:ss 是字符串
__DATE__是当前编译的文件的编译日期 格式是Mmm:dd:yyyy 是字符串
__LINE__是调用该宏语句所在的行数,是个十进制数
(4)跨平台

C++:编写跨平台程序的关键,C/C++中的内置宏定义
分两部分:
操作系统判定:
Windows: WIN32
Linux: linux
Solaris: __sun
编译器判定:
VC: _MSC_VER
GCC/G++: __GNUC__
SunCC: __SUNPRO_C和__SUNPRO_CC

二、头文件防卫式声明

在头文件添加宏定义的判断,即防卫式声明,避免头文件引用时的重复问题。

1.

#pragma once //在有此标识的头文件仅会被编译器包含一次

2.

#ifdef _somefile.h
#define _somefile.h
....//声明、定义语句
#endif

两者的区别:

#ifdef:由语法提供支持,针对代码片段注意不能同名宏,编译时间长,可跨平台
#pragma:由编译器提供保证,针对整个文件,编译速度较快,但头文件多次拷贝仍会包含,且无法支持跨平台与版本较旧的编译器