一、extern "C"的作用
void foo(int x, int y);
foo函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字用来支持函数重载和类型安全连接。由于编译后的名字不同,C++程序不能直接调用C函数。C++提供了一个C连接交换指定符号extern "C"来解决这个问题。
extern "C"
{
void foo(intx, int y);
}
这就告诉C++编译器,foo是个C连接,应该到库中找名字_foo而不是找_foo_int_int。
二、隐式类型转换导致重载函数产生二义性
void output(int x);
void output(float x);
void main()
{
output(0.5);
}
结果:编译错误,因为数字本身没有类型,编译器不知道该将0.5转换成int还是float。
三、成员函数的重载、覆盖与隐藏
成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名相同;
(3)参数不同;
(4)virtual关键字可有可无。
覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名相同;
(3)参数相同;
(4)基类函数必须有virtual关键字。
隐藏是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数被隐藏(不是重载)。
(2)如果派生类的函数与基类的函数同名,并且参数不同,但是基类没有virtual关键字。此时,基类的函数被隐藏(不是覆盖)。
三、参数的缺省值
缺省值只能出现在函数的声明中,而不能出现在定义体中。
四、运算符重载
Complex operator +(const Complex &a, const Complex &b);
如果运算符被重载为全局函数,那么只有一个参数的运算符叫做一元运算符,二元运算符只有一个右侧参数,因为对象自己成了左侧参数。
如果运算符被重载为类的成员函数,那么一元运算符没有参数,二元运算符只有一个右侧参数,因为对象自己成了左侧参数。
建议将运算符重载为成员函数,= () [] ->只能被重载为成员函数。
不能被重载的运算符:
(1)不能改变C++内部数据类型(如int,float等)的运算符。
(2)不能重载'.',因为'.'在类中对任何成员都有意义,已经成为标准用法。
(3)不能重载目前C++运算符集合中没有的符号,如#,@,$等。一是难以理解,二是难以确定优先级。
(4)对已经存在的运算符进行重载时,不能改变优先级规则,否则引起混乱。
五、函数内联
用内联取代宏,因为内联能避免宏替代时候的一些错误,能进行类型安全检查,或者是自动类型转换,能操作类的私有成员。
在C++程序中,应该用内联取代宏,"断言assert”是唯一的例外。为了不在程序的Debug版本和Release版本引起差异,assert不应该引起任何副作用。如果assert是函数,由于函数调用会引起内存、代码的变动,那么将导致Debug版本与Release版本存在差异。所以assert不是函数,而是宏。
inline必须放在函数定义体前,才起作用。inline void Foo();
定义在类声明之中的成员函数将自动地成为内联函数。
内联会复制代码,使程序的总代码量增大,消耗更多的内存空间。