【C++】5.对象与基本类型[深蓝学院C++第3章]
一.从初始化/赋值语句谈起
初始化语句 int x=10;
赋值语句 x=20;
初始化/赋值语句是程序中最基本的操作,其功能是将某个值与一个对象关联起来。
值:字面值(如直接的数字10、字符串)、对象所表示的值。。。
标识符:变量、常量、引用&。。。
初始化基本操作:开辟内存并保存相应的数值、在编译器中构造符号表并将标识符与对应的内存空间关联起来 。
值和对象都有类型。
初始化/赋值可能涉及到类型转换。int x=10.5;
二.类型详述
2.1基本概念
类型是一个编译器概念,可执行文件中不存在类型的概念。
C++是强类型概念。
引入类型是为了更好地描述程序,防止误用。
类型描述了:
(1)存储所需要的尺寸,sizeof可以获得,C++语言本身并没有限定类型的尺寸;
(2)取值空间,查找std::numeric_limits,如int:(-2^31)~(2^31-1);
(3)对其信息,方便CPU-catch-内存的读取,可以使用alignof()函数来读取类型的对齐信息;
(4)可以执行的操作。
2.2种类
基本类型和复杂类型
基本类型:C++语言中内建的支持的类型,包括:
数值类型(字符类型、整数类型、浮点类型)和void。各数值类型所占内存大小可具体通过程序读取。
复杂类型:由基本类型组合、变种所产生的类型,可能是标准库引入或者是自定义类型。
2.3标准中未定义的部分
(1)char是否有符号,可以通过unsigned和signed明确指出是否有符号;
(2)整数中内存中的保存方式,是大端还是小端,
(3)每种类型的大小,除非指定bit尺寸。
2.4字面值及其类型
(1)字面值:在程序中直接表示为一个具体数值或字符串的值
(2)每个字面值都有类型,如:
– 整数字面值: 20 (十进制), 024 (八进制), 0x14 (十六进制) -- int 型
– 浮点数: 1.3, 1e8 – double 型
– 字符字面值: 'c', '\n', '\x4d' – char 型
– 字符串字面值: "Hello" – char[6] 型
– 布尔字面值: true, false – bool 型
– 指针字面值: nullptr – nullptr_t 型
(3)可以为字面值引入前缀或后缀以改变其类型,前/后缀可以是自定义后缀
– 1.3 ( double ) -- 1.3f ( float )
– 2 ( int ) -- 2ULL (unsigned long long)
另外,自定义后缀有专用函数
2.5变量及其类型
(1)变量:对应了一段存储空间,可以改变其中内容;
(2)变量的类型在其首次声明(定义)时指定:
– int x : 定义一个变量 x ,其类型为 int
– 变量声明与定义的区别: extern 前缀,便于通过编译
(3)变量的初始化与赋值
初始化:在构造变量之初为其赋予的初始值
● 缺省初始化
● 直接 / 拷贝初始化
● 其它初始化
赋值:修改变量所保存的数值
2.6隐式类型转换
(1)为变量赋值时可能涉及到类型转换,bool与整数、浮点数与整数,发生类型降级或类型升级;
(2)其他隐式类型转换,如if判断、数值比较,比如无符号数和带符号数进行比较时会转为有符号数再比较;
2.7显式类型转换
参考资料:https://blog.csdn.net/Chauncyxu/article/details/119322610
较旧的版本中提供了类C和函数式两种强制转换,分别为(int)a和int(a)。
为了约束这种不受限制的显式类型转换(允许将任何指针转换为任何其他指针类型)
在C++11后提供了4种新式转换,分别为const_cast、static_cast、dynamic_cast、reinterpret_cast
2.7.1const_cast
1 const char * c = "sample text"; 2 print ( const_cast<char *> (c) );
将const变量转为非const,用于需要传入非const参数的函数。
注意,删除指向对象的常量或实际写入它会导致未定义的行为。
2.7.2static_cast
(1)在基类和派生类的指针之间,可以向上转换也可以向下转换,不执行任何检查以保证安全!
(2)可以执行隐式允许的所有转换及逆转换,如从void*转为其他指针类型、整数转为枚举、非const转const等;
(3)其他没看懂
2.7.3dynamic_cast
只能与类的指针和引用一起使用(或与void*一起使用),其目的是确保类型转换的结果指向目标指针类型的有效完整对象,也就是说要确保转换是安全的。
向上转换:派生类指针转换为基类指针,与隐式转换所允许的方式相同
向下转换:基类指针转为派生类指针时,要检查当前指针指向的是否是派生类的完整对象。
转换成功时返回相应正确的类型,转换失败时可能返回NULL或bad_cast异常。
其他操作:
(1)在指针类型之间转换空指针;
(2)将任何类型的任何指针转换为void*指针。
2.7.4reinterpret_cast
可以做任何类型的转换,既不检查指向的内容,也不检查指针类型本身,运算结果就是从一个指针到另外一个指针的二进制副本。
三.复合类型:从指针到引用
3.1指针的特点
(1)可以“指向”不同的对象,
(2)具有相同的尺寸;
(3)&,取地址操作符;
(4)*,解引用操作符;
3.2指针的定义与初始化
int* p=&val;
int* p=nullptr;//类似于C中的NULL,但更安全
指针与bool的隐式转换:非空指针可以转为true,空指针可以转为false
3.3指针的主要操作
解引用,*p
增加,p++
减少,p--
判等,if(p)
3.4void*指针
未记录对象尺寸信息,可保存任意地址(可以转为任意类型的指针类型),支持判断
3.5指针与对象的对比
(1)对函数入参时,指针复制成本低,读写成本高;对象相反;
(2)指针是对对象的一种间接引用,但可以修改源数据。
3.6指针的风险
(1)可以为空;
(2)地址信息可能非法;
解决方案:引用&
3.7引用类型&
int x;
int& y=x; //y是对x的引用
(1)引用是对象的别名,不能绑定字面值,因为引用其实还是要获取对象的地址;
(2)构造时绑定,生命周期内不能重绑定;
(3)不存在空引用,但可能存在非法引用,如引用对象生命周期已结束被销毁——总的来说比指针安全;
(4)编译期间,底层还是通过指针实现。
指针的引用:int*& p,是对一个int*的引用,因为类型信息要从右向左解析。
不存在引用的引用,因为要引用的对象需要是对象。
引用和指针的异同:
(1)指针保存的是地址,引用的底层实现也是地址,但引用更安全;
(2)指针由运行时赋值,而引用需要在编译期赋值。
引用的用途:
(1)作为复杂变量名称的别名:auto & whichList = theList[myHash(x, theList.size())];
(2)用于range-for循环;
(3)避免复制较大的对象,比如函数返回时;
(4)参与函数中的参数传递,在函数内可以修改对象数据。
四.常量与常量表达式类型
常量不可以修改,是一个编译时概念。
4.1需求来源
常用作形参,目的:
(1)防止非法操作;
(2)优化程序逻辑;
4.2常量指针与顶层常量
int* const p=&x;初始化之后,不能修改指向,即不能再指向其他对象;
const int* ptr;初始化之后,不能修改指向的内存的内容;
五.类型别名与类型的自动推导
5.1类型别名
可以为类型引入别名,从而引入特殊的含义或便于使用;
两种引入类型别名的方式:
(1)typedef int MyInt;
(2)using MyInt = int;
5.2类型的自动推导
从 C++11 开始,可以通过初始化表达式自动推导对象类型,
自动推导类型并不意味着弱化类型,对象还是强类型,
自动推导的几种常见形式:
(1)auto,最常用的形式,但会产生类型退化;
(2)const auto:推导出的是常量;
(3)auto&:推导出引用类型,避免类型退化。
注:类型退化,int x=0;int& y=x;int z=y;z把int引用退化为int
六.域与对象的生命周期
5.1域
种类:
(1)域 (scope) 表示了程序中的一部分,其中的名称有唯一的含义。
(2)全局域( global scope ):程序最外围的域,其中定义的是全局对象
(3)块域( block scope ),使用大括号所限定的域,其中定义的是局部对象
(4)其它的域:类域,名字空间域……
域可以嵌套,嵌套域中定义的名称可以隐藏外部域中定义的名称
5.2生命周期
对象的生命周期起始于被初始化的时刻,终止于被销毁的时刻
一般:
(1)全局对象的生命周期是整个程序的运行期间;
(2)局部对象生命周期起源于对象的初始化位置,终止于所在域被执行完成

浙公网安备 33010602011771号