【C++】缺省参数、函数重载、内联函数、auto、for、nullptr

众所周知,C++由C发展而来,对C语言进行了一些改善,本文将介绍C++与C语言不同的一些零碎知识点:缺省参数函数重载内联函数auto范围fornullptr


一、缺省参数

1.1 定义&使用

在C语言中,一个函数要么永远不能传参数,要么必须传参数。而C++引入了缺省参数的概念,就是在函数声明是为函数的某个或某些参数指定一个默认值(缺省值),在函数调用时,如果有缺省值的参数没有传参就使用它的缺省值。

#include<iostream>
using namespace std;

int func(int a = 0)
{
	return a;
}
int main()
{
	int b = func();
	int c = func(2);

	cout << "b = " << b << endl << "c = " << c << endl;

	return 0;
}
//最后的运行结果为 b = 0 c = 2

1.2 分类

缺省参数可以分为全缺省参数半缺省参数。如果一个函数的参数全为缺省参数那么它就是全缺省参数,如果它既有缺省参数又有普通参数就是半缺省参数。

void func1(int a, int b, int c);
void func2(int a = 1, int b = 2, int c = 3);//全缺省
void func3(int a, int b = 2, int c = 3);    //半缺省
void func4(int a, int b, int c = 3);        //半缺省

1.3 注意点

1.半缺省参数只能从右往左给,不能间隔着给,不然在调用时就会产生歧义;

如果一个函数参数是这样的:viod func(int a = 1, int b, int c = 0);调用时b一定要传参,a,c可以不传,如果此时传入两个参数就会有歧义,所以规定如果是半缺省参数必须是前面是正常参数,后面是缺省参数。

2.缺省参数不能在定义和声明同时出现。如果函数定义和声明分离,那么就只在声明时给缺省值(其实在定义时给,声明时不给也是能通过的,只不过人们习惯在声明时给),否则会报错。

void func(int a = 1, int b = 2, int c = 3);    //声明

void func(int a , int b , int c)    //定义
{
    //...
}

3.缺省值必须是常量或者全局变量。


二、函数重载

C语言是不支持同名函数的存在的,如果我们想实现计算器中的加法功能,为了分别满足整型和浮点型参数相加功能的实现,需要两个不同名的函数才可以(比如 int int_add (int x, int y);和double double_add(double x, double y);)。但是在C++中我们可以把两个函数名都命名为add,同名函数就是函数重载

2.1 条件

函数名相同,参数不同(参数类型不同/参数个数不同/参数顺序不同),返回值随便(但是只有返回值不同的两个函数是不能被称为函数重载的)。

2.2 使用

int Add(int x, int y)
{
	return x + y;
}

double Add(double x, double y)
{
	return x + y;
}

int main()
{
	int sum_a = Add(3, 4);
	double sum_b = Add(3.7, 7.8);

	return 0;
}

sum_a会调用参数为int的函数,sum_b会调用参数为doub的函数。

2.3 注意点

  1. 用这个例子只是为了好理解(会有很多真的很有用的场景),真正在C语言中写加法函数时,如果只有其中一个函数Add(3,4);Add(3.4,6.5);都是可以被调用起来的,因为其中会发生隐式类型转换。无论在C还是C++中,如果这两个加法函数只存在一个,那么Add(3,6.7);都是可以编译通过的。但是C++中如果已经存在这两个函数还出现Add(3,6.7);就会报错(编译器不知道调用哪个,解决办法就是屏蔽掉其中一个或者再写一个int,double参数类型的函数)。
  2. void func( );void func(int a = 0);在理论上是构成重载的,有参数时很明确,无参时存在二义性,编译器也会报错。
  3. C++支持函数重载而C语言不支持是因为C语言编译链接函数地址时是通过函数名去找的,而C++则通过参数对函数名进行修饰,编译链接时通过修饰过后的函数名去找地址。

 三、内联函数

3.1 C语言中的宏

宏在C语言中是一种替换,它不是函数,所以不用建立栈帧,运行效率也比较高

如果用宏替换代替Add函数,可以写成

#define Add(x,y) ((x)+(y))

虽然宏看起来是香饽饽,其实有很多缺点:

1.语法细节多,容易出错

2.不能调试

3. 没有类型安全的检查

所以C++引入了内联函数

3.2 内联函数的使用

inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调

用建立栈帧的开销,内联函数提升程序运行的效率。

inline int Add(int x, int y)
{
	return x + y;
}

 内联函数的好处是不用建立栈帧还可以调试

3.3 VS环境下展开内联函数

在VS环境下,debug版本下,内联函数一开始默认不会直接展开,在通过汇编代码查看时,发现它和普通函数一样需要通过call函数地址去调用,

此时可以通过以下设置使内联函数展开

  1. 右键项目,点开属性
  2. 常规-调试信息格式-程序数据库
  3. 优化-内联函数扩展-只适用于_inline

经过这一番操作后,再调试看汇编发现inline函数直接展开了而不是像普通函数一样调用建立栈帧 

3.4 注意点

1.并不是所有函数使用于inline(适合使用内联的函数 : 短小精悍的函数 频繁调用的函数 无递归的函数)。内联函数虽然能提升一些运行时的效率,如果应用不好会影响可执行程序的大小。它只是一个普通函数时,每次使用都去调用该函数,调用100次,就是该函数被使用100次,而内联函数时把这个函数直接展开到表达式中,不调用函数却每次展开占空间,调用100次,表达式就多了100倍个该内联函数。(就像美瞳日抛和年抛,如果一个人每天都带美瞳,那么建议买一个年抛,一直用那一对,如果她很少带美瞳那么日抛更划算,他每次使用的都是不一样的美瞳,付不一样的钱)。

2.第一条是建议不要犯蠢,但是如果犯了蠢也不一定闯祸。因为内联只是向编译器发出的一个请求,编译器可以忽略这个请求,有时函数代码长,前面加了inline,即使编译通过,最后也可能不是内联函数。

3.内联函数如果定义和声明分离,只能在定义的文件中使用,其他文件使用不了,所以内联函数最好不要定义和声明分离,要写一起


四、auto

自动推导变量类型(有typedef的优点,比它智能)

4.1 使用

int a = 0;
int b = a;
auto c = a;     //c的类型是int   
auto d = &a;    //d的类型是int*
auto* e = &a;   //e的类型也是int*
int& f = a;     
auto& g = a;    //引用必须显示着写

4.2 注意点

1.有些时候(迭代器)定义对象时类型很长就可以使用auto

2.auto必须初始化 auto a;是不可以的

3.auto不能做参数和返回值,auto不能声明数组


五、基于范围的for循环

此前for循环需要我们自己设置范围,而对于一个有范围的集合而言,由程序员再说明范围是多余的,所以引进范围for。

for循环后括号由冒号分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围

5.1 遍历数组array

for (auto e : array)
{
    cout << e << " ";
}
cout << endl;

auto可以直接写成array数组的类型。上述表达式的含义是:依次取数组中数值赋值给e,自动判断结束,自动++往后走。e是每个值的拷贝

5.2 修改数组array

for(auto& e : array)
{
    e++;
}

 此时只能使用引用&,不能使用指针

5.3 错误写法

for的范围必须是确定的,以下写法是错误的,for的范围不确定,因为函数传进来的是指针,而for对于数组必须要明确数组的第一个元素和最后一个元素的范围。数组如果是在函数中定义的没问题。

void TestFor(int array[])
{
    for(auto& e : array)
        cout << e << endl;
}

六、nullptr 

这是C++为C语言打的一个补丁。

在C语言中NULL是一个宏,点击头文件#include <stdio.h> 右击查看代码,可以找到↓

所以在表达式中int* ptr = NULL;其实是int* ptr = 0; NULL表示的并不是一个空指针,编译器在默认情况下将其看成是一个整型变量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0

比如在以下程序中就会出现违背初衷想法的调用

void f(int)
{
    cout << "void f(int)" << endl;
}
void f(int*)
{
    cout << "void f(int*)" << endl;
}

int main()
{
    f(0);
    f(NULL);
    f((int*)NULL);
    return 0;
}

C++使用nullptr是真正意义上的空指针,以后定义空指针最好使用它

int* ptr = nullptr;


——The End——

  • 27
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王_哈_哈 Jw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值