内联函数,函数的缺省值,函数重载,右值引用
内联函数内联函数函数名前加inline内联函数与普通函数//普通函数 int add(int a,int b) { return ab; } int main() { int retadd(10,20); coutretendl; return 0; } //内联函数函数名前加inline int inline add(int a,int b) { return ab; } int main() { int retadd(10,20);//展开后既是ab语句 coutretendl; return 0; }内联函数的特点1.函数功能体积小2.逻辑简单3.在调用位置上编译时 自动展开在编译时直接将此函数的功能语句嵌入到此处int subint a,int b{return a-b;}问调用sub函数后系统做了哪些事1保护现场2创建函数的空间栈3传递参数入栈实参是从右边开始一一入栈的4执行函数体的功能5函数返回后恢复现场inline函数与普通函数的区别inline函数相对于普通函数则是以空间换时间提高运行效率。注意事项1.inline 对编译器而言只是建议编译器会自动优化2.inline 不建议声明和定义分开inline 函数没函数地址链接时有可能失效3.不是所有函数都适合inline如果函数执行小于系统开销适合inline如果函数执行大于系统开销不适合inline思考面试题内联函数与有参宏的区别1.内联函数在编译时展开有参宏在预编译时展开。2.内联函数是嵌入到代码中展开有参宏是文本替换。3.内联函数有类型检查、语法判断宏只是替换。函数的缺省值在C中函数的形参可以存在默认值或者缺省值函数调用时可以不需要实参采用默认值即可int add(int a, int b1, int c2) { return abc; } int main() { //a1, b,c使用默认值 coutadd(1)endl; //输出4 //a1,b20, c使用默认值 coutadd(1,20)endl; //输出23 //a1,b8,c9 coutadd(1,8,9)endl; //输出18 return 0; }注意1.带有默认值或缺省值的函数只需要在声明的位置指定缺省值即可exrern int add(int,int,int); //exrern int add(int,int2,int9); int main() { coutadd(10,20,30); //coutadd(10); return 0; } //声明时需要缺省值定义时则不需要了 int add(int a,int b,int c) { return abc; }2.在某一个形参以上指定了缺省值后其后的所有参数都必须存在缺省值//void rndNum(int n, int min_ 0, int max_)是错的 void rndNum(int n, int min_ 0, int max_10) { n n rand()%(max_-min_1)min_; } int main() { srand(time(NULL)); int a 0; for (int i 0; i 10; i) { rndNum(a); cout a a endl; } return 0; }3.缺省值不限于常数表达式可以是任意表达式如函数等。思考函数调用的时候实参个数可以与形参的个数不同吗c语言不行c可以。C 和 C 的普通函数实参个数必须与形参个数严格匹配不存在 “直接允许个数不同” 的情况C 通过「默认参数」省略实参用默认值、「函数重载」匹配不同形参的同名函数实现 “调用时实参个数看似不同”这是语法扩展而非打破 “个数匹配” 原则。函数指针作为缺省参数的核心要求缺省参数的函数指针类型必须与形参的函数指针类型完全匹配缺省参数仍需遵循 从右往左连续指定 的规则可以用函数名自动退化为函数指针或nullptr作为缺省值推荐前者更安全函数重载针对多个相同名的函数。只有c可以。函数名相同参数表不同个数不同个数相同时类型不同对于多个具有相同的功能不同函数名优化可以让函数名相同。对于重载的函数调用时依据实参个数、数据类型等查找或匹配相应的函数。注意缺省值不构成函数重载//两个add重复定义类型相同参数个数形同类型相同 int add(int a,int b) { return a100; } int add(int a,int b9) { return ab; } int main() { add(10);//是错的缺省值不构成函数重载 }const和volatile修饰的相关注意(volatile关键字告诉编译器不要优化为常数)1.const和volatile修饰非指针类型时不构成函数重载//以下不是函数重载 int add(int a, int b) { return a b; } int add(const int a, volatile int b) { return a b; }2.const和volatile修饰指针类型时构成函数重载//是重载 int add(const int* a,volatile int* b) { return *a *b; } int add(int* a, int* b) { return *a *b; } //是重载 int add(int *a,int *b); int add(const int *a,int * const b); int add(int * const a,const int *b);为什么C支持函数重载而C不支持呢回答一记住这个就行C函数之所以可以重载是因为编译器存在名字粉碎机制。名字粉碎机制函数名在编译时依据函数的调用约定、函数名、返回值类型、参数表等信息修改为新的名称。回答二C 编译器仅用函数名生成符号无法区分参数不同的同名函数C 通过 “名字修饰” 将函数名 参数列表编码为唯一符号支持重载。函数名的新名称符号格式函数名调用约定名{返回值类型}{参数表类型}Z比如函数类型生成的符号就不同int生成的符号是“H”。__cdecl是C的调用约定C/C函数的默认调用约定是C语言调用约定也是按从右到左压参数入栈函数调用完成后由调用者清栈(管理)。__stdcall是标准调用约定是Pascal程序的缺省调用方式用于Win32APIstdcall中函数采用从右到左的压栈方式函数自己退出时会清空堆栈。__fastcall是快速调用约定主要的特点是快将前2个双字节或更小的参数传入到ECX、EDX寄存器中其它参数也是按从右到左压入栈。函数返回时清理参数所在的内存栈。__thiscall是类成员函数的调用约定仅用于C类的成员函数类成员函数调用时则会将this指针传入到EC寄存器。其他参数也是从右到左压入栈中。extern C{}告诉 C 编译器对花括号内的代码按照 C 语言的规则来编译 / 链接。则不使用C函数名的修改规则。//没有被粉碎 extern C { int __cdecl sub(int a, int b); int __stdcall sub(int a, int b,int c);//不是函数重载是重定义 } int main() { sub(1, 2); return 0; }extern C{}C风格定义函数支持重载缺省值。在C中可以使用。右值引用C11后存在C11引入值的类别左值右值左值有名称具名可取地址的可以出现在赋值语句的左边右值无具名没有名字或不可取地址如10atrue定义右值引用数据类型 引用名 右值右值引用的例子int ar 10; int ar2 10; coutarendl; coutar2endl; //输出的地址不同右值引用有自己的空间注意1.右值引用不能引用变量2.右值引用本身是左值具名可取地址3.可以为右值引用定义左值引用int ar_ref ar2 ;4.右值引用可以--也可以地址变化有左值和右值匹配重载函数的顺序是什么void func(int a){} void func(const int a){} void func(int a){} //测试用例 int x10; func(x);//x是左值不调用第三个先调用第一个其次是第二个 func(20);//20是右值优先调用第三个20是常数其次调用第二个最后调用第三个