函数基础学习(这章比较杂,点比较分散,都是四处凑的,欢迎提问和指正哈哈哈哈)

本文深入探讨C++中的函数特性,包括形参与实参的概念、局部对象与静态对象的生命周期、函数重载机制、内联函数的使用、尾置返回类型及函数指针的理解。同时,讲解了数组作为函数参数的退化、initializer_list形参的特殊性及默认实参的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

形参和实参

实参是形参的初始值

局部对象

对象有生命周期,理解这两个概念非常重要

名字的作用域是程序文本的一部分,名字在其中可见

对象的生命周期是程序执行过程中该对象存在的一段时间

 

局部静态对象

相对于自动对象而言,局部静态对象在程序执行路径第一个经过对象定义语句时初始化,直到程序终止了才会被销毁,在此期间机制对象所在的函数执行结束也不会有影响。

/*
1.验证局部变量对全局变量的隐蔽性。
结果:局部变量和全局变量同名时,局部变量对全局变量具有隐蔽性。
2.验证局部静态变量的生命周期
结果:局部静态变量的生命周期是在整个程序运行期间都存在

需要注意的是静态声明的关键字是static ,而不是const
static 声明对象,会使得对象储存在内存四区的全局静态区
const 声明仅仅只是该该对象内容不可被改变
*/
#include <iostream>
#include <string>

using namespace::std;
int value_test = 5;
void object_test()
{
	int value_test = 0; //与全局变量的名字相同
	static int value_static_test = 0;

	value_static_test++;
	cout << "value_test:" << value_test << endl;
	cout << "value_static_test:" << value_static_test << endl;
}
int main(void)
{
	for (int i = 0; i < 4; i++)
	{
		object_test();
	}

	system("pause");
	return 0;
}

尽量使用常量引用

把函数不会改变的形参定义成(普通的)引用是一种比较常见的错误,这么做带给函数的调用者一种误导,即函数可以修改它的实参的值

 

数组做函数参数会退化成指针

eg  void test(int  value[]){};

      void test  (int *value ) {};  

//这两句是是等价的,如果看客有疑惑。

可以用下例测试

int test[5]  ={0,1,2,3,4};

//value :数组名 , size :数组的大小,调用时填入test和5或者sizeof(test)

//注意千万不要耍小聪明,将数组传入形参后,在函数中对形参进行sizeof()操作,

得到的并不是数组的大小,而是指针本身的大小。如有疑问,请看标题,它解释的很清楚

void test (int *value, int size)  

{

      for(int i = 0; i < size; i++)

      cout << value[i] << endl;

}

函数中多维的数组的指针形式形参

如 int (* test)[][5] //定义一个指向一维为5,二维未知的数组指针

 

initializer_list形参

是一种模板类型,较为特殊的是,它对象的元素永远是常量

如果函数的参数是 initializer_list形参, 它的参数传递,只能是花括号包裹起来的列表初始化

#include <iostream>
#include <string>
#include<vector>

using namespace::std;
int value_test = 5;
void msg_cout(initializer_list<string> il)
{
	for (auto beg = il.begin(); beg != il.end(); ++beg)
		cout << *beg << " ";
	cout << endl;
}
int main(void)
{
	initializer_list<string> i2 = { "1","2" };
	vector<string> i3 = { "0","1" };
	msg_cout({ "ok","I am fan","thanks" });//正确,列表传参
	//msg_cout(i3);//错误,vector对象不可给initializer_list对象传参
	system("pause");
	return 0;
}

函数重载

如果同一个作用域内的几个函数名字相同但形参列表不停,称之为重载函数

eg : void print(const char *p)

         void print(const int *beg, const int *end)

int j[2] = {0,1};

print("hello");//调用第一个

print(begin(j), end(j));//调用第二个

/*
1.使用函数返回引用
结果:返回值可以做左值

2.使用函数返回列表

3.返回数组指针

4.函数重载是否能靠const性质分辨
结果:如果形参本身是普通对象,会显示函数重复声明
      如果形参是指针或者引用类型,它会做以区分(仅在底层声明有效)
原因:函数的形参是传值调用,
      普通形参,接收的实参过程仅仅是复制其实参对象内容,对象内容无法区分cosnt与非const
	  eg:实参 string s1 = "a", s2 = "b";
	      函数test(string s);
		   test(s1);   实际上做的操作仅仅是 s = s1;再直白点就是 s = "a";
		  那么test(s2) 与上述过程相同,无法靠这个过程去区分实参是否是const,并且也无必要
	  而引用和指针传入时,带有其本身的性质,底层const声明表示其指向对象是不能被改变的
	  因而可以区分

注意:如果传入的实参与重载函数的形参类型都没有符合的,它会选择最佳匹配,并生成调用该函数的代码
      但是以下情况会报错
	  1.找不到能够匹配的函数就会发出无匹配的错误信息
	  2.有多于一个函数可以匹配,但是都不是最佳匹配,也报错,成称为二义性调用
          最佳匹配条件
          1.该函数的每个实参的匹配都不劣于其他可行函数需要的匹配
          2.至少有一个实参的匹配优于其他可行函数提供的匹配

*/
#include <iostream>
#include <string>
#include<vector>

using namespace::std;

char &back_char(string &str, string::size_type ix)
{
	return str[ix];
}
vector<string> back_string(void)
{
	return{"a","b","c"};
}

void test_const(const int &i)
{
	cout << "const" << endl;
}
void test_const(int &i)
{
	cout << "not const" << endl;
}

int (*arr())[5] //表示解引用arr的调用会一个大小为5的数组
{               //或是说返回值是一个指向大小为5的数组的指针
	int (*p)[5] = NULL;
    p = (int(*)[5])malloc(sizeof(int) * 5);
	return p;
}
int main(void)
{	
	string s("a value");
	vector<string> s1(3);
	int a = 0;
	const int b = 0;

	cout << "s_f:" << s << endl;
	back_char(s, 0) = 'A';
	cout << "s_d:" << s << endl;

	s1 = back_string();
	cout << "s1[0]:" << s1[0] << endl;
	cout << "s1[1]:" << s1[1] << endl;
	cout << "s1[2]:" << s1[2] << endl;

	test_const(a);
	
	system("pause");
	return 0;
}

默认实参

某些函数有这样一种形参,再函数的很多次调用中他们都被赋予一个相同的值,这时,我们把这个反复出现的值称为函数的默认实参

eg :void test(int a = 1; int b = 2){}

以上的1,2便是默认实参,如果没有给其传入参数其就使用默认实参初始化形参

想要使用默认实参时,省略即可

eg test(1);  test();均可

需要注意的是;仅仅只能省略尾部的实参 如果test(,1);这样用时错误的。

 

内联函数inline

将函数指定为内联函数,通常就是将它再每个调用点“内联的”展开。在函数前加上inline即可指定。

eg inline int test(){ return 0;}

在编译过程中,test()会被展开为return 0;从而消除了test()韩式运行的开销

注意:一般这个函数使用次数较多时才声明为inline。因而最好定义放在头文件,以供多次调用。

 

尾置返回类型

该类型提供,一种更好理解的返回类型书写方法

格式eg:auto f1(int)-> int(*)[];//返回类型为一个指向int型数组的指针

 

多提一句

函数指针的东西

using f = int(int*,int);//f是函数类型,并不是指针

using pf =  int(*)(int*,int);//pf是函数指针

 

 

 

                           

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值