核心要点速览

  • 数据类型分类:基本类型、复合(派生)类型、自定义类型
  • 核心复合类型:指针、引用、数组、结构体、联合体、枚举
  • 变量关键特性:存储类别(auto/static/extern 等)、初始化要求、作用域与生命周期
  • 常量核心:const(只读)、constexpr(编译期常量)
  • 类型转换:隐式转换(编译器自动)、显式转换(四种强制转换)

一、数据类型

1.1 基本类型

基本类型是 C++ 内置的基础数据类型,具有固定内存大小(部分受平台影响)和明确取值范围。

类型 典型大小(32/64 位系统) 含义 / 范围 面试考点
bool 1 字节 布尔值:true(1)/false(0) sizeof(bool)恒为 1;不可用 0 / 非 0 代替(语法允许但不规范)
char 1 字节 ASCII 码:-128127 或 0255 区分signed char(带符号)和unsigned char(无符号);默认符号性由编译器决定
short 2 字节 短整数:-32768~32767 short int等价;用于节省内存
int 4 字节(通用) 整数:-2³¹~2³¹-1 平台无关性(主流编译器统一 4 字节);计数、返回值首选类型
long 4 字节(32 位)/8 字节(64 位) 长整数:随平台变化 避免依赖其大小,优先用固定宽度类型(如int64_t
long long 8 字节 超长整数:-2⁶³~2⁶³-1 C++11 标准,跨平台 8 字节,适合大整数
float 4 字节 单精度浮点:有效数字 6-7 位 精度低;避免直接比较(存在误差)
double 8 字节 双精度浮点:有效数字 15-17 位 默认浮点类型(如3.14是 double);科学计算首选
void 无大小 无类型(表示 “空”) 用于无返回值函数、void*指针(可指向任意类型)

关键补充

  • 跨平台一致性保证:使用 C++11 固定宽度类型(定义于<cstdint>),如int32_t(32 位带符号)、uint64_t(64 位无符号)。
  • sizeof计算规则:sizeof(char)恒为 1;sizeof(int)通常 4 字节;sizeof(void)编译报错;sizeof(bool)始终为 1。

1.2 复合类型(派生类型)

基于基本类型或自定义类型扩展,核心用于组合、关联或间接访问数据。

指针

  • 存储目标变量的内存地址,大小仅与系统位数相关(32 位 4 字节,64 位 8 字节,与指向类型无关)。
  • 核心特性:
    1. 未初始化指针为野指针(指向随机地址,操作易崩溃),需避免。
    2. nullptr(C++11):空指针常量,替代NULLNULL本质是 0,易引发歧义)。
    3. 指针运算:仅对数组指针有效(p++步长为指向类型的大小)。
    4. 数组名本质:指向数组首元素的常量指针(不可修改指向)。

引用

  • 变量的 “别名”,语法:类型& 引用名 = 变量名,必须初始化且绑定后不可更改。
对比项 指针 引用
定义 可空(nullptr 不可空(必须绑定变量)
指向修改 可重新指向其他变量 绑定后不可更改
初始化 可延迟初始化(风险高) 必须定义时初始化
内存占用 占内存(存储地址) 不占额外内存(编译器优化)
核心用途 动态内存管理、多级间接访问 函数参数 / 返回值(避免拷贝)、简化代码

结构体(Struct)

  • 组合多个不同类型数据(成员)为一个整体,成员按顺序占用独立内存。
  • 核心特性:结构体大小 = 成员大小之和 + 内存对齐填充字节。
  • 用途:存储关联数据(如个人信息:姓名、年龄、身高)。

联合体(Union)

  • 所有成员共享同一块内存,同一时间仅能有效使用一个成员。
对比项 结构体(Struct) 联合体(Union)
内存分配 成员独立占用内存,总大小 = 成员和 + 填充 成员共享内存,总大小 = 最大成员大小(+ 对齐填充)
成员关系 成员并存(可同时访问) 成员互斥(同一时间仅能用一个)
核心用途 组合关联数据 节省内存、实现类型转换

枚举(Enum)

  • 自定义整数类型,用于组合含义相关的命名常量。
  • 分类:
    1. 传统枚举:enum E {A, B=5, C};,成员作用域全局(易冲突),可隐式转 int。
    2. 强类型枚举(C++11 推荐):enum class E {A, B};,作用域受限(需E::A访问),不可隐式转 int(更安全)。
  • 赋值规则:未手动赋值时,首个常量为 0,后续依次 + 1;中间赋值后,后续常量基于该值递增。

1.3 自定义类型

  • 由用户通过class(类)、struct(结构体)、enum(枚举)等关键字定义的类型。
  • 核心作用:封装数据与行为,提升代码可读性和复用性。

二、变量

2.1 变量的定义与初始化

  • 定义:编译器为变量分配内存空间。

  • 初始化:定义时赋予初始值(避免 “垃圾值”,提升代码安全性)。

  • 常见初始化方式:

    1
    2
    3
    4
    int a = 10;    // 拷贝初始化
    int b(20); // 直接初始化(适合构造函数场景)
    int c{30}; // 列表初始化(C++11,禁止窄化转换,如int{3.14}编译报错)
    int d = {40}; // 拷贝列表初始化

2.2 存储类别(关键字修饰)

存储类别决定变量的生命周期、作用域和存储位置。

关键字 核心特性与用途
auto(C++11) 编译器自动推导类型;不能用于函数参数(模板除外)、数组类型;推导引用需显式加&
static 局部静态变量:生命周期为程序全程,首次调用初始化;全局静态变量:仅当前.cpp 可见(避免命名冲突);类静态成员:属于类,所有对象共享
extern 声明变量 / 函数在其他文件定义(跨文件共享);仅声明不分配内存,带初始化则变为定义
register 提示编译器存于寄存器(C++17 后弃用,现代编译器优化足够)
mutable 仅用于类非静态成员;允许 const 成员函数修改该变量(突破 const 限制)
volatile 禁止编译器优化;变量值可能被外部因素修改(如硬件、多线程),每次访问直接读内存

2.3 常见问题解答

  • 局部变量屏蔽全局变量时如何访问全局变量?用::(全局作用域解析符),如::global_var
  • 全局变量与局部static变量的初始化顺序?全局变量在main前初始化,局部static变量首次进入函数时初始化(C++11 后线程安全);销毁顺序与初始化相反。
  • 未初始化的局部变量和全局变量区别?局部非static变量是 “垃圾值”;全局变量和static变量会零初始化(数值为 0,指针为nullptr)。

2.4 常量

常量是初始化后不可修改的变量,核心分为constconstexpr

const(只读常量)

  • 修饰变量:初始化后不可修改,作用域与变量一致。

  • 修饰指针(三大场景):

    1
    2
    3
    const int* p;    // 常量指针:指向的内容不可改(*p不可改),p可改指向
    int* const p; // 指针常量:p的指向不可改,*p可改
    const int* const p; // 指向常量的指针常量:内容和指向均不可改

constexpr(编译期常量,C++11)

  • 要求表达式在编译期可计算,比const更严格(const可运行期初始化)。
  • 用途:定义数组大小、模板参数等依赖编译期常量的场景。

2.5 类型转换

隐式转换(自动转换)

  • 遵循 “安全优先” 原则,优先 “小范围→大范围”(类型提升),避免溢出。
  • 转换顺序:boolcharshortintlonglong longfloatdoublelong double
  • 注意:explicit关键字可禁止类的隐式类型转换。

显式转换(四种强制转换)

转换方式 核心用途 风险程度
static_cast 基本类型转换(int→double)、父类 / 子类指针转换(无动态检查) 中等(父类→子类可能越界)
dynamic_cast 多态类型转换(仅用于含虚函数的类),运行期检查有效性 低(失败返回nullptr/ 抛异常)
const_cast 移除指针 / 引用的const属性 高(修改原const变量会导致未定义行为)
reinterpret_cast 底层二进制重解释(如int*→char* 极高(依赖平台,无移植性)

问答

  • 何时用dynamic_cast?多态场景下,需将父类指针安全转为子类指针(需父类有虚函数,运行期校验合法性)。
  • 为何避免reinterpret_cast?直接操作二进制,忽略类型安全,结果依赖平台,移植性极差。