C++新经典07--auto、头文件防卫、引用与常量

auto的使用

严格来讲,在C语言中,如果某个函数中需要用到一些局部变量,那么局部变量都会集中定义在函数开头,而在C++中不必遵循这样的规则,随时用随时定义即可。当然,作用域一般就是从定义的地方开始到该函数结束为止。当然,也有例外,例如如果在一个循环中定义的变量就只在循环内有效,在一个{}包着的语句块中定义的变量就只能在该语句块内有效。典型的如for(int i=0;i<100;i++){…},i的作用域就仅仅限制在for循环体内。传统编码方式中,可以使用“=”在定义变量的时候进行初始化。代码如下:

int abc = 5;

在C++新标准中,可以使用“{}”在定义变量的时候进行初始化。代码如下:

int abc {5};

所以,针对刚才的for语句,可以换一种写法。代码如下:
在这里插入图片描述
在看到了C++新标准中“{}”的用法后,需要额外说明的是,在“{}”之前还可以增加一个“=”号。如下代码:

在这里插入图片描述
在上面的“{}”用法中,只涉及一个数据,因为只有一个变量来接收数据。实际上,如果定义一个数组,那么是可以在“{}”中包含一组数据的。代码如下:
在这里插入图片描述
建议在学习的时候,把这些新标准的写法单独整理和记录一下,新标准中引入“{}”这种给变量初值的方法也是有一些考虑和好处的。例如下面这行语句:
在这里插入图片描述
上面这行代码是可以编译通过的,但执行起来后会发现,实际上abc因为是int类型,所以3.5的小数部分会被截断,结果是abc的值等于3。那下面这种C++新标准语法呢?
在这里插入图片描述
上面这行代码根本无法编译通过,直接报语法错,这样做的好处是不会使数据被误截断,进一步保证所写的代码的健壮性。
再看一例,用“()”也可以对变量进行初始化:
在这里插入图片描述

auto关键字简介

auto关键字其实在C++98中就已经有了,只是那时候这个关键字没什么作用,但是到了C++11中,auto被赋予了全新的含义——变量的自动类型推断。

auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型(这表明在声明变量的同时也要给变量初始值)。auto的自动类型推断发生在编译期,所以使用auto并不会造成程序运行时效率的降低。

换句话说,在定义一个变量的时候,如果变量类型能够由系统推断出来,就不需要显示指定类型。看看如下范例:
在这里插入图片描述

有些类型名很长,如后面要学习到的泛型,那么,使用auto就能避免书写很长的类型名。

头文件防卫式声明

C/C++头文件中有关于#ifndef、#define、#endif的用法。
通过下面的语言描述创建一个范例:
(1)头文件head.h中有如下定义:

int g_globalh1 = 8;

(2)头文件head2.h中有如下定义:

int g_globalh2 = 5;

(3)在主源文件(MyProject.cpp)中需要用这两个全局变量,代码如下:

#include "head.h"
#include "head2.h"
int main()	//主函数
{
	cout <g_globalh1 <endl;	//8
	cout <g_globalh2 <endl;	//15
}

执行上面这段代码,目前为止并没有什么问题。
(4)随着项目的增大,需要定义更多复杂的数据类型,假如现在因为一些原因需要在头文件head2.h中包含头文件head.h,于是头文件head2.h内容修改如下:

#include "head.h"
int g_globalh2 = 5;

此时编译,出现重定义错误。这是因为在源文件MyProject.cpp文件中有如下内容:

#include "head.h"
int g_globalh2 = 5;

如果上面这两行代码都展开,则结果如下:
在这里插入图片描述

显然globalh1被定义了两次,因此编译的时候提示出现重定义错误。

这非常让人头疼,因为保不准哪个头文件就#include了其他头文件,也保不准哪个.cpp源文件无意中就#include两次同一个头文件,上面这种是间接通过head2.h重复#include了head.h,那直接重复#include也是不可以的。例如如下代码,系统编译时也会报错:

在这里插入图片描述

既然重复#include的问题时有发生,无法避免,那么如何解决这个问题呢?

这就要从.h头文件本身入手,通过使用#ifndef、#define、#endif解决这个问题。首先,改造头文件head.h。改造后的内容如下:

#ifndef __HEAD__
#define __HEAD__
int g_globalh1 = 8;
#endif

接着,改造头文件head2.h。改造后的内容如下:

#ifndef __HEAD2__
#define __HEAD2__
#include "head.h"
int g_globalh2 = 5;
#endif

有一点必须说明:每一个.h头文件的#ifndef后面定义的名字都不一样,不可以重名。
如此修改后再次编译,不难发现,编译通过并能成功执行,奥妙在哪里?就在于通过使用#ifndef、#define、#endif的组合,避免了.h头文件中的内容被多次#include。例如当head.h第一次被#include到MyProject.cpp中时,#ifndef HEAD条件成立,因此下面两行代码都被#include到MyProject.cpp中:
在这里插入图片描述
但是假如第二次head.h被#include到MyProject.cpp中时,#ifndef HEAD条件就不成立了(因为#define HEAD代码行的存在),这样,上面两行内容就不会再次被#include到MyProject.cpp中,从而避免了重定义等错误的发生。

所以要求读者在书写.h头文件的时候,要习惯性地在文件头部增加#ifndef、#define语句行,在文件末尾增加#endif语句行。出现在.h头文件中的这三行代码,被习惯性地称为“头文件防卫式声明”。

引用

引用是为变量起的另外一个名字(别名),一般用“&”符号(以往看到过该符号,但含义与这里并不相同)表示。之后,该引用和原变量名代表的变量看成是同一个变量。所以,在理解时要理解成:定义引用并不额外占用内存。或者也可以理解成,引用和原变量占用的是同一块内存。
看看如下范例:
在这里插入图片描述
定义引用类型的时候必须进行初始化,不然给哪个变量起别名呢?看看如下范例,找找代码行中的错误:
在这里插入图片描述

看看如下范例,注意比较,看看“&”作为引用和作为取地址符时的使用区别:
在这里插入图片描述
再看一个比较完整的范例——引用作为函数形参:

#include <iostream>
using namespace std;
void func(int &ta,int &tb)   	//形参类型都是引用类型(整型引用) @
{
	ta = 4;        //改ta和tb值直接影响到main()中的a和b
	tb = 5;
}
int main()        //主函数
{
	int a = 13;
	int b = 14;
	func(a, b);
	cout << a <<" "<< b<< std::endl;	//4 5
	return 0;
}

常量

常量就是不变的量。前面讲解的常量一般都是具体的数值,如10、23.5等。

1.const关键字

该关键字有很多作用,但这里不准备多介绍,主要是先熟悉一下。const表示不变的意思。定义变量时,可以在前面增加const关键字,一旦增加该关键字,该变量的值就不可以发生改变。看看如下范例:
在这里插入图片描述

2.constexpr关键字

这是C++11引入的关键字,也代表一个常量的概念,意思是在编译的时候求值,所以能够提升运行时的性能。编译阶段就知道值也会带来其他好处,例如更利于做一些系统优化工作等。看看如下范例:

constexpr int var1 = 1;
constexpr int var2 = 11 * func1(12);

上面代码用到了func1函数,那func1函数要怎样写呢?这里必须注意,因为var2是常量,初始化时调用了func1函数,所以func1也得定义成constexpr。代码如下:

constexpr int func1(int abc)
{
	abc = 16;
	int a3 =5;
	return abc * a3;
}

但是,在书写func1函数时必须小心,其中的代码尽可能简单。而且,某些代码出现在func1函数中还会导致编译无法通过。例如,在func1函数中定义一个未初始化的变量就会导致编译出错,必须在定义的时候初始化:

int unvar;	//编译时会引发错误,必须在定义的时候初始化

再如,如果下面的for循环语句出现在func1函数中,那么for循环中的printf语句也同样会引发编译错误,

for (int i = 0;i < 100; i++)
{
	//这句printf也会导致编译不过。不是这个函数有问题,而是constexpr关键字的问题
	printf("good");
}

还可以进行一些尝试:

int k = 3;
constexpr int var= 11 * func1(k);	//编译错误,不可以用变量k作为参数
int k2 = func1(k);		//用变量k调用constexpr函数不会有问题,
					//此时该函数相当于普通函数,结果当然也是在执行期间产生

可以看到,加了constexpr修饰的函数不但能用在常量表达式中,也能用在常规的函数调用中。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值