c++ primer 学习笔记 第六章

第六章

函数基础

  • 函数执行的第一步是隐式的定义并初始化他的形参。
  • 如果局部静态变量没有显式的初始值,他将执行值初始化,内置类型的局部静态变量初始化为零。
  • 在头文件中进行函数声明,含有函数声明的头文件应该被包含到定义函数的源文件中。
  • 使用引用避免拷贝,效率高,而且某些类类型不支持拷贝操作。如果函数无需修改引用形参的值,声明为常量引用。

温习----指针引用与const

int i = 42;
const int *cp = &i;	 //正确:但是cp不能改变i
const int &r = i; 	// 正确:但是r不能改变i 
const int &r2 = 42; 	//正确, 常量引用可以引用常量
int *p = cp;	//错误: p的类型和cp的类型不匹配
int &r3 = r;	//错误: r3的类型和r的类型不匹配
int &r4 = 42;	//错误:不能用字面值初始化一-个非常量引用

尽量使用常量引用。

数组形参

  • 为函数传递一个数组时,实际上传递的是指向数组元素的指针。

  • 当函数不需要对数组元素执行写操作的时候,数组形参应该是指向const的指针。只有当函数确买要改变元素值的时候,才把形参定义成指向非常量的指针。

温习

  • int *matrix[10]; //10个指针构成的数组
    int (*matrix)[10]; //指向含有10个整数的数组的指针
    
  • 返回局部对象的引用是错误的。同样,返回指向局部对象的指针也是错误的。一旦函数完成,局部对象被释放,指钍将指向一个不存在的对象。

函数返回值

数组不能拷贝,所以函数不能返回数组。

声明一个返回数组指针的函数

//Type ( *function (parameter_ list) ) [dimension]
int (*func(int i))[10];	//函数返回指向int数组的指针
  • func(int i) 表示调用func函数时需要一个int类型的实参。
  • (*func(inti)) 意味着我们可以对函数调用的结果执行解引用操作。
  • (*func(int i)) [10]表示解引用func的调用将得到一个大小是10的数组。
  • int (*func(int i)) [10]表示数组中的元素是int类型。

使用尾置返回类型

// func 接受一个int类型的实参,返回一个指针,该指针指向含有10个整数的数组
auto func(int i) -> int(*) [10] ;

函数重载

  • 不允许两个函数除了返回类型外其他所有的要素都相同。

  • 一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开来

Record lookup (Phone);
Record lookup (const Phone);//重复声明了Record lookup (Phone)

Record lookup (Phone*);
Record lookup (Phone* const);//重复声明了Record lookup (Phone*)
  • 如果形参是某种类型的指针或引用,则通过区分其指向的是常量对象还是非常量对象可以实现函数重载
//对于接受引用或指针的函数来说,对象是常量还是非常量对应的形参不同
//定义了4个独立的重载函数
Record lookup (Account&);	// 函数作用于Account 的引用
Record lookup (const Account&);	// 新函数,作用于常量引用
Record lookup (Account*);	//新函数,作用于指向Account的指针
Record lookup (const Account*);	//新函数,作用于指向常量的指针
  • const_cast:在下面这个版本的函数中,首先将它的实参强制转换成对const 的引用,然后调用了shorterString函数的const版本。const版本返回对const string 的引用,这个引用事实上绑定在了某个初始的非常量实参上。因此,我们可以再将其转换回一个普通的string&, 这显然是安全的。
string &shorterString(string &s1, string &s2){
	auto &r = shorterString(const_cast<const string&>(s1),
                             const_cast<const string&> (s2) );
	return const_cast<string&>(r);
}//发问:这样的意义是不重写一遍代码?

默认实参

  • 一旦某个形参被赋予了默认值,则其后面的所有形参都必须有默认值。
  • 只能省略尾部的默认实参,从右到左看。
  • 默认实参可以多次声明,但不能修改一个已经存在的默认值。
string screen(SZ, SZ, char ='');
string screen(SZ, SZ, char = '*');  //错误:重复声明
string screen(sz = 24, sz = 80, char);    //正确:添加默认实参          

内联函数和constexpr函数

inline : 内联函数可避免函数调用的额外开销,但是只是像编译器发出的一个请求,编译器可以选择忽略它。

constexpr函数(constexpr function): 指能用于常量表达式的函数。

  • 约定:函数的返回类型及所有形参的类型都得是字面值类型,而且函数体中必须有且只有一条return语句。

  • 为了能在编译过程中随时展开,constexpr函数被隐式地指定为内联函数。

  • 允许constexpr函数的返回值并非一个常量。

    • //如果arg是常量表达式,则scale(arg)也是常量表达式.
      constexpr size_t scale (size_t cnt) { return new_sz() * cnt; }
      //当scale的实参是常量表达式时,它的返回值也是常量表达式,反之则不然:
      int arr[scale(2)];	//正确: scale(2)是常量表达式
      int i = 2; 			// i不是常量表达式
      int arr[scale(i)];	//错误: scale(i)不是常量表达式
      

函数匹配

  • 函数每个实参的匹配都不劣于其他可行函数需要的匹配。

  • 至少有一个实参的匹配优于其他可行函数提供的匹配。

如果在检查了所有实参之后没有任何一个函数脱颖而出,则该调用是错误的。编译器将报告二义性调用的信息。

调用重载函数时应尽量避免强制类型转换。如果在实际应用中确实需要强制类型转换,则说明我们设计的形参集合不合理。

函数指针

声明函数指针

要想声明一个可以指向该函数的指针,只需要用指针替换函数名即可。

// pf指向一个函数, 该函数的参数是两个const string 的引用,返回值是bool类型
bool (*pf)(const string &, const string &); //未初始化

使用函数指针

函数名作为值使用时,该函数自动转换为指针。

pf = func;		//pf指向名为func的函数
pf = &func;		//等价的赋值语句:取地址符是可选的

直接使用指向函数的指针调用该函数,无须提前解引用指针,但指向不同函数类型的指针间不存在转换规则。

bool b1 = pf("hel1o", "goodbye");	//调用func函数
bool b2 = (*pf)("hello", "goodbye");	//一个等价的调用
bool b3 = func("hello","goodbye"); 	// 另一个等价的调用

重载函数的指针

void ff(int*);
void ff(unsigned int);
void (*pf1)(unsigned int) = ff; 	// pf1指向ff (unsigned)
//编译器通过指针类型决定选用哪个函数,指针类型必须与重载函数中的某一个精确匹配
void (*pf2)(int) = ff;		//错误:没有任何一个ff与该形参列表匹配
double (*pf3)(int*) = ff;	//错误: ff和pf3的返回类型不匹配
typedef decltype(lengthCompare) *FuncP2; //指向函数的指针

decltype的结果是函数类型,所以只有在结果前面加上*才能得到指针。

返回指向函数的指针

  • 使用类型别名,最简单。

    using F = int (int*, int);		// F是函数类型,不是指针
    using PF = int (*)(int*, int);	// PF是指针类型
    
    PF f1 (int);	//正确:PF是指向函数的指针,f1返回指向函数的指针
    F f1 (int);		//错误: E是函数类型f1不能返回一个函数
    F *f1 (int);	//正确:显式地指定返回类型是指向函数的指针
    
    
  • 尾置返回
    int (*f1(int))(int*, int);
    auto f1(int) -> int (*)(int*, int); //尾置返回
    

由内而外解析:首先f1带有形参列表, 是一个函数,(类比)直接调用一个函数就是使用其返回值,前面加了’*’,说明返回的是一个指针。进一步观察,返回的指针也带有参数列表,所以这个指针指向的是一个函数,且函数的返回类型是int。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值