ch02.对象与基本类型目录
- 从初始化 / 赋值语句谈起
- 类型详述
- 复合类型:从指针到引用
- 常量类型与常量表达式
- 类型别名与类型的自动推导
- 域与对象的生命周期
一.从初始化 / 赋值语句谈起
初始化/赋值语句是程序中最基本的操作,其功能是将某个值与一个对象关联起来
int x = 10;//初始化+赋值
x = 20;//赋值
int y = 30;
x = y;//此时y为对象,字面值
- 值:字面值、对象(变量或常量)所表示的值 ……
- 标识符:变量、常量、引用 ……
- 初始化基本操作:
- 在内存中开辟空间,保存相应的数值
- 在编译器中构造符号表,将标识符与相关内存空间关联起来
- 值与对象都有类型
- 初始化 / 赋值可能涉及到类型转换
int x = 10.5;//直接扔掉小数部分
二.类型详述
- 类型是一个编译期概念,可执行文件中不存在类型的概念
- C++ 是强类型语言
- 引入类型是为了更好地描述程序,防止误用
- 类型描述了:
- 存储所需要的尺寸 (sizeof ,标准并没有严格限制 )
- 取值空间 (std::numeric_limits ,超过范围可能产生溢出 )
#include<limits>//需要包含这个头文件 std::cout<<std::numeric_limits<int>::min()<<std::endl; std::cout<<std::numeric_limits<int>::max()<<std::endl; //取值空间可以用来判断是否溢出 - 对齐信息( alignof )
alignof(int);//对齐信息 struct str{ char h; int x; }; sizeof(str) = 8;```c 8000-8003 7999-8002;//没对齐需要读取两次
- 可以执行的操作
- 类型可以划分为基本类型与复杂类型
- 基本(内建)类型: C++ 语言中所支持的类型
- 数值类型
- 字符类型( char, wchar_t, char16_t, char32_t .分别为1,2,2,4字节 )
- 整数类型 a.带符号整数类型: short, int, long, long long. 分别为2,4,8,8字节 b.无符号整数类型: unsigned + 带符号整数类型
- 浮点类型 a.float, double, long double; 分别为4,8,16字节
- void
- 数值类型
- 复杂类型:由基本类型组合(结构体组合)、变种所产生的类型(指针,引用,const),可能是标准库引入(vector,string),或自定义类型
- 基本(内建)类型: C++ 语言中所支持的类型
- 与类型相关的标准未定义部分
- 字面值:在程序中直接表示为一个具体数值或字符串的值
- 每个字面值都有其类型
- 整数字面值: 20 (十进制), 024 (八进制), 0x14 (十六进制) – int 型
- 浮点数: 1.3, 1e8($1*10^8$) - double 型
- 字符字面值: ‘c’, ‘\n’, ‘\x4d’(十六进制) - char 型
- 字符串字面值: “Hello”(自带’\0’) - char[6] 型
- 布尔字面值: true, false - bool 型
- 指针字面值: nullptr - nullptr_t 型
- 可以为字面值引入前缀或后缀以改变其类型
- 1.3 ( 默认为double ) – 1.3f ( float )
- 2 ( int ) – 2ULL (unsigned long long)
- 可以引入自定义后缀来修改字面值类型
int operator "" w(long double x){ return (int)x * 2; } int x = 3.144w;// 此时x为6
2.2.类型详述 — 变量及其类型
- 变量:对应了一段存储空间,可以改变其中内容
- 变量的类型在其首次声明(定义)时指定:
- int x : 定义一个变量 x ,其类型为 int
- 变量声明与定义的区别: extern 前缀
- 变量的初始化与赋值
- 初始化:在构造变量之初为其赋予的初始值
- 缺省初始化
- 直接 / 拷贝初始化
- 其它初始化
- 赋值:修改变量所保存的数值
- 初始化:在构造变量之初为其赋予的初始值
2.3.类型详述 — (隐式)类型转换
- 为变量赋值时可能涉及到类型转换
- bool 与 整数之间的转换
- 浮点数与整数之间的类型转换
eg: float x = 1.3;//实际上1.3为double类型
- 隐式类型转换不只发生在赋值时
int val = 42;
int* p = &val;
- 特点
- 可以“指向”不同的对象
- 具有相同的尺寸 ==> 32位机为4字节
- 相关操作
- \& - 取地址操作符
- * - 解引用操作符
- 指针的定义
- int* p = &val;
- int* p = nullptr;
3.2.关于 nullptr
- 一个特殊的对象(类型为 nullptr_t ),表示空指针
- 类似于 C 中的 NULL ,但更加安全
3.3.指针与 bool 的隐式转换
非空指针可以转换为 true ;空指针可以转换为 false
3.4.指针的主要操作
解引用;增加、减少;判等
3.5.void* 指针
- 没有记录对象的尺寸信息,可以保存任意地址
- 支持判等操作
3.6.指针的指针

3.7.指针 V.S. 对象
- 指针复制成本低,读写成本高
3.8.指针的问题
- 可以为空
- 地址信息可能非法
- 解决方案:引用
3.9.引用
- int& ref = val;
- 是对象的别名,不能绑定字面值
- 构造时绑定对象,在其生命周期内不能绑定其它对象(赋值操作会改变对象内 容)
- 不存在空引用,但可能存在非法引用——总的来说比指针安全
- 属于编译期概念,在底层还是通过指针实现
3.10.指针的引用
- 指针是对象,因此可以定义引用
- int* p = &val; int* &ref = p; 从右到左进行解析,ref是一个引用,引用的是指针对象,指针指向了一个int型变量
- 类型信息从右向左解析
不存在引用的引用
四.常量类型与常量表达式
4.1.常量与变量相对,表示不可修改的对象
- 使用 const 声明常量对象
- 是编译期概念,编译器利用其
- const int* p;
const
int* p;//去掉类型,就可以看到const修饰的是谁 - int* const p;
- const int* const p;
- 常量指针可指向变量
4.3.常量引用(也可绑定变量)
- const int&
- 可读但不可写
- 主要用于函数形参
struct str{ //... } void fun(const str & param){ param = ...;//报错,只读 } int main(){ str x; fun(x); } - 可以绑定字面值:
const int &tmp = 10;4.4.常量表达式 (从 C++11 开始)
- 使用 constexpr 声明
- 声明的是编译期常量
int main(){ int x; cin >> x; const int &y1 = x;// 运行期 ==> constexpr int &y1 = x;// 报错!! const int &y2 = 3;// 编译器 ==> constrxpr int &y2 = 3;// 合法!! if(y1 == 3) if(y2 == 3) } - 编译器可以利用其进行优化
- 常量表达式指针: constexpr 位于 * 左侧,但表示指针是常量表达式
const char* ptr = "123"; ==> constexpr const char* ptr = "123"; constexpr const char* ptr = "123"; <==> const char* const ptr = "123";
五.类型别名与类型的自动推导
- 可以为类型引入别名,从而引入特殊的含义或便于使用(如: size_t )
5.1.两种引入类型别名的方式
- typedef int MyInt;
- using MyInt = int; (从 C++11 开始)
5.2.使用 using 引入类型别名更好
- typedef char MyCharArr[4];
- using MyCharArr = char[4];
5.3.类型别名与指针、引用的关系
- 应将指针类型别名视为一个整体,在此基础上引入常量表示指针为常量的类型
int x = 3; const int* ptr = &x; int y = 0; ptr = &y;//正确;*ptr为const, ptr不是const ----------------- using IntPtr = int*; const IntPtr ptr = &x;//此时int*为一个整体 int y = 0; ptr = &y;//错误;ptr为const - 不能通过类型别名构造引用的引用类型别名与类型的自动推导
include<type_traits> using RefInt = int&; using RefRefInt = RefInt&; std::is_same_v<RefInt, RefRefInt> ==>is_same_v<>,判断类型是否相等,相等为1
5.4.类型的自动推导
- 从 C++11 开始,可以通过初始化表达式自动推导对象类型
- 自动推导类型并不意味着弱化类型,对象还是强类型
- 自动推导的几种常见形式
- auto: 最常用的形式,但会产生类型退化
int x = 3; int &ref = x; auto ref2 = ref;//ref2退化为int,因为ref为右值 - const auto / constexpr auto: 推导出的是常量 / 常量表达式类型
- auto& : 推导出引用类型,避免类型退化
const int& x = 3; auto& y = x;// auto& 推导出来的y 为const int& 不会产生类型退化 - decltype(exp) :返回 exp 表达式的类型(左值加引用)
- decltype(val) :返回 val 的类型
- decltype(auto) :从 c++14 开始支持,简化 decltype 使用
- concept auto :从 C++20 开始支持,表示一系列类型( std::integral auto x = 3; )
- auto: 最常用的形式,但会产生类型退化
六.域与对象的生命周期
- 域 (scope) 表示了程序中的一部分,其中的名称有唯一的含义
- 全局域( global scope ):程序最外围的域,其中定义的是全局对象
- 块域( block scope ),使用大括号所限定的域,其中定义的是局部对象
- 还存在其它的域:类域,名字空间域……
- 域可以嵌套,嵌套域中定义的名称可以隐藏外部域中定义的名称
- 对象的生命周期起始于被初始化的时刻,终止于被销毁的时刻
- 通常来说
- 全局对象的生命周期是整个程序的运行期间
- 局部对象生命周期起源于对象的初始化位置,终止于所在域被执行完成

