C++预处理器,typeid与强制类型转换专题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
本文作者:黄邦勇帅(编著)(原名:黄勇)
本文是属于学习C++的附加内容,本文主要讲解了预处理器,#define,#if指令,typid的作用与使用方法,C++使用的四种强制类型转换,其中对dynamic_cast和reinterpret_cast两种转换作了深入细致的讲解。本文由浅入深易学易懂,内容全面,是学习C++的不错的资料,相信本文能给读者带来对C++的重新认识和更深入的理解。
本文使用的是x86机器(主流计算机都是x86机器),windows xp操作系统,VC++2010编译器进行讲解的。
本文内容完全属于个人见解与参考文现的作者无关,限于水平有限,其中难免有误解之处,望指出更正。
声明:禁止抄袭,复印,转载本文,本文作者拥有完全版权。
主要参考文献:
1、C++.Primer.Plus.第五版.中文版[美]Stephen Prata著孙建春韦强译人民邮电出版社 2005年5月
2、C++.Primer第四版.中文版 Stanley B.Lippman、Barbara E.Moo、Josee Lajoie著李师贤、蒋爱军等译人民邮电出版社 2006年3月
3、C++.Primer第三版.中文版 Stanley B.Lippman、Josee Lajoie著潘爱民、张丽等译中国电力版社 2002年5月
4、《C++程序设计》作者谭浩强清华大学出版社 2004年6月
5、《C++程序设计语言》特别版[美]Bjarne Stroustrup著裘宗燕译机械工业出版社 2010年3月
第18部分 C++预处理器,typeid与强制类型转换专题(2016-7-14)
(共5页)
1、预处理器:预处理器是编译器把C++代码编译为机器指令之前执行的一个过程,所有的预处理器都以#开头,以便
与C++语句区分开来,#include预处理器指令在前面已经用过不少了
2、注意:预处理器指令必须作为第一个非空白字符,在之前不能有其他语句;而且预处理器之后不能有其他与预处理
器不相关的语句,也就是非预处理器语句必须另起一行。本文把预处理器指令的语法都写在一行上,假设用户已做了正确的格式处理。
一、#define指令
1、#define指令格式:#define 标识符字符序列。比如#define N 3;
1)、表示以后凡是使用到“标识符”的地方都被后面的“字符序列”替换。注意该语句不以分号结束。
2)、编译器不会对“字符序列”进行类型检查。也就是说字符序列可以是任意的字符。
3)、语句中的字符序列可以是任意的字符序列,而不仅仅是数字,比如#define PI HYONG这样的话在使用PI时就
会用HYONG来替换掉PI,替换之后HYONG可能会是一个未定义的标识符。
2)、示例:#define N 3
1)、表示以后使用到符号PI时都会被置换为3,比如int a[N];定义大小为3的数组。
2)、虽然N看起来和变量一样,但N和变量没有任何关系,N只是一个符号或标志,在程序代码编译前该符号
会用一组指定的字符来替换。
3)、可以看到,N被3置换后,相当于拥有常量的性质,但在C++中最好是用const来声名常量,比如const long
double PI=3.1416;。
2、怎样把预处理指令放在多行上:其方法为使用续行符符号”\”,该符号应在上一行的最后一个字符。
比如#define m \
kkielfml
3、删除#define定义的标志的语法:#define 标识符
在#define语句中,不为标识符指定置换字符串就表示该标识符被删除了。比如#define PI表示在程序中该语句后面删除所有的PI标识符。比如int a=PI;则PI不会替换为任何东西,语句int a=PI相当于是int a=;所以程序出错。
4、使用#undef取消#define的定义的语法:#undef 标识符
表示取消在#undef后定义的“标识符。标识符被取消后,就不能再使用该标识符了。
5、带参数的#define的格式:#define 标识符(参数列表) 置换字符串
#define f(v) cout<<(v)< 6、重点:使用#define只能对标识符进行简单的置换,也就是他会将标识符直接替换为后面表示的字符序列,而不会 进行算术优先级或类型的检查。比如#define f(m,n) m*n 如果有调用f(4+2, 3);则该语句会被简单的替换为4+2*3这与我们所希望的(4+2)*3不一致,要解决这个问题就是给参数加上括号,比如#define f(m,n) (m)*(n) 8、使用字符串作为#define参数:比如#define m “kdi”如果有语句cout< 做#define m dki cout<<”m”;不能在标志符前加上双引号以试图输出字符串dki,这样只会输出字符串m,因为程序会把”m”解释为一个字符串,而不会把它解释为cout<<”dki”。 9、把#define参数指定为字符串:其方法是在参数前加上符号”#”,比如#define f(m) cout<<#m 如果这时有f(dikl);则程 序将会转换为cout<<”dikl”,最后输出字符串dikl。这里要注意的是该方法只能用于参数,而不能用于其他地方,比如#define m #kidkl这样就是错误的,这里试图用m来代替字符串”kidkl”,这是不成功的,正确方法为#define m “kidkl” 二、逻辑预处理器指令: 1、逻辑#if指令:该指令原理与条件语句if相同,如果测试为真就执行后面的语句,如果为假则跳过后面的语句。该 指令有两种用法,其一可以用#if指令测试某个符号以前是否用#define指令定义过,这是最常用的用法,其二可以用来测试某个条件表达式是否为真。 2、#if指令用法一:测试某个符号是否以前用#define定义过,共有以下几种情形 1)、#if指令语法形式一: 语法为: #if defined 标识符…. #endif //注意关键字defined比define多一个字母d。 缩写形式为:#ifdef 标识符….#endif 意义:表示如果指定的“标识符”已被#define定义,则中间的语句就包含在源文件中,如果该标识符还未被#define定义,则跳过#if和#endif之间的语句,该语句以#endif结束。 2)、#if指令语法形式二: 语法:#if !defined 标识符…..#endif //注意关键字defined比define多一个字母d。 缩写形式为:#ifndef 标识符…..#endif 意义:表示如果指定的标识符没有定义,则把#if和#endif之间的语句包含在源文件中,如果标识符已定义则跳过#if和#endif之间的代码,系统常使用该语句防止头文件被多次包含, 3)、示例1:#define N //定义标识符N,此例可以不需要指定值。 void main(){ //注意:预处理器指令必须作为第一个非空白字符,因此不能在”{“后使用预处理器指令。 #if defined N //若标识符N被定义则执行以下语句,注意预处理器指令结束后必须另起一行(即必须输入换行符)。 cout<<"A"< #endif//注意:预处理器指令必须另起一行进行输入。 #ifndef N //若标识符N未被定义则执行以下语句 cout<<"B"< #endif } //注意:大括号必须另起一行,不能在#endif预处理器指令的后面 3、防止头文件被包含多次的语法: #ifndef HY #define HY语句#endif //此处应使用正确的回车换行符 说明:程序在开始遇到标识符HY时没有被定义,这时执行后面的语句,并使用#define定义标识符HY,在第二次被使用时则标识符HY已经被定义,这时就不会执行后面的语句了,从而防止了同一头文件被包含多次的情 况。这里要注意,使用#define后面定义的标识符可以不需要值。 4、#if指令用法二:测试某个表达式的值是否为真,其语法格式为:#if 常量表达式….#endif,注意常量表达式的求值 结果应是整数常量表达式,比如#if a=2 …. #endif测试a的值是否为2,如果为2则执行#if与#endif之间的语句。 5、多个#if选择块:和常规的if语句一样#if也有对应的#else和#elif语句,比如#if a=3 …. #else …. #endif表示如果a=3 则执行if后面且在#else前面的语句,如果为假则执行#else与#endif间的语句。#elif用来实现多个选择,该语句和常规语句的else if相似,比如#if a=1 …. #elif a=2 …. #elif a=3…. #else …. #endif表示,如果a=1则执行#if后的语句,如果a=2则执行该条件后的语句。 三、RTTI运行时类型识别 使用以下函数需要包含头文件 注意:有些编译器需要把RTTI的特性打开才能使用,比如VC++2010就有这项设置,位于项目/属性然后展开C/C++选项卡选择“语言”,在右侧找到“运行时类型识别”,然后选是。 1、静态类型与动态类型:静态类型指的是对象(包括指针和引用)在声明时的类型,动态类型指的是当前对象(包括指针 和引用)实际指向的类型。比如B mb; A* p=&mb; 则p的静态类型是A*,而动态类型是B*,详见《C++继承,虚函数与多态性专题(修订版)》 2、RTTI运行时类型识别:使用运行时类型识别的主要作用是让我们能获得指向父类的指针实际所指向的子类的类型。 C++使用两个操作符来实现RTTI,即typeid和dynamic_cast,本小节介绍typeid操作符,dynamic_cast是强制类型转换运算符,位于下一小节。 3、typeid操作符形式:type_info& typeid(object) 其中object是任何类型的对象,也可以是一个类型。typeid反回type_info 类型的引用。 4、通过引用typeid反回的type_info的成员函数,可以使用typeid获得对象类型的名称、判断两个类型是否相等等操