c++ primer plus笔记(5)函数基础

一、函数的声明(declaration):

return_typename function_name(typename parameter_name,...)   //函数原型(函数头)
{
   ...;   //函数体
   return ...;
}

①形参(parameter)与传值调用:

1>形参:

函数原型处的形参,其名称仅相当于占位符。

所以单独声明函数原型的时候也可将变量名省略。

return_typename function_name(typename ,...)

2>传值调用:

仅将实参的值(的拷贝)传递给形参,而非实参地址处的实参本身。

因此传值调用关心的是使用该值得到的结果而不是处理和改变,其不影响原实参在内存中的值。

#include "stdafx.h"
#include<iostream>

void swap(int, int);
int main()
{
	//
	using std::cout;
	using std::endl;

	//
	int a = 10;
	int b = 1;
	cout << "before swap:\n";
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	cout << "after swap:\n";
	swap(a, b);
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;

	//
	system("pause");
    return 0;
}
void swap(int a, int b)
{
	int c = a;
	a = b;
	b = c;
	return;
}

而想要修改实参地址处的实参本身,就必须选择指针引用作为形参:

#include "stdafx.h"
#include<iostream>

void swap(int* const, int* const);               //指针作为形参,相应的函数原型也应修改
int main()
{
	//
	using std::cout;
	using std::endl;

	//
	int a = 10;
	int b = 1;
	cout << "before swap:\n";
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	cout << "after swap:\n";
	swap(&a, &b);                //调用时应传递地址
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;

	//
	system("pause");
    return 0;
}
void swap(int* const a, int* const b)
{
	int c = *a;                  //全部对传递的地址解除引用
	*a = *b;
	*b = c;
	return;
}
#include "stdafx.h"
#include<iostream>

void swap(int& const, int& const);               //引用作为形参,相应的函数原型也应修改
int main()
{
	//
	using std::cout;
	using std::endl;

	//
	int a = 10;
	int b = 1;
	cout << "before swap:\n";
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	cout << "after swap:\n";
	swap(a, b);                  //调用时直接使用变量即可
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;

	//
	system("pause");
    return 0;
}
void swap(int& const a, int& const b)
{
	int c = a;
	a = b;
	b = c;
	return;
}

以上两种方法运行结果相同:

//为尽量减少不必要的错误,形参(尤其是指针或引用)的修改权限应尽可能的低,使用const严格限定其行为

//由于数组名可以近似的看做const指针,(或者说数组本来就是通过指向内存块的指针来调用的)所以数组做形参的任何一种写法都不能实现数组的传值调用。换句话说,当数组作为形参时,使用的一定是其本身而不是其拷贝。

以c-style string为例:

void array_funct(const char[]);
void array_funct(const char*);

两种写法并没有什么区别。

3>参数传递方式的选择:

(1)使用传递的值而不修改,且数据结构本身很小----传值;

(2)数组或内置数据类型----指针;(不修改则const限定)

(3)其余情况一般全部使用引用;(不修改则const限定)

4>参数的默认值:

int function(const char*,int n=1);    //当n没有被提供值,则使用默认值1
//默认参数必须出现在形参列表的最右边。

//默认参数只写在函数原型中,而函数定义部分不写。

②返回值(return value)与引用:

事实上,通常情况下调用函数得到返回值都是其原本值的拷贝,而不是其本身;

而返回引用类型则使得返回原地址处的值。

int& funct();

所以应积极使用引用作为返回值类型。

1>返回引用类型的原因:①省去了拷贝的开销,效率更高,尤其对于越是大的数据结构。

                                    ②左值用法。

//左值(L-value):地址(内存块),如&和*类型;

//右值(R-value):(无址)数据,如字面值和表达式;

int& funct(a)=b;   //将b的值写入funct(a)的返回值地址处

2>返回引用类型的注意事项:①由于允许左值用法,可能导致一些不易察觉的书写错误,为减少这种错误应尽可能使用const限                                              定引用返回值。

                                          ②返回的地址应当有效,在函数体中定义的临时变量,不能作为引用类型返回。

int& funct(int& ft)
{
   int a;
   a=ft;
   return a;       //a不是有效的引用,其地址处的内存在函数调用结束时已经被释放
}

//但如果创建的临时变量是使用new创建在heap区,那么其引用就可以作为引用类型返回;

被引用的参数可以作为引用类型返回:

int& funct(int& ft)
{
   return ft;       //指向被引用的实参地址处的值,而这个值长期存在,所以可行
}

二、函数指针:

声明方法:

int funct(int*);      //声明一个函数
int (*p_funct)(int*); //声明一个和该函数特征标相同的指针
pf = funct;           //将指针指向该函数

//pf = funct; 该句也说明函数名本身就是函数的入口地址,也就不必&funct。

//在函数指针被使用的情况下,函数的形式可能变得非常复杂,调用时书写冗长,此时可使用自动类型推断auto或typedef减少书写量:

const double* funct(const double*,int);           //函数声明
const double* (*p_funct)(const double*,int);      //指针声明
typedef const double* (*temp)(const double*,int); //将temp作为函数指针const double* (*)(const double*,int)类型的别名
temp funct1=funct;                                //将函数指针指向函数

三、内联函数:

常规函数在每次调用时通过函数名寻找跳转至函数stack区,并记录下执行完应该返回的地址,调用结束后返回主程序继续执行。

内联(inline)与宏定义有一定相似性,在编译时使用预设的固有函数代码直接展开在每一个调用处,其行为更接近符号。

inline void funct(){...//函数体};   //定义一个内联函数

//内联函数只在标头定义,不将声明与原型分开,行数不宜过多(一般都写在同一行);

//递归函数不能内联;

//内联函数不能进行异常规范声明;

//内联函数节省了调用函数时的跳转开销,但代价是会使程序体积增大,因此不宜用于函数体复杂的(如含有switch、while)函数。

四、函数重载:

重载(overloading)函数调用时以参数列表(特征标)来区分应匹配的原型:

函数重载适合于多个同名函数基本执行同样的任务,但参数类型及所需实现不同的场合。

void funct(int,char*);
void funct(int,int,char*);   //参数数目不同
void funct(char,char*);      //参数类型不同

①重载的注意事项:

1>返回值不能作为重载依据:

void funct(int,char*);
int* funct(int,char*);  //冲突的声明

2>以const限定为依据的重载只对指针(*)和引用(&)类型参数起作用:

#include "stdafx.h"
#include<iostream>

int afunc(const int& );                   
int afunc(int& );
int main()
{
	//
	using std::cout;
	using std::endl;

	//
	int a = 1;
	cout << "afunc(3)=" << afunc(1) << endl;
	cout << "afunc(a)=" << afunc(a) << endl;      //const参数重载只能区分 引用& 和 指针* 类型

	//
	system("pause");
    return 0;
}
int afunc(const int& a)
{
	return a * 2;
}
int afunc(int& b)
{
	return b * 3;
}


指针(*)类型同,不再列举。

3>当没有任何原型与调用处的参数匹配时,将尝试执行转换:

void funct(int,const char*);
void funct(int,int,const char*);
int main()
{
   ...;
   unsigned int a = 2;
   funct(a,"fun");               //a将被从unsigned int转换为int,并与原型void funct(int,const char*)匹配
   ...;
   return 0;
}
...

//当存在多个转换途径时,拒绝调用该函数:

void funct(int,const char*);
void funct(double,const char*);
void funct(int,int,const char*);
int main()
{
   ...;
   unsigned int a = 2;
   funct(a,"fun");               //转换途径有int和double两种,拒绝该调用
   ...;
   return 0;
}
...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值