C++ 变量一
文章目录
- 1.数据类型
- 1.基本数据类型
- 1.基本数据类型 int 默认有符号
- 2.基本数据类型 char
- 3.基本数据类型 浮点类型
- 4.其他
- 2.类型转换
- 1.隐式类型转换(自动转换)
- 1. 数值类型转换规则
- 2. 类类型转换
- 2.显式类型转换(强制转换)
- 3.C++ 风格显式类型转换
- 1.static_cast
- 2.dynamic_cast
- 1.RTTI
- 3.const_cast
- 4.reinterpret_cast
- 4.显式类型转换 vs. 隐式类型转换
- 5.C++ 风格显式类型转换 vs C 风格显式类型转换
1.数据类型
数据类型是编程语言中对数据的一种分类,用于定义数据的 取值范围 和 操作方式。它决定了数据在内存中的存储方式、占用空间大小,以及可以对该数据执行的运算(如算术运算、逻辑运算等)。
1.基本数据类型
由语言本身定义的内置类型,直接对应底层硬件的存储单元。
1.基本数据类型 int 默认有符号
- signed char 1 字节 -128 至 127 小整数、字符编码(ASCII)
- short 2 字节 -32,768 至 32,767 节省空间的整数
- int 4 字节 -2,147,483,648 至 2,147,483,647 常规整数计算
- long 4 字节(32 位系统)/ 8 字节(64 位系统) -2¹⁵ 至 2¹⁵-1(32 位)或更大范围 跨平台需注意差异
- long long 8 字节 ,long long 是 有符号整数类型
2.基本数据类型 char
字符类型用于表示单个字符或小整数,本质是整数的特殊解释。
- char 1 字节 取决于编译器(有符号或无符号) ASCII(0-127)、扩展 ASCII(0-255)
- signed char 1 字节 -128 至 127 显式有符号字符
- unsigned char 1 字节 0 至 255
3.基本数据类型 浮点类型
- float 4 字节 6-7 位 ±3.4×10³⁸ 图形渲染、精度要求不高的计算
- double 8 字节 15-16 位 ±1.8×10³⁰⁸ 科学计算、默认浮点类型
- long double 8/10/16 字节 18-19 位(取决于编译器) 更大范围
4.其他
- 使用 sizeof 运算符
- 为什么整数区分有符号数和无符号数,浮点数不区分。
整数区分的起源:
1.计算机早期为科学计算设计,补码系统解决了负数表示问题。
2.随着应用场景扩展(如索引、位操作),无符号数被引入以提高效率和安全性。
浮点数不区分的原因:
1.IEEE 754 通过符号位直接支持负数,且所有浮点应用都需要负数,无需额外类型。
2.类型转换
把一种数据类型转换为另一个数据类型,分为隐式类型转换(自动转换)和显式类型转换(强制转换)。
1.隐式类型转换(自动转换)
编译器自动完成的转换,通常发生在赋值、运算、函数调用时。
1. 数值类型转换规则
- char/short int 直接提升
- int double 整数→浮点数(精确)
- double int 截断小数部分(可能丢失数据)
- int unsigned int 二进制不变,解释方式改变
2. 类类型转换
1.构造函数转换:单参数构造函数可将其他类型转为该类。
2.类型转换运算符:允许类对象转为其他类型。
operator 目标类型()
返回值类型会强制整个表达式采用目标类型的运算规则。
3.继承中转换。
派生类指针→基类指针(向上转型,自动转换)
派生类引用→基类引用(合法)
派生类对象→基类对象(对象切片)
转换原理:基于继承关系的类型兼容
C++ 的继承模型中,派生类对象包含基类的所有成员(基类子对象)
2.显式类型转换(强制转换)
1、原因,编译器无法自动完成,需要显式指定
2、值类型的向下转型(将基类对象直接转换为派生类对象)是被禁止的,会编译报错。
3、C++ 支持两种强制类型转换语法:
1.C 风格:(目标类型)表达式
2.函数风格:目标类型(表达式)
3.C++ 风格显式类型转换
1.static_cast
编译时转换,不检查类型安全性。
1、隐式类型转换都使用,在继承层级内的指针/引用转换(不进行运行时检查)。
2.dynamic_cast
1.RTTI
RTTI(Run-Time Type Information,运行时类型信息)是 C++ 提供的一种机制,允许程序在运行时获取对象的类型信息。
1、虚函数表结构
1.类型信息指针:指向描述类类型的std::type_info对象。
2.虚函数地址数组:按声明顺序排列的虚函数地址。
2、std::type_info结构
1.类型标识:通过唯一的名称和哈希值区分不同类型。
2.继承关系查询:支持运行时判断类型间的继承关系。
3.安全类型转换:为 dynamic_cast 提供必要的元数据。
C++ 通过两种机制实现 RTTI:
- dynamic_cast 运算符
运行时转换,要求基类有虚函数,用于安全向下转型(基类→派生类),失败时返回nullptr或抛异常。
功能:安全地将基类指针 / 引用转换为派生类指针 / 引用,在转换前进行运行时类型检查。
必要条件:基类必须包含至少一个虚函数(即多态类型)。
返回值:- 指针转换:若类型匹配,返回目标类型指针;否则返回 nullptr。
- 引用转换:若类型匹配,返回目标类型引用;否则抛出 std::bad_cast 异常。
- 对象转换:编译报错,无论是上转还是下转。dynamic_cast要求
使用场景:需要将基类指针 / 引用安全地转换为派生类指针 / 引用,且必须在运行时验证对象的实际类型时,使用 dynamic_cast。
多态的补充:当虚函数无法满足需求时(如访问派生类特有接口),提供类型安全保障。
设计警示:过度使用可能暗示继承结构设计不合理,优先考虑面向接口编程。
没有虚函数会编译报错。
- typeid 运算符
功能:返回表示对象类型的 std::type_info 对象,可用于比较类型或获取类型名称。
3.const_cast
用于修改类型的const或volatile属性的类型转换运算符。
1.语法形式
const_cast<类型>(表达式);
- 类型:目标类型,必须与源类型仅在const/volatile属性上不同。
- 表达式:要转换的值,可以是变量、指针或引用。
2.牢记安全规则
- 不要修改真正的常量
未定义行为(可能编译通过,但运行时可能崩溃或无效果)
3.推荐使用场景
- 重载const和非const成员函数。
- 与不支持const的旧代码或 C API 交互。
4.设计原则:const_cast 应作为最后的手段,而非常规工具。若频繁使用,可能暗示代码设计存在问题。
4.reinterpret_cast
即重新解释
1、reinterpret_cast通常为运算对象的位模式提供较低层次上的重新解释,绝不要用于普通类型转换。
4.显式类型转换 vs. 隐式类型转换
-
隐式类型转换的风险:隐藏意外行为
隐式类型转换由编译器自动执行,无需开发者显式声明,但可能导致语义模糊或运行时错误。 -
显式类型转换的优势:强制意图明确化
显式转换要求开发者主动声明转换行为,迫使思考转换的合理性,避免 “意外转换”。
5.C++ 风格显式类型转换 vs C 风格显式类型转换
C 风格显式转换的缺陷:万能钥匙式的危险
C 风格转换使用统一语法(type)expr,可实现四种不同类型的转换,但无法从语法上区分具体行为,导致:
- 转换意图模糊:无法快速判断转换是 “安全的向上转型” 还是 “危险的跨类型指针强转”。
- 绕过安全检查:C 风格转换可直接操作底层指针,跳过编译器对类型相关性的检查。
C++ 将转换分为四种独立运算符,每种对应明确场景,避免误用。