函数新特性、内联函数、const详解
一、函数回顾与后置返回类型
函数定义中,形参如果在函数体内用不到的话,则可以不给形参变量名字,只给其类型。
函数声明时,可以只有形参类型,没有形参名
把函数返回类型放到函数名字之前,这种写法,叫前置返回类型。
C++11中,后置返回类型,在函数声明和定义中,把返回值类型放到参数列表之后。
前面放auto,表示函数返回类型放到参数列表之后,而放在参数列表之后的返回类型是通过 -> 开始的。
1 #include <iostream> 2 using namespace std; 3 4 void func123(int , int); // 函数声明(函数原型); 5 void func123(int a,int b)// 函数实现 6 { 7 return; 8 } 9 10 // C++11后置返回类型 11 auto func(int a , int b) -> void; // 函数声明 12 auto func(int a , int b) -> void 13 { 14 return; 15 } 16 17 inline int myfunc(int testv) // 函数定义前加inline,这个函数为内联函数 18 { 19 return; 20 } 21 22 23 int main() 24 { 25 //函数定义中,形参如果在函数体内用不到的话,则可以不给形参变量名字,只给其类型。 26 func123(12,13); 27 return 0; 28 }
二、内联函数
在函数定义前加关键字inline,导致该函数变成内联函数。
函数体很小,调用很频繁,引入inline(内联函数)
(1)inline影响编译器,在编译阶段对inline这种函数进行处理,系统尝试将调用该函数的动作替换为函数本体。通过这种方式来提升性能。
int abc = myfunc(5); //==> int abc = 1;
(2)inline只是我们开发者对编译器的一个建议,编译器可以尝试去做,也可以不做,这取决于编译器的诊断功能。
(3)内联函数的定义放到头文件中。这样需要用到这个函数的时候能够通过#include 把这个内联函数的源代码#include进来,以便找到这个函数的本体源代码并尝试将该函数的调用替换为函数体内的语句。
优缺点:
代码膨胀的问题;所以内联函数函数体尽量要小。
注意:各种编译器对inline的处理各不相同,inline函数尽量简单,代码尽量少。循环,分支,递归调用尽量不要出现在inline函数中,否则的话编译器很可能会因为你写这些代码的原因拒绝让这个函数称为inline函数。
1 constexpr int mf() 2 { 3 // ..写的特别简单 4 }
constexpr函数可以看成为更严格的内联函数。
#define 宏展开也类似于inline(内联函数)。
三、函数杂合用法总结
(1)函数返回类型为void,表示函数不返回任何类型。但是我们可以调用一个返回类型为void的函数,让它作为另一个返回类型是void的函数的返回值。
1 void funa(){} 2 void funb() 3 { 4 return funa(); 5 //return; 6 }
(2)函数返回指针和返回引用的情况
1 //返回指针 2 int* myfunc() 3 { 4 // 存在隐患 5 int tmpval = 9; 6 return &tmpval; // 这个地址出了这个函数,地址被系统回收。 7 } 8 9 10 int main() 11 { 12 int *p = myfunc(); 13 *p = 6; // 你向一个不存的地址写了数据 14 } 15 16 //返回引用 17 int& myfunc() 18 { 19 int tmpval = 9; 20 cout << &tmpval << endl; 21 return tmpval; // 也存在隐患 返回已经回收了地址的引用 22 } 23 24 int main() 25 { 26 int& k =myfunc(); 27 cout << &k << endl; 28 k = 10; //你向一个不存的地址写了数据 29 30 // 返回值 31 int x = myfunc(); // 这种写法是OK的 32 cout << &x << endl; 33 x = 20; 34 35 return 0; 36 }
(3)不带形参的函数定义()、(void)
1 int myfunc(void) 2 { 3 return 1; 4 }
(4)如果一个函数如果不调用的话,则该函数只有声明部分,没有定义部分。
int a();
int b();
int c();
(5)普通函数定义只能定义(.cpp)一次,声明可以声明(.h)多次。
(6)void func(int& a,int& b); 函数可以通过参数引用来实现返回多个值。
(7)C++中,函数允许同名,但是形参列表的参数类型或者数量必须有明显区别。
void fs(int i);
void fs(float i);
void fs(int i , int b);
四、const char*、char const*、char* const三者的区别
(1)const char* p;
1 int main() 2 { 3 char str[] = “I Love China”; 4 const char* p; // p指向的东西不能通过p来修改(p所指向的目标,目标中的内容不能通过p来改变) 5 p = str; 6 //*p = ‘Y’; // 语法错误 7 p++; 8 9 str[0] = ‘Y’; 10 return 0; 11 }
(2)char const* 与 const char*等价
(3)char* const
1 int main() 2 { 3 char str[] = “I Love China”; 4 char* const p = str; // 定义的时候必须初始化 5 // p一旦指向了一个东西之后,就不能再指向其他东西了。 6 *p = ‘Y’; // 但是可以修改p指向的目标中的内容 7 8 //char const* const p = str; 9 const char* const p =str; // p的指向不能变,p指向的内容也不能通过p来改变 10 11 int i = 100; 12 const int& a =i // 代表a的内容不能通过a自己来修改; 13 i=1000; 14 //a = 50; // 不合法 15 16 //int &b = 3; // 错误 17 const int &b = 3; // OK 18 //b = 45; // 错误 19 cout << b << endl; 20 21 return 0; 22 } 23 24
五、函数形参中带const
把形参写成const的好处:
(1)可以防止你无意中修改了形参值导致实参值无意被修改;
(2)实参类型可以更灵活。
1 struct student{int num;}; 2 void fs(const student &stu) 3 { 4 //stu.num = 1010; // 加const stu不可以修改 5 } 6 7 void fs2(const int i) 8 { 9 //i=100; // 不可以修改 10 } 11 12 13 int main() 14 { 15 student student1; 16 student1.num = 100; 17 fs(student1); 18 cout << student1.num << endl; 19 return 0; 20 }