【C++】引用、内联函数、函数重载、函数默认参数(缺省参数)与占位参数、extern “C“ 浅析

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 【C++】引用、内联函数、函数重载、函数默认参数(缺省参数)与占位参数、extern “C“ 浅析,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

        端午继续~

        C++对C的扩展

目录

引用

普通变量名引用

对数组的引用

对指针的引用

对函数的引用

引用作为函数的参数

引用作为函数的返回类型

常引用

内联函数 

函数重载

函数的默认参数(缺省参数)

默认参数和函数重载的二义性

占位参数

extern “C” 浅析


引用

        本质:给变量名取别名,可以通过别名间接操作变量

        &:引用说明符(不是取地址符)

        给哪个变量取别名,就定义该变量

普通变量名引用

void Test()
{
	int a = 0;
	//给变量a取一个别名叫b 
	//&修饰变量为别名,b就是a的别名 --- 引用
	int& b = a;//必须初始化,这里&不是取地址,是引用
}

注意:系统并不会为引用开辟空间,a,b代表同一个空间。

我们可以看一下地址

void Test()
{
	int a = 0;
	//给变量a取一个别名叫b 
	//&修饰变量为别名,b就是a的别名 --- 引用
	int& b = a;//必须初始化

	cout << "&a = " << &a << endl;
	cout << "&b = " << &b << endl;
}

运行结果:

【C++】引用、内联函数、函数重载、函数默认参数(缺省参数)与占位参数、extern “C“ 浅析

操作b等价于操作a

b = 10; 等价于操作了 a = 10;

对数组的引用

void Test_2()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//给数组arr取别名my_arr
	//注意这里要将&my_arr用括号括起来,否则my_arr会先于[10]结合
	int (&my_arr)[10] = arr;
	//访问的方式是一样
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		cout << my_arr[i] << " ";
	}
}

对指针的引用

void Test_3()
{
	int num = 6;
	int* p = &num;
	//给num取别名为 my_num 
	int*& my_num = p;//这里&的优先级高于*,所以可以不用带括号
	//访问时,与指针的访问方法是一样的
	cout << "num = " << *my_num << endl;
}

对函数的引用

int main()
{
	//对函数Test_3取别名为My_Test_3
	void(&My_Test_3)() = Test_3;//注意括号不可省略
	//访问
	My_Test_3();
	return 0;
}

        这么多例子,我们为什么要用引用,引用能解决什么问题?

        咱往下走~

引用作为函数的参数

        这是引用解决的主要问题,函数可以通过引用来操作外部变量

        这里学过C语言的小伙伴可能注意到了,引用和指针十分相似

确实如此~

        指针有一些操作比较麻烦地方:

形参是带指针*,并且实参要取地址,相对于来说比较麻烦。

所以在之后的学习中需要用到指针的地方尽量换成用引用

我们来对比一下,指针操作和引用操作,交换两个变量:

void My_exchange_1(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
void My_exchange_2(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}
int main()
{
	int a = 6;
	int b = 8;
	cout << "交换前:a = " << a << " b = " << b << endl;
	My_exchange_1(&a, &b);//指针
	My_exchange_2(a, b);//引用
	cout << "交换后:a = " << a << " b = " << b << endl;
	return 0;
}

引用作为函数的返回类型

int& Ret()
{
	int num = 5;
	return num;
}
int main()
{
	int& b = Ret();//由于函数返回类型为int&,所以应该用别名类型来接收
	//这里相当于间接给num取了一个别名b
	return 0;
}

        但是,我们都知道,局部变量一旦出了函数,就销毁了,所以这里的相当于你给一个已经释放了的空间取别名,这是不因该的,(会出现段错误)所以函数返回时不应该返回局部变量 !

常引用

简而言之就是给常量取别名

注:不能通过常引用修改内容

【C++】引用、内联函数、函数重载、函数默认参数(缺省参数)与占位参数、extern “C“ 浅析

         可以看到这里编译器会报错,为什么呢?

        给10这个常量取别名为num,10是一个常量,但num是一个变量, C++格式要求十分严格,所以这里会报错。

如何解决呢?

const修饰以下即可 

【C++】引用、内联函数、函数重载、函数默认参数(缺省参数)与占位参数、extern “C“ 浅析

有什么用呢?

防止函数内部修改外部的值

观察以下代码:

void Print(const int& x)
{
	//x = 100 //err
	cout << "num = " << x << endl;
}
int main()
{
	int num = 10;
	Print(num);
	return 0;
}

        我们知道,用引用作为形参可以节省空间,x 和 num 表示一个空间,这里写一个函数,功能就是遍历,但同时我希望他的功能只是遍历,如果一不小心修改了形参 x,也意味着 num 被修改,很危险,所以这里可以用常引用修饰 x,使 x 不可被修改,既提高了安全性,有节省了空间。

内联函数 

        必须在定义函数的时候使用inline关键字修饰,声明时不需要

string Print();

int main()
{
	cout << Print() << endl;
	return 0;
}

inline string Print()
{
	string s1 = "端午节";
	string s2 = "快乐";
	return s1+s2;
}

直观感受是不是和普通函数差不多?

其实有很大滴作用!

        内联函数:在编译阶段,将内联函数中的函数体 替换 函数调用处 ,避免函数调用时的开销(类似于宏函数,内联函数只是编译阶段直接替换,宏函数在预处理阶段替换)。

注意事项:

1.不能存在任何形式的循环语句

2.不能存在过多的判断语句

3.函数体不能过于庞大

4.不能对函数取地址

所以,加上inline并不是使函数成为内联函数的充要条件,他只是必要条件

加上inline只是告诉编译器,希望使其成为内联函数,最终是不是,还是有编译器决定

函数重载

表示同一个函数在不同的场景下可以有不同的含义

        同一个作用域,函数的参数类型,个数,顺序不同都可以重载(返回类型不能作为重载的条件)。

void print_1(int a)
{
	cout << "int" << endl;
}
void print_1(char a)
{
	cout << "char" << endl;
}
void print_1(int a, char b)
{
	cout << "int char" << endl;
}
void print_1(char b, int a)
{
	cout << "char int" << endl;
}
int main()
{
	print_1(50);
	print_1('a');
	print_1(60,'b');
	print_1('c',70);//根据参数自动匹配

	return 0;
}

        可以看到这里,函数名都一样,只是参数的类型,个数,顺序不一样,只要一种或多种,都可以重载。

        重载函数的底层原理:实际上这些函数在linux编译之后会产生不同的函数名,然后根据参数自动匹配不同函数的

函数的默认参数(缺省参数)

#include<iostream>

using namespace std;

void test_1(int a = 10, int b = 20)//这里的int a = 10,被赋值10,说明只是一个默认参数
{
	cout << "a + b = " << a + b << endl;
}

//注意1
//如果b设为默认参数,则从b往右的参数都必须设为默认参数
//也就是说,此时a不受影响,c是必须设为默认参数
//因为形参位置与实参位置保持一致,假设c没有默认参数
//调用test_2(100,200),这时,a,b都被赋值,c没有赋值,编译器就会报错(缺少参数)

void test_2(int a, int b = 20, int c = 30)
{
	cout << "a + b = " << a + b << endl;
}
//还有值得注意的一点:如果函数声明与函数定义分开,想要设置默认参数,只需在声明里设置即可,函数定义无需再设。
int main()
{
	test_1();//可以什么参数都不传,这里就会使用默认参数
	test_1(30);//将30这个实参传给a,这时,函数就不会使用默认参数,而是a = 30;
	test_1(40, 50);//同理,此时a,b的默认参数失效, a,b的值因为 40 , 50
	return 0;
}

默认参数和函数重载的二义性

void fun(int a)
{
	cout << "a = " << a << endl;
}

void fun(int a, int b = 20)
{
	cout << "a = " << a << endl << "b = " << b << endl;
}

int main()
{
	fun(10);
	return 0;
}

此时编译器会报错:

【C++】引用、内联函数、函数重载、函数默认参数(缺省参数)与占位参数、extern “C“ 浅析

什么意思呢?

        就是说,此时调用fun(10)传入一个参数,既可以传给第一个fun,也可以传给第二个fun(第二个fun的第二个参数有默认参数,所以传入一个参数也正确),编译器不知到传给哪个fun,所以就报错 ,但如果这样调用fun(10,20)就是正确的,他会自动匹配到第二个fun。

占位参数

        占位参数只有类型声明,没有参数名声明,一般情况下,函数体内部无法使用占位参数。

//形式一
void test_1(int a , int)
{
	;//这里的int就是占位参数
}
//形式二
void test_2(int a , int = 20)
{
	;//int = 20是占位参数,其实这里只是有一个隐形的参数名,但也只是表现形式,无法使用
}
int main()
{
	test_1(10, 20);//传参依然要传两个,并且类型对应,否则报错(缺少参数)
	test_2(10);//占位参数有缺省值,所以可以只传一个参数
	test_2(10, 20);//当然传两个也okk
	return 0;
}

也就是说,占位参数位置必须要传入参数,除非有缺省值。

至于怎么用,以后章节会细讲滴。

extern “C” 浅析

        C++编译函数和C编译器编译函数的方式是不同的,假设定义一个Fun函数,经过C编译后会产生一个新的函数名叫Fun,而经过C++编译器编译后产生的新函数名可能(不同的C++编译器效果不一样)叫Funv,所以如果调用函数可能就会存在连接错误,那么为了能在C++的环境下调用C语言函数,就引入了extern “C”,这部分代码也将按照C语言的编译方式取运行。

使用如下:

#if __cplusplus //检测当前是否是C++工程
extern "C"//满足则执行这里
{
#endif//不满足则执行这里,因为不满足说明就是C语言工程,直接引用以下就可以
	extern//引入你想要实现的C语言的函数声明
		//...
		; 
#if __cplusplus
}
#endif

码字不易~

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/129920.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!