C++ primer 函数
函数基础
1.函数定义包括返回类型,函数名,形参,函数体几个部分。
2.调用函数完成两项工作:
(1)实参初始化形参;
(2)控制权移给被调用函数;
参数传递
1.传值参数
初始化一个非引用类型的变量时,初始值被拷贝给形参变量(包括指针)
2.传引用参数
使用引用可以避免较大数据类型的拷贝
使用引用形参返回不止一个的额外信息
3.当形参为顶层const时,因为传给它常量和非常量都是可以的,故顶层const效果会被忽略;而const实参却不能传给非底层const形参。
4.数组传递
(1)因为数组是不允许拷贝的,故为函数传递一个数组会将其转化为指向数组首元素的指针。
(2)数组传递的三种方法
[1]使用带结尾标记的指针数组:如C风格的字符串数组带’\0’结尾标记
[2]传递数组首元素与尾后第一个元素的指针
[3]传递一个表示数组大小的形参:void fun(int a[],size_t n);(以数组形式表示形参时省略[ ]中的数)
(3)传递多维数组
void func(int a[][10])
void func(int (*a)[10])
5.形参为函数指针类型(见后函数指针)
6.main函数的形参
void main(int argc,char *argv[]){}
其中argv为C风格字符串指针数组,接收命令行中的字符串,argv[0]指向程序的名字或空字符串
argc为数组的个数
7.形参个数可变——处理不同数量实参的函数
实参类型不同时,用可变参数模板
实参类型相同,但数量未知时,两种方法:
(1) initializer_list:类似于vector,也是模板类,不过initializer_list对象元素中均为常量;通过{}来传递一个实参序列;
(2) 省略符实参:void func(…)或void func(int a,…);
返回值
1.无返回值函数
无返回值函数体中最后一句后面会隐式执行return
2.有返回值函数
(1)引用返回左值:调用一个返回引用的函数得到左值,其他类型为右值,故能为非const引用返回函数的结果赋值:
(2)列表初始化返回值:返回值为一个可接受列表初始化的类型,函数体中return一个{}包含的列表
//例: vector<string> func( { if(a.empty()) return {"kobe","wade"};//返回一个列表初始化的vector对象 else return {};//返回一个空vector对象
(3)主函数的返回值–状态指示器:返回0表示执行成功,非0失败
为了与机器无关,cstdlib头文件定义了两个与预处理变量 EXIT_FAILURE与EXIT_SUCCESS.
(4)返回数组指针
声明一个返回数组指针的函数的几种方法
[1] 利用类型别名typedef或者using
typedef int arrT[10];//arrT是一个类型别名,表示类型是含有十个整数的数组 using arrT=int [10];//arrT的等价声明 arrT *func(int i);
[2] 不使用类型别名直接声明
此时需牢记返回数组的维度
int *a[10]//定义一个指针数组 int (*a)[10]//定义一个指向数组的指针 int *func(int i);//函数返回值是一个指向int型的指针 int (*func)(int i);//是一个函数指针,函数类型为形参int,返回值int int *func(int i)[10];//错误,此时表示函数返回值是指针的数组,且该指针指向整型, // 但不能返回数组,故该写法错误 int (*func(int i))[10];//正确,返回值数组维度必须位于函数名后 int (*func[10])(int i);//是一个函数指针数组
[3] 使用尾置返回类型
auto func(int i)->int (*)[10]
[4]使用decltype–只用于预先知道返回值类型
int odd={1,3,5,7}; int even={0,2,4,6}; decltype(odd)* func(int i)//有几种情况数组名不会转化为指针,decltype便是其中之/一,故添加* { return (i%2)? odd:even;
(5)返回值为函数指针类型(见后函数指针)
函数重载
同一作用域的几个函数名称一致,形参个数不同的函数成为重载函数)
1.函数重载中的const及const_cast
(1) 函数形参中的顶层const会被忽略,故而有顶层const形参函数和与之相应的无顶层const形参函数是同一个函数
int func(const int ); int func(int );
注意:满足精确匹配且函数名相同及形参个数一样的均为同一函数。
(2)constr_cast与重载–多用于同一函数功能的无底层const的实现
const_cast<>()可去掉与添加底层const。
const string &Shortstring(const string &a,const string &b)//有底层const版本 { return (a.size()>=b.size())? a:b; } //可以对两个非常量的string实参调用上面函数,但返回值却是一个const string的 //引用,故需要一个新函数,当两实参为非常量string时,返回值仍然是非常量string string &Shortstring(string &a,string &b)无底层const版本 { auto &r=&Shortstring(const_cast<const string &>(a), const_cast<const string &>(b)); return const_cast<string &>(r); }
2.函数匹配(重载确定)----根据实参调用具体重载函数的过程
(1)函数匹配结果三种结果:
[1] 找到与实参最佳匹配的函数,并生成调用该函数的代码;
[2] 找不到任何一个能与实参匹配的函数
[3] 有不止一个函数可以与实参进行匹配,且二者匹配契合度一致,称为二义性调用
(2)函数匹配的过程
确定候选函数——>确定可行函数——>根据转换优先级寻找最佳匹配
[1] 候选函数:所有的重载函数(同名+其声明在调用点可见)
[2]可行函数:形参数量与实参数量一致+实参与形参类型一致或可转换
[3]最佳匹配:该函数至少有一个形参实参匹配优于其他函数且该函数其他匹配不弱于其他函数
匹配优先级:精准匹配>const转换匹配>类型提升匹配>算数提升匹配/指针转换>类类型转换匹配
精准匹配包括以下情况:
《1》实参形参相同
《2》实参从函数或者数组转换为对应指针类型
《3》向实参添加顶层const或向形参删除顶层const
const转换匹配: 非常量实参转换为常量实参再传递(拷贝或者绑定)给形参
类型提升匹配:从一中类型转换到另一种类型:整型,浮点型,字符型
算数提升匹配:整型内提升,无符号跟符号类型提升
指针转换:0或者nullstr转换为任意类型指针;任意指针转换为通用指针*void或者const *void
类类型转换匹配:如C风格字符串转换为string等
函数指针
(1)函数指针写法:将函数名替换成指针并在两边加上括号即可。
bool (*pf) (const string &);//pf即为函数指针
(2)使用函数指针
[1]
《1》函数名作为一个值使用时,自动转换为函数指针
《2》通过指针调用函数,既可以用解引用符*,也可以直接用指针名
《3》指向不同函数类型的指针间不存在转换
pf=lengthCompare(); pf=&lengthCompare();//两者等价 bool b1=pf("kobe","wadejames"); bool b2=(*pf)("kobe","wadejames"); bool b3=pf=&lengthCompare("kobe","wadejames");//三者等价
[2]用于函数形参时
《1》函数类型作为函数形参自动转换为函数指针
《2》如何简化函数指针或函数作为形参–类型别名
typedef bool func(const string &,const string &); typedef decltype(lengthCompare) func2;//func,func2即为等价函数别名 typedef bool (*funca)(const string &,const string &); typedef decltype(lengthCompare) *funca2;//funca,funca2即为等价函数指针别名 void use(const string&,func);
[3] 用作函数返回值
《1》用类型别名或using
typedef int(*pf)(int *,int); using pf=int(*)(int *,int);//二者等价 pf func(int );//用pf写函数声明 typedef int(pf1)(int *,int); using pf1=int(int*,int); pf1 *func(int );
《2》用尾置返回类型
auto func(int )->int (*)(int*,int);
《3》用decltype或者auto
int s(double); decltype(s) * func(int );
《4》直接声明
int (*int(char *))(int );
三种函数相关的语言特性
(1)默认实参
[1] 尽量把默认实参初始化的形参放置参数列表的最后面;
[2] 通常在函数声明中指定默认实参,并将该声明放在合适的头文件中;
[3] 在作用域内,一个形参只能被赋予一次默认实参;
[4] 不能用局部变量作为默认实参;
(2)constexpr函数
[1] 用于常量表达式,且返回类型及形参类型必须为字面值类型,函数体内有且仅有一条返回语句;
[2] 函数体内的语句必须均在编译器即可执行,故而constexpr函数被隐形指定为内联函数;
[3] 返回值不一定是常量表达式;
(3)inline
在内联点展开,只是一个像编译器提出的请求,编译器可以根据它是否优化规模小,流程直接,频繁调用来决定是否忽略该请求。
- 点赞
- 收藏
- 分享
- 文章举报
- c++ Primer 第一章
- c++ Primer 第二章
- c++ Primer 第三章
- c++ Primer 第八章
- 初识C语言
- 初学C语言之语句
- C语言程序设计(2)
- 什么是指针,C语言指针概述
- C语言位运算
- C语言使用栈和队列来判断回文
- (转)C#与C++之间类型的对应
- C语言strcmp()函数:比较字符串(区分大小写)
- C语言链表各类操作详解
- C#委托实现C++ Dll中的回调函数
- Windows系统搭建Kafka C++ 客户端实现消息avro序列化发送
- C语言数组可以定义为a[n]吗
- c++ string类型的定义及方法
- c++中new的用法
- 按单词倒序字符串,C语言实现
- [UE4]C++中SpawnActor用法(动态创建Actor)