从C学C++(2)
从C学C++(2)
域运算符
::
双冒号可以构成域标识符,用于访问指定域中的同名变量。如,
用于区分访问全局变量和局部的同名变量
用于表示类成员
new delete 运算符
new
-
类似于C中的
malloc
,用于利用堆空间创建变量, -
但
new
一个新对象的时候,不仅会调用内存分配(operator new),还会调用对应类的构造函数。 -
另外,
new
成功的话,会返回分配的首地址,不成功的话,不会像malloc
一样返回NULL
而是直接抛出异常。int *p = new int(3); // new一个int变量,且初值赋3,()用于赋值初值 char* pStr = new char[50]; //new一个数组,[]用于分配指针(数组)变量,如果new的新数组需要赋初值的话,需要使用for循环挨个赋值。
delete
- 类似于C中的
free
,用于释放堆空间, - 但
delete
一个对象的时候,还先调用对应类的析构函数,再执行释放内存的操作(operator delete)
delete p; //释放new到的对象
delete [] pStr; //如果new的是指针(数组),delete时也需要带上[].
函数重载(overload)
相同的作用域,如果两个函数名称相同,而参数不同,我们把它们称为重载overload。
重载的函数必须有不同的形式:
- 形参数量不同
- 形参类型不同
- 形参顺序不同
- 形参的数量和类型都不同。
静态联合和动态联合
函数重载是静态联合,其实现是在编译时就实现了,通过将不同参数形式的同名函数做名字改编(name managling),不同参数形式的同名函数最终的函数名并不相同,编译器在编译时依靠对参数个数、类型、顺序的识别调用对应的函数。
因此,如果同名函数参数的个数、类型、顺序完全相同但返回值不同是非法的,这不是函数重载,因为编译器进行名字改编后是同一个函数,会报错函数重定义。
动态联合是指在执行的时候才决定使用哪个函数(在类继承中的函数/方法的继承,或者是virtual
指定的虚函数)。
name managling 和extern “C”
C++中默认会对函数进行名字改编(name managling) , 因此,如果和C混合编写时,实际编译时的名字不是我们所写的函数名,为了利于和C混合编写,可以使用 extern "C"
关键字圈定一个环境,这个环境内的函数不会进行名字改变。通常,我们会将C语言中的函数在.h文件中声明时使用extern "C"
进行圈定,这样C语言中的定义和.h的声明可以对应,在CPP文件中调用时也可以找得到。 如下:
#ifdef _cplusplus
extern "C"
{
#endif#ifdef _cplusplus
}
#endif
带默认参数的函数
函数声明或者定义的时候,可以给形参赋一些默认值口调用函数时,若调用时没有给出实参,贝则按指定的默认值进行工作。需要注意的是:
-
函数没有声明时,在函数定义中指定形参的默认值。
-
函数既有定义又有声明时,声明时指定后,定义后就不能再指定默认值。
-
默认值的定义必须遵守从右到左的顺序,如果某个形参没有默认值,则它左边的参数就不能有默认值。
void function(int a, double b=4.5, int c=3); //正确,合法 void function(int a=1, double b , int c=3); //错误,会报错
-
函数调用时,实参与形参按从左到右的顺序进行匹配。
同时需要格外注意的一点是,如果重载函数中带有默认值参数,可能会产生二义性,当编译器不知道该使用哪个函数的时候,就会报错,如下是二义性的一个例子:
int add(int x, int y);
int add(int a=5, int b=6, int, c=7);
//调用add的时候,如果如下只传入两个参数,编译无法判断是第一个函数调用,还是第二个函数调用,最后一个参数使用默认值的情况,所以会报错。
add(5,9);