C++ Primer Chapter 2 Variables and Basic Types

2024-05-30 15:20

本文主要是介绍C++ Primer Chapter 2 Variables and Basic Types,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C++ Primer Chapter 2 Variables and Basic Types

2024/05/27
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变量时,七十年等同于在不同文件中分别定义了独立的变量。
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。

这篇关于C++ Primer Chapter 2 Variables and Basic Types的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1016441

相关文章

关于C++中的虚拟继承的一些总结(虚拟继承,覆盖,派生,隐藏)

1.为什么要引入虚拟继承 虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下: class A class B1:public virtual A; class B2:pu

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

C++的模板(八):子系统

平常所见的大部分模板代码,模板所传的参数类型,到了模板里面,或实例化为对象,或嵌入模板内部结构中,或在模板内又派生了子类。不管怎样,最终他们在模板内,直接或间接,都实例化成对象了。 但这不是唯一的用法。试想一下。如果在模板内限制调用参数类型的构造函数会发生什么?参数类的对象在模板内无法构造。他们只能从模板的成员函数传入。模板不保存这些对象或者只保存他们的指针。因为构造函数被分离,这些指针在模板外

C++工程编译链接错误汇总VisualStudio

目录 一些小的知识点 make工具 可以使用windows下的事件查看器崩溃的地方 dumpbin工具查看dll是32位还是64位的 _MSC_VER .cc 和.cpp 【VC++目录中的包含目录】 vs 【C/C++常规中的附加包含目录】——头文件所在目录如何怎么添加,添加了以后搜索头文件就会到这些个路径下搜索了 include<> 和 include"" WinMain 和

C/C++的编译和链接过程

目录 从源文件生成可执行文件(书中第2章) 1.Preprocessing预处理——预处理器cpp 2.Compilation编译——编译器cll ps:vs中优化选项设置 3.Assembly汇编——汇编器as ps:vs中汇编输出文件设置 4.Linking链接——链接器ld 符号 模块,库 链接过程——链接器 链接过程 1.简单链接的例子 2.链接过程 3.地址和

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C++学习 贝蒂的主页:Betty’s blog 1. 泛型编程 首先让我们来思考一个问题,如何实现一个交换函数? void swap(int& x, int& y){int tmp = x;x = y;y = tmp;} 相信大家很快就能写出上面这段代码,但是如果要求这个交换函数支持字符型

C++入门01

1、.h和.cpp 源文件 (.cpp)源文件是C++程序的实际实现代码文件,其中包含了具体的函数和类的定义、实现以及其他相关的代码。主要特点如下:实现代码: 源文件中包含了函数、类的具体实现代码,用于实现程序的功能。编译单元: 源文件通常是一个编译单元,即单独编译的基本单位。每个源文件都会经过编译器的处理,生成对应的目标文件。包含头文件: 源文件可以通过#include指令引入头文件,以使

C++面试八股文:std::deque用过吗?

100编程书屋_孔夫子旧书网 某日二师兄参加XXX科技公司的C++工程师开发岗位第26面: 面试官:deque用过吗? 二师兄:说实话,很少用,基本没用过。 面试官:为什么? 二师兄:因为使用它的场景很少,大部分需要性能、且需要自动扩容的时候使用vector,需要随机插入和删除的时候可以使用list。 面试官:那你知道STL中的stack是如何实现的吗? 二师兄:默认情况下,stack使

剑指offer(C++)--孩子们的游戏(圆圈中最后剩下的数)

题目 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去

剑指offer(C++)--扑克牌顺子

题目 LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为1