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++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

c++的初始化列表与const成员

初始化列表与const成员 const成员 使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。 不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。 在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。 初始化列表 在构造函数小括号后面,主要用于给

2024/9/8 c++ smart

1.通过自己编写的class来实现unique_ptr指针的功能 #include <iostream> using namespace std; template<class T> class unique_ptr { public:         //无参构造函数         unique_ptr();         //有参构造函数         unique_ptr(