1、函数基础
典型的函数定义包括:返回类型、函数名、由0个或多个形参组成的列表以及函数体。
2、参数传递
形参初始化的机理和变量初始化一样。
有两种方式:引用传递和值传递
2.1 传值参数
当形参是非引用类型时,形参初始化和变量初始化一样,将实参的值拷贝给形参。
指针形参
当执行指针拷贝操作时,拷贝的是指针的值,拷贝之后,两个指针是不同的指针。但通过指针可以修改它所指的对象。
2.2 传引用参数
使用引用避免拷贝
拷贝大的类类型对象或者容器对象比较低效,甚至有的类类型根本就不支持拷贝操作。当某种类型不支持拷贝操作时,函数只能通过引用形参访问该类型的对象。
使用引用形参返回额外信息
2.3 const形参和实参
当用实参初始化const形参时会忽略顶层const。因此,当形参有顶层const时,传给它常量对象或者非常量对象都是可以的。
1
2
3
void fun1(const int i){.......}
void fun2(int i){.....}
上述两个函数不能算是重载,两个函数是一样的,程序会报错,fun2重复定义了fun1.
指针或引用形参与const
可以使用非常量初始化一个底层const对象,但是反过来不行。同时一个普通的引用必须用同类型的对象初始化。
图1
尽量使用常量引用2.4 数组形参数组有两个重要的特性:不允许拷贝使用数组时会转换成指针尽管不能以值传递的方式传递数组,但是可以将形参写成类似数组的形式12345void print(const int*);void print(const int[]);void print(const int[10]); 以上三种形式的声明等价NOTE:当函数不需要对数组元素执行写操作的时候,数组形参应该是指向const的指针。只有当函数确实要改变元素值的时候,才把形参定义成指向非常量的指针。当数组作为函数形参时,因此应该提供一些额外信息来确定数组的确切尺寸,管理数组形参有三种常用的技术:使用标记指定数组长度 要求数组本身包含一个结束标记。例如C风格字符串以空字符结尾。使用标准库规范 传递指向数组首元素和尾元素的指针。1234567void print(const int *beg,const int *end){ while(beg!=end) { cout<<*beg++
print(begin(arr),end(arr));显式传递一个表示数组大小的形参 专门定义一个表示数组大小的形参。12345void print(const int ia[], size_t size); int j[]={0,1}; print(j, end(j)-begin(j));数组引用形参 形参可以是数组的引用,此时,引用形参绑定到对应的实参上,也就是绑定到数组上。12345678void print(int (&arr)[10]){ for(auto elem:arr) { cout<
图2
lnitializer_list和vector一样都是模板类型,不同的是initializer_list对象中的元素永远是常量值,不能改变。12345678void error_msg(initializer_listls){ for (auto beg = ls.begin(); beg != ls.end(); ++beg) { cout << *beg << " "; } cout << endl;}error_msg({ "hello" });error_msg({ "hello!", "world!!" }); //注意值的传递要放在花括号里省略符形参 省略符形参是为了便于C++程序访问某些特殊的C代码而设置的。通常,省略符形参不应用于其他目的。省略符形参只能出现在形参列表的最后一个位置。实参类型不同,使用可变参数模板3、返回类型和return语句3.1 无返回值函数 返回类型是void类型的函数3.2 有返回值函数值是如何被返回的 返回一个值的方式和初始化一个变量或形参的方式完全一样:返回的值用于初始化调用点的一个临时量,该临时量就是函数调用的结果。 不要返回局部对象的引用或指针返回类类型的函数和调用运算符1auto sz=getstring().size(); //getstring返回的string对象再调用size函数 引用返回左值调用一个返回引用的函数得到左值,其他返回类型得到右值。 列表初始化返回值函数可以返回花括号包围的值的列表。1234vectorprocess(){ return {"ni","hao"};} 递归如果一个函数调用了它自身,不管这种调用是直接还是间接的,都称该函数为递归函数。1234567int factorial(int val){ if(val>1) return factorial(val-1)*val; return 1;}求1x2x3x4...... 3.3 返回数组指针因为数组不能被拷贝,所以函数不能返回数组。不过,函数可以返回数组的指针或引用。最直接的方法是使用类型别名12typedef int arrT[10];using arrT=int[10]; 声明一个返回数组指针的函数123int arr[10]; //arr是一个含有10个整数的数组int *p1[10]; //p1是一个含有10个整型指针的数组int (*p2)[10]=&arr; //p2是一个指针,其指向一个有10个整数的数组 如果要定义一个返回数组指针的函数,则数组的维度必须跟在函数名字之后,并且函数的形参列表应该先于数组的维度。1int (*func(int a,int b))[10]; 此函数返回的是一个指向有10个整数数组的指针。 使用尾置返回类型任何函数的定义都能使用尾置返回,但是这种形式对于返回类型比较复杂的函数最有效,比如返回类型是数组的指针或引用。尾置返回类型跟在形参列表后面并以一个->符号开头。为了表示函数真正的返回类型跟在形参列表之后,我们在本应该出现返回类型的地方放置一个auto。1auto func(int i)->int (*)[10]; 使用decltype4、函数重载如果同一作用域内的几个函数名字相同但形参列表不同,称为函数重载。注意必须是形参列表不同,仅仅只是返回类型不同不可以称为重载。重载和const形参顶层const不影响传入函数的对象。一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开来。12345int f1(int i);int f1(const int i); //不构成重载,重复声明了f1 int f2(int *i);int f2(int *const i); //不构成重载,重复声明了f2但底层const不同,可以构成重载12345int f1(int &i);int f1(const int &i); //重载,新函数 int f2(int *i);int f2(const int *i); //重载,新函数NOTE:最好只重载那些确实非常相似的操作。const_cast和重载const_cast在重载函数的情景中最有用。1234567891011const string &shorterString(const string &s1, const string &s2){ return s1.size() <= s2.size() ? s1 : s2;} string &shorterString(string &s1, string &s2){ auto &r = shorterString(const_cast(s1), const_cast(s2)); return const_cast(r);
作者:久伴必知情深
链接:https://www.jianshu.com/p/27c6f539030d



