C++ Primer Chapter 2 Variables and Basic Types

C++ Primer Chapter 2 Variables and Basic Types

2024/05/27

2.2 变量

2.2.1 变量定义

初始值

2.3 复合类型

引用
定义
通过将声明符写成&d的形式来定义引用类型,其中d是声明的变量名。
int ival=1024;
int &refVal=ival;
int &refVal2;
//报错:引用必须被初始化

引用即别名
引用并非对象,相反的,它只是为一个已经存在的对象所起的另外一个名字。

定义了一个引用之后,对其进行的所有操作都是在与之绑定的对象上进行的:
refVal=2;
int ii=refVal;

为引用赋值,实际上是把值付给了与引用绑定的对象。
获取引用的值,实际上获取了与引用绑定的对象的值。
以引用作为初始值,实际上是以与引用绑定的对象作为初始值:

int &refVal3=refVal; //正确,refVal3绑定到了那个与refVal绑定的对象上,这里就是绑定在ival上
int i=refVal //正确:i被初始化为ival的值

因为引用不是一个对象,所以不能定义引用的引用。

指针

指针本身就是一个对象,允许对指针进行赋值和拷贝,而且在指针的声明周期内它可以先后指向几个不同的对象。
指针无须在定义时赋初值。和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。

定义
int ival=42;
int *p=&ival;
取地址符(&)
指针值

指针的值(即地址)应属于下列4种状态之一:
1.指向一个对象。
2.指向紧邻对象所占空间的下一个位置。
3.空指针,意味着指针没有指向任何对象。
4.无效指针,也就是上述情况之外的其他值。

解引用符(*)
int ival=42;
int *p=&ival; //p存放着变量ival的地址,或者说p是指向变量ival的指针。

cout<<p; //由符号得到指针p所指的对象,输出42

p=0; //由符号得到指针p所指的对象,即可经由p为变量ival赋值

cout<<*p; //输出0

Note 解引用操作仅适用于那些确实指向了某个对象的有效指针。

空指针(null pointer)不指向人很对象,在试图使用一个指针之前可以首先检查它是否为空。

以下列出了几种生成空指针的方法:
int *p1=nullptr;
int *p2=0;
//需要首先#include cstdlib
int *p3=NULL;

把int变量直接赋值给指针是错误的操作,即使int变量的值恰好等于0也不行。
int zero=0;
int *pi=zero; //错误:不能把int变量直接赋给指针
建议:初始化所有指针

赋值和指针
赋值永远改变的是等号左侧的对象

其他指针操作
指针用在条件表达式中

int ival=1024;
int *pi=0;			//pi合法,是一个空指针
int *pi2=&ival;		//pi2是一个合法的指针,存放着ival的地址

if(pi)				//pi的值是0,因此条件的值是false
	//		
if(pi2)				//pi2指向ival,因此它的值不是0,条件的值是true
	//

void*指针
void是一种特殊的指针类型,可用于存放任意对象的地址。一个void指针存放着一个地址,这一点和其他指针类似。不同的是,我们对该地址中到底是个什么类型的对象并不了解:

2.3.3理解复合类型的声明

WARNING 很多程序员容易迷惑于基本数据类型和类型修饰符的关系,其实后者不过是声明符的一部分罢了。

指向指针的引用
引用本身不是一个对象,因此不能定义指向引用的指针。但指针是对象,所以存在对指针的引用:

int i=31;
int *p;			//p是一个int型指针
int *&r=p;		//r是一个对指针p的引用
r=&i;			//r引用了一个指针,因此给r赋值&i就是令p指向i
*r=0;			//解引用r得到i,也就是p指向的对象,将i的值改为0

要理解r的类型到底是什么,最简单的办法是从右向左阅读r的定义。离变量名最近的符号(此例中的是&r的符号&)对变量的类型有最直接的影响,因此r是一个引用。声明符的其余部分用以确定r引用的类型是什么,此例中的符号*说明r引用的是一个指针,最后,声明的基本数据类型部分指出r引用的是一个int指针。

Tip 面对一条比较复杂的指针或引用的声明语句时,从右向左阅读有助于弄清楚它的真实含义。

2.4 const限定符

因为const对象一旦创建后其值就不能再改变,所以const对象必须初始化。一如既往,初始值可以是任意复杂的表达式:

只能在const类型的对象上执行不改变其内容的操作

在不改变const对象的操作中还有一种是初始化,如果利用一个对象去初始化另外一个对象,则它们是不是const都无关紧要。
注解:在类的构造函数中也可对const对象进行初始化

默认情况下,const对象仅在文件内有效。
当多个文件中出现了同名的const变量时,七十年等同于在不同文件中分别定义了独立的变量。
Note 如果想在多个文件之间共享const对象,必须在变量的定义之前添加extern关键字。

2.4.1 const的引用

初始化和对const的引用

初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。
int i = 31;
const int& r1 = i;
const int& r2 = 31; //r2也绑定对象i,但是不允许通过r2修改i的值
const int& r3 = r1 * 2;
//非常量引用的初始值必须为左值
//int& r4 = r2*2;

对const的引用可能引用一个并非const的对象。

2.4.2 指针和const
指向常量的指针不能用于改变其所指对象的值。
要想存放常量对象的地址,只能使用指向常量的指针;

和常量引用一样,指向常量的指针也没有规定其所指的对象必须是一个常量。所谓指向常量的指针仅仅要求不能通过该指针改变对象的值,而没有规定那个对象的值不能通过其他途径改变。

Tip 试试这样想把:所谓指向常量的指针或引用,不过是指针或引用的“自以为是”罢了,他们觉得自己指向了常量,所以自觉地不去改变所指对象的值。

const指针
允许把指针本身定位常量。常量指针(const pointer)必须初始化,而且一旦初始化完成,则它的值(也就是存放在指针中的那个地址)就不能再改变了。
把*放在const关键字之前用以说明指针是一个常量,这样的书写形式隐含了一层意味,即不变的是指针本身的值而非指向的那个值:

指针本身是一个常量并不意味着不能通过指针修改其所指对象的值,能否这样做完全依赖于所指对象的类型。

2.4.3 顶层const

指针本身是一个对象,它又可以指向另外一个对象。因此,指针本身是不是常量以及指针所指的是不是一个常量就是两个相互独立的问题。用名词顶层const(top-level const)表示指针本身是个常量,而用名词底层const(low-level const)表示指针所指的对象是一个常量。
更一般的,顶层const可以表示任意的对象是常量,这一点对任何数据类型都适用,如算法类型、类、指针等。底层const则与指针和引用等复合类型的基本类型部分有关。

比较特殊的是,指针即可以是顶层const也可以是底层const,这一点与其他类型相比区别明显。

当执行对象的拷贝操作时,常量是顶层const还是底层const区别明显。
其中,顶层const不受什么影响:
执行拷贝操作并不会改变被拷贝对象的值,因此,拷入和拷出的对象是否是常量都没什么影响。
另一方面,底层const的限制却不能忽视。
当执行对象的拷贝操作时,拷入和拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换。
一般来说,非常量可以转换为常量,反之则不行。

2.4.4 constexpr和常量表达式

常量表达式(const expression)是指值不会改变并且在编译过程就能得到计算结果的表达式。
一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同决定。
2.4.4 constexpr和常量表达式
常量表达式(const expression)是指值不会改变并且在编译过程中就能得到计算结果的表达式。
一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同决定的。

const int max_files=20;				//max_files是常量表达式
const int limit=max_files+1;		//limit是常量表达式
int staff_size=27;					//staff_size不是常量表达式
const int sz=get_size();			//sz不是常量表达式,尽管sz本身是一个常量,但它的具体值知道运行时才能获取到,所以不是常量表达式。

constexpr变量
C++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化:

constexpr int sz=size();			//只有当size是一个constexpr函数时才是一条正确的声明

尽管不能使用普通函数作为constexpr变量的初始值,但是,新标准允许定义一种特殊的constexpr函数。这种函数应该足够简单以使得编译时就可以计算其结果,这样就能用constexpr函数去初始化constexpr变量了。
字面值类型
算数类型、引用和指针都属于字面值类型。
自定义类、IO库、string类型则不属于字面值类型,也就不能被定义成constexpr。

指针与constexpr

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

constexpr把它所定义的对象置为了顶层const。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值