A、重载函数
一、定义
函数不能仅仅基于不同的返回类型来实现重载。
record lookup(Phone);与record lookup(const Phone);是重复声明,而不是函数的重载。因为这在于实参传递的方式,复制形参时并不考虑形参是否为const,函数操纵的只是副本。但是对于指针和引用的则不同,const和非const是函数重载。
二、类型提升与转换
参考资料:http://learn.akae.cn/media/ch15s03.html
1、类型转换的匹配劣于类型提升的匹配
2、没有哪个标准的转换比其他标准的转换具有更高的优先级
3、对于数值小的的实参值(例如5或者char型数据),int型版本都是优于short型版本的匹配
3、无法将数值型值传递给枚举类型的形参,但可以将枚举值传递给整形形参,例如
enum token {ILINE=12; VIRTUAL=13};
void ff(int);// ff(LINE)是正确的,无法调用 void ff(int)
void ff(token);//ff(5)是错误的,无法调用 void ff(token)
4、const引用和指针的重载
const对象为实参,只能匹配const类型的形参
非const对象为实参,既可以匹配const类型的形参,也可以匹配非const类型的形参,但是非const类型为最佳匹配,因为匹配为const类型需要进行类型转换。
3、指向重载函数的指针
指针的类型必须与重载函数的一个版本精确匹配,如果没有精确匹配的函数,则对该指针的初始化或者复制都是错误的
B、内联函数
一、内联函数使用方法:
关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用,也就是说inline是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。 正确使用方法:
void Foo(int x, int y);
inline void Foo(int x, int y) // inline 与函数定义体放在一起
{
…
}
在内联函数内不允许用循环语句和开关语句。如果内联函数有这些语句,则编译将该函数视同普通函数那样产生函数调用代码,递归函数(自己调用自己的函数)是不能被用来做内联函数的。内联函数只适合于只有1~5行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,所以也没有必要用内联函数实现。
二、宏定义和内联函数的区别
1、宏定义是预处理器在代码优化时直接替换的,而内联函数是在编译期间插入代码,宏定义替换比内联函数执行得早。
2、宏定义是简单的替换,并不进行类型检查,因此安全性不高。内联函数类似于普通函数,会进行类型检查
3、所有在类的声明中定义的函数将被自动认为是内联函数。
4、C++ 语言的函数内联机制既具备宏代码的效率,又增加了安全性,而且可以自由操作类的数据成员。所以在C++ 程序中,应该用内联函数取代所有宏代码,“断言assert”恐怕是唯一的例外。assert是仅在Debug版本起作用的宏,它用于检查“不应该”发生的情况。为了不在程序的Debug版本和Release版本引起差别,assert不应该产生任何副作用。如果assert是函数,由于函数调用会引起内存、代码的变动,那么将导致Debug版本与Release版本存在差异。所以assert不是函数,而是宏。
三、C++中,什么时候函数不能声明为内联函数?
如果在类中的所有虚函数都内声明为内联函数,启发式算法就会失败,大多数基于启发式算法的编译器会在每个使用它的object文件中生成一个类的vtbl。在大型系统里,这会导致程序包含同一个类的成百上千个vtbl拷贝!大多数遵循这种启发式算法的编译器会给你一些方法来人工控制vtbl的生成,但是一种更好的解决此问题的方法是避免把虚函数声明为内联函数。
四、宏和函数的区别:
1. 宏做的是简单的字符串替换(注意是字符串的替换,不是其他类型参数的替换),而函数的参数的传递,参数是有数据类型的,可以是各种各样的类型.
2. 宏的参数替换是不经计算而直接处理的,而函数调用是将实参的值传递给形参,既然说是值,自然是计算得来的.
3. 宏在编译之前进行,即先用宏体替换宏名,然后再编译的,而函数显然是编译之后,在执行时,才调用的.因此,宏占用的是编译的时间,而函数占用的是执行时的时间.
4. 宏的参数是不占内存空间的,因为只是做字符串的替换,而函数调用时的参数传递则是具体变量之间的信息传递,形参作为函数的局部变量,显然是占用内存的.
5. 函数的调用是需要付出一定的时空开销的,因为系统在调用函数时,要保留现场,然后转入被调用函数去执行,调用完,再返回主调函数,此时再恢复现场,这些操作,显然在宏中是没有的.宏占用了空间,而函数的调用占用了时间。