const变量和内联函数教学方法的探讨
2021-09-27王晓东
摘 要:const变量和内联函数是C++语言特有的语法,其功能和使用方法与C语言的宏定义有很多相似之处。本文简述了const变量和内联函数的功能与使用方法,通过与宏定义对比教学,引导学生在掌握了宏定义的基础之上,更深刻地理解const变量和内联函数的特点。
关键词:const变量;内联函数;宏定义;教学
一、引言
C++语言完全兼容C语言,具有C语言的全部功能。单纯就程序语法的学习而言,如果已经学习了C语言,那么再学习C++会轻松一些,只需要重点学习C++新增的语法知识即可,例如类、对象和继承等等。const变量和内联函数也是C++新增的语法,其功能和使用方法与C语言的宏定义有很多相似之处,但是又有宏定义所不具备的优点。在C++语言授课中有意识地与C语言的宏定义对照学习,通过引导学生进行对比分析,体会C++语法的优点,从而有效掌握新增知识点。
二、const变量
变量是程序运行期间,其值可以改变的量。变量有名字,实际代表内存中某一段存储空间,其中可以存放数据即变量的值,存储空间的大小由变量的数据类型决定。在C++程序中,所有的变量在使用之前都必须要定义。变量的定义主要是指出变量的名称,确定变量的类型,并让系统为其分配相应的内存空间。变量定义语句的一般形式为:
类型 变量名1,变量名2,……;
const变量又称为只读变量,其定义形式与普通变量极为相似,只不过是在数据类型的前面加上const而已。例如:
const float PI=3.14;
const变量必须在定义的时候立刻初始化,而且在程序执行期间,其值不能够被修改。在本例中PI用来存放圆周率π的值,它的值固定为3.14。C++语言的const变量其用法与C语言的符号常量,颇有相似之处。所谓符号常量,就是用标识符表示的常量。C语言允许用宏定义的方式描述符号常量,例如:
#define PI 3.14
宏定义是指用#define开头的预处理命令,有无参数和有参数两种形式。它的作用是用一个标识符来代表一个字符串,标识符称为宏名,字符串称为宏体。在编译预处理时,把程序中该宏定义之后的所有宏名都用宏体替换,这称为宏替换。在本例中PI称为宏名,3.14称为宏体。在程序中出现标识符PI,即表示常量3.14。
表面上看const变量的实际效果似乎等同于符号常量,所以往往有学生会提问,既然用宏定义的方式就可以描述符号常量,为什么C++语言还要引入const变量呢?这时就需要给学生解释强类型语言的概念。宏定义只是在程序编译之前做简单的字符替换,即用3.14替代PI,并不进行数据类型的检查,这样有可能会出现一些编译阶段所无法发现的错误;而const变量除了其值不能被修改之外,其它方面完全与变量一样。C++作为一种强类型语言,在操作之前,编译器会对const变量进行类型合法性检查,从而有可能在编译阶段就发现一些错误。这样做既降低了程序调试的难度,又提高了程序的可靠性。就此可以乘势建议学生在C++程序中,尽量用const变量,少用宏定义描述的符号常量。
三、内联函数
函数是C程序实现模块化结构的主要手段,也是C++程序描述对象行为的主要方法。函数可以提高程序代码的可读性和重用性,便于调试和维护。但是函数调用也增加了额外的系统开销,例如在程序執行转移时,为函数的变量分配内存的存储空间,保存主调函数的执行点(现场)以及一些参数和寄存器的值等。C++语言允许程序员将那些代码较短、调用频繁的函数定义为内联函数,以提高程序运行的效率。内联函数的作用是,在调用它时并不发生通常的程序执行转移,而是把函数体的语句插入到函数调用处。inline是C++语言的关键字,用来定义内联函数。例如定义一个函数area,其功能是计算正方形的面积。代码如下:
inline float area(float x)
{
return x*x;
}
从编写程序的角度来看,内联函数的定义和调用与普通函数的定义和调用几乎没有什么差别,只不过内联函数在定义时多了一个inline关键字而已。程序运行时内联函数并没有发生真正的函数调用,而是类似于粘贴动作一样,自动把函数体插入到每一个函数调用的位置。因此内联函数是以牺牲程序的空间为代价,来换取程序运行的时间。如果学生已经学习过C语言的带参数的宏定义,一定会发现它与内联函数非常相似。表面上看都具有函数的形式,有形参,使用时也是插入到调用之处等等。例如:
#define area(x) x*x
定义了一个带参数的宏定义,在程序中如果出现area(3.2),将被自动替换为3.2*3.2。通过内联函数与带参数的宏定义的对比学习,学生可能会问,既然带参数的宏定义与内联函数如此相似,为什么C++语言还要提供内联函数这种机制呢?这就需要教师进行深入分析,内联函数虽然执行机制与带参数的宏定义很相似,但它毕竟是C++的函数,调用时C++编译器会对它进行类型检查和参数检查,计算实参的值,并依次赋给形参。而带参数的宏定义在使用时,只是作简单的替换工作,即用宏体替代宏名。这种方式是不进行任何检查的,因而会带来一些隐患。
例如在程序中出现area(1+2),我们预期的结果显然是9。但是替换之后变为1+2*1+2,结果却是5。可能有的学生已经看出来了,只要带参数的宏定义的形参带上括号,就能够避免类似的问题,即写为:#define area(x) (x)*(x)。此时教师可以接着提问,难道这样做了之后,就可以高枕无忧了吗?如果在程序中出现8/area(2),我们预期的结果显然是2。但是替换之后变为8/(2)*(2),结果却是8。进一步启发学生,即可得出结论,实际上要想做到万无一失,只能写成以下形式:#define area(x) ((x)*(x))。因此相比较而言,内联函数没有带参数的宏定义所可能有的副作用,是一种执行效率较高,也较为安全的语法。通过案例对比分析,学生就会较为容易地接受内联函数,并乐于在C++程序中采用。
四、结语
相对类、对象和继承而言,const变量和内联函数并不是C++语言的核心语法。但是通过与C语言的宏定义对比教学中,还是可以让学生深刻理解const变量和内联函数的特点,并逐渐体会C++语言的优点,在程序中熟练运用。
参考文献:
[1] 王晓东. C++程序设计简明教程(第二版)[M].北京:中国水利水电出版社, 2017.
[2] 郑莉. C++语言程序设计[M].北京:清华大学出版社, 2001.
[3] 江义华. C/C++完美演绎[M].北京:中国水利水电出版社, 2001.