第二章 C++基础(Ⅱ)

(5)const 和 constexpr 常量

1.定义时必须初始化

const int i = 42;	//正确
const int k;		//错误,const should be initialized
另:
char const *p2;		//正确

2.可以用非常量初始化

int i = 42;
const int j = i;	//正确,拷贝完成后j的值与i没什么关系了

3.默认情况下仅在文件内有效

如果多个文件声明了同名const变量,编译器认为是不同的变量。若要在多个文件中使用同一个const,需要在声明和定义时,均添加extern关键字,这样只需要定义一次就可以了。

4.const与constexpr区别在于

const未区分编译期常量和运行期常量,constexpr限定编译期常量。
即constexpr变量必须在编译时进行初始化,而const变量的初始化可以延迟到运行时

与指针的关系:

  • 指针和const

指针和常量结合在一起可以组合成指针常量、常量指针以及指向常量的指针常量(前两者的结合)。结合在一起到底是哪一个可以从常量符号const和指针符号*的先后顺序来判断。const在*前则是常量指针,如果*在const之前则是指针常量。

const*号)左边放,我是指针变量(常量指针)指向常量;(指针指向的值(对象)不可改变,但指针的值可以改变)
const*号)右边放,我是指针常量指向变量;(指针本身不能改变,指针指向的值可以改变)
const*号)两边放,我是指针常量指向常量;

(1)指针常量
int i = 0;
int* const j = &i;
 ↑ ↑
指针 常量
指针常量指的是指向的指针(地址)是常量,指针本身不能改变,指针指向的值可以改变。用名词顶层const表示指针本身是个常量。

(2)常量指针
int i = 0;
int const * j = &i;
  ↑  ↑ 
 常量 指针
常量指针指的是指针指向的值(对象)不可改变,但指针的值可以改变。用名词底层const表示指针所指的对象是一个常量。

!!敲黑板 !!

const对象的地址只能赋给const对象的指针,指向const对象的指针可以被赋予一个非const对象的地址,否则将会报错

  • 指针和constexpr

在constexpr声明中如果定义了一个指针,限定符constexpr仅仅对指针有效(变成顶层const),与指针所指的对象无关:

const  int  *p= nullptr;     		// p是一个指向整型常量的指针,常量指针,底层const
constexpr  int  *q = nullptr;    	// q是一个指向整数的常量指针,指针常量,顶层const

const的引用

可以把引用绑定到const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用。与普通引用不同是的,对常量的引用不能被用作修改它所绑定的对象。

const  int  ci = 42;
const  int  &r1 = ci;		//正确:引用及其对应的对象都是常量
r1= 42;    		 			//错误:r1是对常量的引用,不能修改
int  &r2 = ci;    	 	 	// 错误:试图让一个非常量引用指向一个常量对象

允许将一个const int&绑定到一个普通的int对象上

const double &ff=10;			//正确
int i=10;
const int &ir=i+10;				//正确
int &ii=3;						//错误

该结果与编译器的处理方式有关

顶层const和底层const

首先,const是一个限定符,被它修饰的变量的值不能改变。对于一般的变量来说,其实没有顶层const和底层const的区别,而只有向指针这类复合类型的基本变量,才有这样的区别。

指针实际上定义了两个对象:指针本身和它所指的对象。这两个对象都可以用const进行限定

当指针本身被限定为常量时称指针为顶层const
当所指的对象被限定为常量,而指针本身未被限定时,称指针为底层const:
当指针和所指对象两者都被限定为常量时,则指针为顶层const,所指对象为底层const

  • 复制顶层const不受影响

  • 底层const的复制受限制

一般而言,非常量能够转化为常量,反之则不行
执行对象拷贝时有限制,常量的底层const不能赋值给非常量的底层const

int num_c = 3;
const int *p_c = &num_c;  //p_c为底层const的指针
//int *p_d = p_c;  //错误,不能将底层const指针赋值给非底层const指针
const int *p_d = p_c; //正确,可以将底层const指针复制给底层const指针

(6)auto和decltype

auto
auto 变量名1=表达式1,变量名2=表达式2

auto使编译器运用从表达式结果推断出的类型定义变量,并用表达式的结果值初始化定义的变量。auto 一般忽略表达式的顶层const和引用的const,而指针底层const则会保留下来。

用auto设置一个引用类型时,初始值中的顶层const会被保留,而引用字面常量时需要指定为const 引用。

由于auto需要根据表达式的值推断数据类型,所以要求在用auto定义变量时,表达式的类型是清楚而明确的。另外,auto 也是一种变量定义语句,可以在一条语 句中同时定义多个变量,但数据类型只能有一种。

auto会用表达式的值初始化其定义的变量,如果只需定义变量,不想用表达式值初始化它,则可用deltype
decltype

deltype(表达式)		变量=表达式;
deltype((表达式))	变量=表达式; 	//定义引用

decltype用于从表达式推断出类型并定义变量,但不用表达式的值初始化定义的变量。与auto不同的是,decltype不会忽略顶层const,其结果是定义与变量相同类型的变量(包括顶层const和引用在内)。


当用双重括号把表达式括起来时,定义的一定是引用。而用单括号时,只有当变量本身是引用时,定义的才是引用。

(7)函数重载解析过程

把函数调用与多个同名重载函数中的某个函数相关联的过程称为函数重载解析。在具有多个同名函数的情况下,需要找到形式参数与实参表达式类型匹配最好的那个函数。C++进行函数参数匹配的原则和次序如下。

精确匹配。精确匹配是指实参与函数的形式参数类型完全相同,不需要做任何转换或只需进行要平凡转换(如从数组名到指针、函数名到函数指针或 T 到 const T等)的参数匹配。

提升匹配。提升主要是指从窄类型到宽类型的转换,这种转换没有精度损失,包括整数提升和float到double的提升。整数提升包括从bool到int、char 到int、short 到int,以及它们的无符号版本,如unsigned short到unsigned int的提升。

标准转换匹配。如int到double、double 到int、double到long double,派生类指针到基类指针的转换(将在第4章讲述),如T到void、int 到unsigned int的转换。

用户定义的类型转换。在C++语言中,程序员可以定义类型转换函数。如果在程序中定义了这样的转换函数,这些转换函数也会用于重载函数的匹配。

(8)内联函数

在函数声明或者定义时,将inline关键字加在返回类型前面的函数就是将它指定为内联函数

说明:
①内联函数的声明或定义必须在函数的调用之前完成:
②一般而言,只有几行程序代码的(最好只有1~5行)、经常被调用的简单函数才适宜作为内联函数;
③inline 关键字仅是对编译器的一种建议,并非写上inline的函数就一定是内联函数,将复杂函数指定为inline 函数是无效的,编译器还是会把它处理成普通函数。例如,以下3类函数就不能作为内联函数:递归函数,函数体内含有循环、switch 语句之类复杂结构的函数,或者具有较多程序代码的大函数。

(9)预处理器

  • #define和#undef
    #define用于定义宏
    #undef用于删除#define定义的宏

eg.

#define pi  3,1415
#undef pi
  • 条件编译
    (1)
#ifdef 标识符
	语句1
[#else
	语句2
]
#endif

[ ] 中内容可不写
(2)

#ifndef 标识符
	语句1
[#else
	语句2
]
#endif

[ ] 中内容可不写



第二章 完










部分内容转载自其他博客...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值