【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)局部对象生命周期起源于对象的初始化位置,终止于所在域被执行完成

 

posted @ 2023-02-10 16:28  啊原来是这样呀  阅读(19)  评论(0)    收藏  举报