C++和C语言还有一些不同。
1、关于函数的参数
C语言有一些不好的使用方式。比如:如果一个函数没有参数,那么这个函数可接受任意个参数。如下代码可以编译通过:
void func(){}
int main()
{
func(12,13);
return 0;
}
C语言中无参函数是用void填充的,如:void func (void) {}。而且C语言中函数参数是可以没有类型的。
在C++中,如果函数没有参数,认为是无参函数,不可以传参,如void func () {}等价于void func (void) {}。C++中函数参数必须要有类型。
2、新的数据类型(bool类型)
bool类型的变量值只有两种,true和false,true值为1,false为0。用0来表示false,非0表示true。
要注意的是,在运算中,bool类型变量只要值不为0,就是1。bool类型变量可以自加操作(++),但不能自减操作(--)。如:
bool b = true;
int a = 1;
b = a - 2;
b++;
printf ("b = %d\n",b);
编码中,我们一般用这种方法判断真假,而不是和1或者0比较:
if(b){} //判断是否为真
if(!b){} //判断是否为假
3、三目运算符(?:)
C语言中三目运算符表达式返回的是值,不是变量,所以不能作为左值来使用。
比如(a>b?a=100:b=100);只能写成*(a>b?&a:&b) = 100;。
C++中三目运算符表达式可以作为左值使用,因为表达式返回的是变量。上式可以写成(a>b?a:b) = 100;。
其实在C++编译器内部,是将式子转换为类似*(a>b?&a:&b) = 100;的形式来执行的,因此,三目运算符如果要作为左值使用,返回值的表达式中必须没有常量,因为常量没办法取地址,如这种写法就是错误的:(a>b?a:10) = 100;。
4、const关键字
C语言中,const修饰变量,变为只读变量,本质上还是一个变量,不是常量。
C++中,const修饰变量后,变量就变成了常量,所以可以用const去定义常量。
C++中常量是放在一个常量表中(不会在定义时,像变量一样开辟一个空间),常量表由编译器维护。
常量是没有办法取地址的,但是在C++中,对常量取地址并不会出错,如下面这个情况:
const int a = 100;
int *p = (int *)&a;
printf ("*p = %d,p = %p\na = %d,&a = %p\n",*p,p,a,&a);
这是为什么呢?原来,当编译器检测到要对const常量进行取地址操作时,它会为此常量分配内存,但是这个内存不会被该常量使用,而是被指向此块内存的指针使用。涉及到此常量名的地方还是用常量表中的值替换。如下:
const int a = 100;
int *p = (int *)&a;
printf ("*p = %d,p = %p\na = %d,&a = %p\n",*p,p,a,&a);
*p = 20;
int b = a;
printf ("*p = %d,a = %d,b = %d\n",*p,a,b);
其实,C++中的const常量就是为了取代宏常量的。
define宏在预编译阶段处理,这样编译阶段就看不到此符号,产生错误也不会报该符号的错,而是替换的值的错,不利于调试时寻找错误。而const常量会在编译阶段处理。
宏只做简单替换,不会进行类型检查和作用域的检查,宏的作用域从定义位置到文件结束都可以使用,除非用#undef撤销。而const常量会进行类型检查和作用域的检查,作用域在当前的大括号内。
宏可能会开辟多次空间,有多个备份,而const常量只定义一次。
5、inline关键字
说到宏,那就要提到宏函数,宏函数是一种完全替换,在于编译阶段处理,可以避免调用函数时的出入栈、跳转和返回的开销(此开销并不大)。不过宏函数没有函数参数、返回值、作用域的检测,而且形式上也与一般函数不相同,使用时会比较麻烦。比如定义时需要这样:
#define MAX(a,b) ((a)>(b)?(a):(b))
如果少了这些括号,在某些情况下(比如参数是个表达式或者连在一起调用)就会达不到我们预期的效果,如下(预期结果是400):
#define MAX(a,b) a>b?a:b
int a = 10;
int b = 20;
printf ("max*max = %d\n",MAX(a,b)*MAX(a,b));
当然定义正确了,有时也会出问题(预期结果是21):
#define MAX(a,b) ((a)>(b)?(a):(b))
int a = 10;
int b = 20;
printf ("max*max = %d\n",MAX(++a,++b));
C++中提供了内联函数来替换宏函数(工作方式与宏函数类似,是一种非完全替换的函数体替换)。普通函数之前加关键字inline可以变成内联函数。需要注意的是inline必须在函数定义的时候修饰,和函数声明放一起是被忽略的。如下:
inline int func(int a,int b)
{
return a+b+a+b;
}
int main()
{
int a = 10;
int b = 20;
printf("a+b+a+b = %d\n",func(++a,++b));
return 0;
}
内联函数在编译阶段处理,会进行函数参数、返回值、作用域的检测(和函数非常像)。inline修饰后,会向编译器请求在调用该函数时进行函数体的替换,编译器可能会拒绝请求,这时就作为普通函数。如果内联成功,编译成功后,代码是没有这一段函数的原代码的。
想要内联成功,就要注意以下点:
函数体不要过长,最好不要超过5行;函数体不能有循环语句和复杂的if语句。(其实这也适用于宏函数,不然占空间太大,反而有反效果,毕竟函数调用的开销并不大)。
由于内联函数是做一个替换,所以没有函数入口,也不能对内联函数进行取地址操作。内联函数也存在常量表中。