C++中函数的参数与返回值知识点

参数传递

1.值传递:把实参的值拷贝给形参,形参和实参是两个相互独立的对象。

2.引用传递:形参是引用类型,它将绑定到对应的实参上。

3.指针形参:指针的行为和其它非引用类型一样。将形参传递给实参时,是拷贝指针的值(也就是地址)。拷贝之后,两个指针是不同的指针,但是他们指向的地址相同,

   所以通过指针可以修改它所指的对象的值。

   总结:尽量使用引用形参,在拷贝大的类类型对象或者容器对象时,这样做比较高效,有的类类型甚至就不支持拷贝操作。同时,如果不希望改变实参的值,就将形参声明为常      量引用。此外,使用引用形参的好处还包括使得函数变相返回多个值。

注意:

void fun(int i) {}
void fun(const int i) {}//错误,不属于函数重载,因为实参初始化形参时会忽略顶层const,因为实参是被
                        //值传递,所以对实参没有影响。所以就不认为是函数重载了

数组形参

1.一维数组形参  

   下面这三个函数是等价的

void print(const int*);
void print(const int[]);
void print(const int[8]);//虽然给出了维度大小,但对实际传进来的数组维度没有影响
 注意:如果形参是数组的引用,则形参中的维度就控制了实参的维度

void print1(int(&arr1)[]);//错误,若形参是数组的引用,则必须给出维度。
void print2(int (&arr2)[8]);//正确,arr2是具有8个整数的整形数组的引用,实参数组维度的大小也必须为8。
2.二维数组形参

   C++中,多维数组就是数组中元素的内容还是数组。

void print(int(*arr)[10]);//arr指向数组的首元素,该元素是由10个整数构成的数组
//下面是等价定义.要注意的是,不能省略数组第二维的大小,否则会报错。
void print(int arr[][10]);//即使形参写成这样,形参本质上也还是指向含有10个整数的数组的指针。
3.initializer_list形参

   如果函数的实参数量未知但是全部实参的类型都相同,就可以使用initializer_list类型的形参。这是一种标准库类型,使用时需要添加同名的头文件。

函数返回值

1.返回类型是void的函数可以return另外一个返回void的函数。

void f1()
{
}
void f()
{
	int i;
	return f1();
}
2.return语句返回值的类型必须与函数的返回类型相同,或者能隐式转换成函数的返回类型。

3.不要返回局部对象的引用或指针。因为函数完成之后,它所占用的内存空间也随之被注释掉。

string &manip()
{
	string s1 = "cd";
	if (1)
	{
		return s1;//注意:编辑器在此处不会报错。但实际上在函数调用结束的时候s1就会被析构掉
		          //所以是不安全的。编译是可以通过的,但是对于返回的结果,因为已经析构,所以是不应该使用的。
	}
	else
		return "aaa";//错误,并且编译器能够检测出这种错误。因为“aaa”这个字符串被转换成
	                 //局部临时string对象了
}

4.其实标准的C++,主函数的返回类型根本就没有void这么一说,只不过是某些编译器支持void main(){}罢了。具体原因,经过查阅如下:

  <1>Linux下的进程运行完毕都会有一个返回值,范围是[0~255],int main()就是为了对应这个返回值。

  <2>使用int main()主要是可以给操作系统返回一个值,让操作系统明白这个程序执行的状态,比如执行这个程序后下一步可能要根据这个返回值做分支处理,如果是void的话

         返回值不会确定,异出退出和正常退出无法区别。

   注意:允许main()函数没有return语句直接结束。如果控制到达了main()函数的结尾处而且没有return语句,编译器将隐式地插入一条返回0的return语句。

5.main()函数不能调用自己本身。

6.返回数组指针的几种方式:

  <1>使用类型别名。

        using arr=int[10];//arr是一个类型别名

    arr* fun(int i);//返回一个数组指针的函数
   <2>使用尾置返回类型。(C++新标准提出的)任何函数的定义都能使用尾置返回,经常用在返回类型比较复杂的地方,比如返回类型是数组的指针或者数组的引用。尾置返           回类型跟在形参初始化列表后面并以->符号开头。在本应该放置返回类型的地方用auto代替。

 auto fun(int i)->int(*)[10];
   <3>使用declype。这种方式使用情况比较有限。需要纸袋函数返回的指针将指向哪个数组,也就是知道数组的类型和维度。
int odd[] = { 1,3,5,7,9 };
int even[] = { 2,3,4,5,6 };//注意:enen数组的类型和维度必须与odd数组一直,否则错误。
decltype(odd) *arr(int i)
{
	return (i % 2) ? &odd : &even;
}
7.函数的返回类型不作为函数重载的依据。

   此外,在函数重载中,拥有顶层const的形参无法和另一个没有顶层const的形参区分开来。

int fun(int i)
{
	return 0;
}
int fun(const int i)//错误,函数“int fun(int)”已有主体
{
	return 0;
}
   如果函数形参是某种类型的指针或者引用,则通过区分其指向的是常量对象还是非常量对象可以实现函数重载。此时的const是底层的。

int fun(int *p)
{
	return 0;
}
int fun(const int p)
{
	return 0;
}
8.重载与作用域,请看下面实例(需要说明的是,很少会出现下面这种情况,即将函数声明置于局部作用域内):

void print(double);
void print(const string &);
int main()
{
	void print(int);
	print("value:");//错误
	system("pause");
	return 0;
}
 注意:在main()函数中声明的print(int)隐藏了前面两个print函数。

9.默认实参初始值

 局部变量不能作为默认实参。

char c = 'a';
int wd = 80;
int fun();
string screen(int=fun(), int = wd, char = c);
void print()
{
	c = 'b';//改变了默认实参的值
	int wd = 100;//注意,在函数内部定义了同名局部变量,全局变量wd将被隐藏,
                 //但是该局部变量与传递给screen的默认实参没有任何关系。
	string s = screen();//调用的是screen(fun(),80,'a')
}
10.将函数指定为内联函数,也就是将它在每个调用点上“内联地”展开。可以避免函数调用的开销。不过只适用于规模较小、流程简单直接、频繁调用的函数。定义函数时在返回       类型前面加上关键字inline即可。    

函数指针

1.函数指针指向的是函数而非对象。

bool lengthCompare(const string &, const string &);
bool (*pf)(const string &, const string &);//pf首先是一个指针,说明pf指向一个函数,
                                           //该函数的参数是两个const string的引用,返回值是bool类型
bool *pf(const string &, const string &);//如果不加括号,则pf是一个函数名,返回值为bool指针
2.使用函数指针。当把函数名作为一个值使用的时候,该函数自动地转换成指针。

bool lengthCompare(const string &, const string &);
bool(*pf)(const string &, const string &);
int main()
{
	
	pf = lengthCompare;//此时pf指向函数lengthCompare
	pf = &lengthCompare;//同上,等价语句
	system("pause");
	return 0;
}
   而且,能直接使用指向函数的指针调用该函数,无需解引用指针。
bool lengthCompare(const string &, const string &);
bool(*pf)(const string &, const string &);
int main()
{
	bool b1 = pf("hello", "world");//调用lengthCompare函数
	bool b2 = (*pf)("hello", "world");同上
	bool b3 = lengthCompare("hello", "world");
	system("pause");
	return 0;
}

<3>函数指针形参

       和数组类似,不能定义函数类型的形参,但是形参可以是指向函数的指针。虽然看起来是函数类型,实际上是当成指针在使用。

void useBigger1(const string &, const string &, bool pf(const string &, const string &));
void useBigger2(const string &, const string &, bool (*qf)(const string &, const string &));//上面函数的等价形式
<4>返回指向函数的指针  

       和数组类似,同样函数的返回值不能是函数,但是能返回指向函数类型的指针。

using u1= int(*)(int, int);//u1是指针类型
using u2 = int(int, int);u2是函数类型
u1 f1(int);//f1这个函数返回指向函数的指针
u2 *f2(int);//同上,显示指出返回类型是指向函数的指针
auto f1(int)->int(*)(int, int);//尾置返回类型的方法
 

         




  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值