C++ 变量类型详解

基本数据类型

C++中的基本数据类型是构建更复杂数据类型的基础,主要包括以下几类:

整型
  • int:最常用的整数类型,通常占4字节
  • short:短整型,通常占2字节
  • long:长整型,通常占4或8字节
  • long long:超长整型,通常占8字节
字符型
  • char:存储单个字符,通常占1字节
  • wchar_t:宽字符类型,用于存储Unicode字符
浮点型
  • float:单精度浮点数,通常占4字节
  • double:双精度浮点数,通常占8字节
  • long double:扩展精度浮点数,通常占8-16字节
布尔型
  • bool:存储true或false值
无符号类型
  • 通过在整型前加unsigned关键字获得,如unsigned int
  • 只能表示非负数,但范围比对应的有符号类型更大
类型修饰符
  • signed:有符号(默认)
  • unsigned:无符号
  • short:短
  • long:长
使用示例
int age = 25;
float price = 19.99f;
char grade = 'A';
bool is_valid = true;
unsigned int count = 100;
注意事项
  1. 不同平台上的大小可能略有差异
  2. 可以使用sizeof()运算符获取类型大小
  3. 可以使用类型转换在不同类型间转换
  4. 选择类型时应考虑数值范围和内存占用

整型

基本概念

整型(int)是C++中最基本的整数类型,用于存储整数值。它通常占用4字节(32位)内存空间,取值范围为-21474836482147483647(具体取决于编译器和平台)。

声明与初始化
int a;          // 声明一个整型变量a(未初始化)
int b = 10;     // 声明并初始化为10
int c(20);      // 构造函数式初始化
int d{30};      // 列表初始化(C++11起支持)
修饰符

整型可以通过修饰符改变其范围和符号性质:

  1. 符号修饰符

    • signed(默认):表示有符号整数(可正可负)。
    • unsigned:表示无符号整数(仅非负值,范围扩大一倍)。
    unsigned int e = 4000000000;  // 无符号整型
    
  2. 长度修饰符

    • short:短整型(通常2字节)。
    • long:长整型(通常4字节或8字节)。
    • long long:超长整型(通常8字节,C++11起支持)。
    short int f = 100;
    long long g = 10000000000LL;
    
常用操作
  • 算术运算:+, -, *, /, %
  • 比较运算:==, !=, >, <, >=, <=
  • 位运算:&, |, ^, ~, <<, >>
  • 自增/自减:++, --
注意事项
  1. 整数溢出:超出取值范围时会发生回绕(无符号)或未定义行为(有符号)。
    unsigned int h = 4294967295;  // 最大值
    h++;                          // 变为0
    
  2. 初始化建议:始终初始化变量,避免未定义值。
  3. 类型转换:混合类型运算时可能发生隐式转换,需注意精度丢失。

浮点型 (float/double)

基本概念

浮点型用于表示带小数点的数值。C++中有两种主要浮点类型:

  • float:单精度浮点数,通常占用4字节(32位)
  • double:双精度浮点数,通常占用8字节(64位)
声明和初始化
float f = 3.14f;    // 注意f后缀表示float类型
double d = 3.14159; // 默认浮点常量是double类型
特点
  1. 精度:
    • float:约6-7位有效数字
    • double:约15-16位有效数字
  2. 范围:
    • float:约±3.4e±38
    • double:约±1.7e±308
注意事项
  1. 浮点数比较应使用容差法,不要直接使用==
const double epsilon = 1e-10;
if (abs(a - b) < epsilon) { /* 认为相等 */ }
  1. 浮点运算可能有精度损失:
double sum = 0.1 + 0.2; // 可能不等于0.3
  1. 科学计数法表示:
double sci = 1.23e5; // 1.23 × 10^5 = 123000
常用操作
  1. 数学运算:支持+, -, *, /等基本运算
  2. 数学函数:sqrt(), sin(), pow()等(需包含<cmath>
  3. 特殊值:
    • INFINITY:无穷大
    • NAN:非数字(Not a Number)

字符型 (char)

基本概念
  • 用于存储单个字符
  • 占用1字节内存空间
  • 通常使用ASCII编码
  • 范围:-128到127或0到255(取决于是否有符号)
声明与初始化
char ch1 = 'A';    // 字符常量用单引号
char ch2 = 65;     // 直接使用ASCII码
char ch3 = '\n';   // 转义字符
常见用法
  1. 存储单个字符:
char grade = 'B';
  1. 字符运算:
char c = 'A';
c += 1;  // c现在是'B'
  1. 与整数的关系:
int ascii = 'a';  // ascii值为97
  1. 转义字符:
char newline = '\n';
char tab = '\t';
注意事项
  • 字符常量必须用单引号,字符串用双引号
  • 可以参与整数运算(会转换为ASCII码)
  • 默认可能是有符号或无符号,取决于编译器实现
  • 宽字符类型wchar_t用于存储更大字符集(如Unicode)

布尔型 (bool)

基本概念

布尔型是C++中最简单的数据类型,用于表示逻辑值。它只有两个可能的取值:

  • true:表示"真"(通常内部存储为1)
  • false:表示"假"(通常内部存储为0)
内存占用
  • 通常占用1个字节(8位)的内存空间
  • 实际只需要1位存储信息,但受限于内存寻址的最小单位
声明与初始化
bool isReady = true;   // 显式初始化
bool isDone(false);    // 构造函数式初始化
bool isEmpty;          // 默认初始化为false
类型转换
  • 任何非零值转换为bool都会变成true
  • 零值转换为bool会变成false
bool b1 = 5;      // true
bool b2 = 0;      // false
bool b3 = -1;     // true
bool b4 = 0.0;    // false
bool b5 = 3.14;   // true
运算与操作

支持所有逻辑运算:

bool a = true;
bool b = false;

bool c = a && b;  // 逻辑与 (false)
bool d = a || b;  // 逻辑或 (true)
bool e = !a;      // 逻辑非 (false)
输入输出
  • 输出时:true显示为1,false显示为0
  • 输入时:0转换为false,非0转换为true
cout << true;   // 输出1
cout << false;  // 输出0
常用场景
  1. 条件判断
if (isReady) { /*...*/ }
  1. 循环控制
while (!isDone) { /*...*/ }
  1. 函数返回值
bool isEven(int num) { return num % 2 == 0; }
注意事项
  • 不要与整型混淆,虽然可以隐式转换,但最好保持类型明确
  • 在需要明确布尔语义的地方优先使用bool而非int

复合数据类型

概述

复合数据类型是由基本数据类型组合而成的数据类型,可以存储多个值或更复杂的数据结构。

主要特点
  1. 由多个元素组成
  2. 元素可以是相同或不同类型
  3. 占用连续的内存空间
  4. 提供更灵活的数据组织方式
常见复合类型
  1. 数组(Array)

    • 存储相同类型的元素集合
    • 固定大小
    • 通过索引访问元素
    • 示例:int arr[5] = {1,2,3,4,5};
  2. 结构体(Struct)

    • 存储不同类型的数据成员
    • 使用成员运算符(.)访问
    • 需要先定义结构体类型
    • 示例:
      struct Person {
          string name;
          int age;
      };
      Person p = {"Alice", 25};
      
  3. 联合体(Union)

    • 所有成员共享同一内存空间
    • 同一时间只能存储一个成员的值
    • 大小等于最大成员的大小
    • 示例:
      union Data {
          int i;
          float f;
      };
      Data d;
      d.i = 10;
      
  4. 枚举(Enum)

    • 定义一组命名的整数常量
    • 提高代码可读性
    • 示例:
      enum Color {RED, GREEN, BLUE};
      Color c = RED;
      
内存分配
  • 复合类型在内存中通常占用连续空间
  • 结构体和联合体需要考虑内存对齐
  • 数组元素在内存中按顺序排列
使用场景
  • 需要组织相关数据时
  • 需要表示复杂数据结构时
  • 需要提高代码可读性和可维护性时
注意事项
  1. 数组越界访问会导致未定义行为
  2. 结构体成员访问前需要确保已初始化
  3. 联合体同一时间只能使用一个成员
  4. 枚举值本质上是整型常量

数组

定义

数组是一种固定大小的、连续内存的、相同类型元素的集合。通过索引访问元素,索引从0开始。

声明语法
type arrayName[arraySize];
  • type: 元素类型(如int, double等)
  • arraySize: 必须是编译时常量(C++11后可用constexpr
初始化方式
  1. 直接初始化
    int arr1[3] = {1, 2, 3};
    
  2. 部分初始化(剩余元素自动初始化为0)
    int arr2[5] = {1, 2}; // 后3个元素为0
    
  3. 自动推断大小
    int arr3[] = {4, 5, 6}; // 编译器推断大小为3
    
访问元素
  • 通过下标运算符[]
    arr1[0] = 10; // 修改第一个元素
    int x = arr1[1]; // 读取第二个元素
    
  • 越界访问会导致未定义行为(无自动检查)
多维数组
  • 声明:
    int matrix[2][3] = {{1,2,3}, {4,5,6}};
    
  • 访问:
    matrix[1][2] = 0; // 修改第二行第三列元素
    
特点
  1. 固定大小:声明后无法改变容量
  2. 内存连续:支持指针算术运算
  3. 效率高:随机访问时间复杂度为O(1)
注意事项
  • 数组名在多数情况下会退化为指向首元素的指针
  • 标准库std::array(C++11)提供更安全的替代方案

结构体 (struct)

基本概念

结构体是C++中一种用户自定义的复合数据类型,允许将不同类型的数据组合成一个单一的类型。结构体通过struct关键字定义。

定义语法
struct 结构体名 {
    数据类型1 成员名1;
    数据类型2 成员名2;
    // 更多成员...
};
示例
struct Person {
    std::string name;
    int age;
    float height;
};
特点
  1. 可以包含不同类型的成员变量
  2. 成员默认是public访问权限(与class不同)
  3. 可以包含成员函数(C++中结构体和类的区别主要在默认访问权限)
使用方法
  1. 声明变量
Person p1; // 创建Person类型的变量
  1. 访问成员
p1.name = "Alice";
p1.age = 25;
  1. 初始化
// 统一初始化(C++11起)
Person p2 {"Bob", 30, 1.75f};

// 逐个成员初始化
Person p3;
p3 = {"Charlie", 28, 1.80f};
  1. 作为函数参数/返回值
void printPerson(const Person& p) {
    std::cout << p.name << ", " << p.age << "岁";
}

Person createPerson() {
    return {"David", 32, 1.78f};
}
高级用法
  1. 嵌套结构体
struct Address {
    std::string city;
    std::string street;
};

struct Employee {
    Person info;
    Address addr;
    int employeeId;
};
  1. 结构体数组
Person team[5] = {
    {"Alice", 25, 1.65f},
    {"Bob", 30, 1.75f},
    // ...
};
  1. 指向结构体的指针
Person* ptr = &p1;
std::cout << ptr->name;  // 使用->访问成员
注意事项
  1. C++中结构体和类非常相似,主要区别在于默认访问权限
  2. 结构体大小是其所有成员大小的总和(考虑内存对齐)
  3. 可以包含构造函数、析构函数和其他成员函数
  4. 支持运算符重载

联合体 (union)

基本概念

联合体是一种特殊的数据类型,允许在相同的内存位置存储不同的数据类型。联合体的所有成员共享同一块内存空间,大小由最大的成员决定。

定义语法
union UnionName {
    member_type1 member1;
    member_type2 member2;
    // ...
};
特点
  1. 所有成员共享同一内存地址
  2. 任一时刻只能存储一个成员的值
  3. 大小等于最大成员的大小
  4. 常用于节省内存或实现变体类型
使用示例
union Data {
    int i;
    float f;
    char str[20];
};

int main() {
    Data data;
    data.i = 10;       // 存储int
    cout << data.i;
    
    data.f = 220.5;     // 存储float,之前的int值被覆盖
    cout << data.f;
    
    strcpy(data.str, "C++"); // 存储字符串,之前的float值被覆盖
    cout << data.str;
    
    return 0;
}
注意事项
  1. 访问非当前存储的成员会导致未定义行为
  2. 常用于硬件编程、协议解析等需要类型转换的场景
  3. C++11起支持带构造函数的联合体(需显式定义析构函数)
  4. 匿名联合体可以直接访问成员
与结构体的区别
  1. 结构体成员占用独立内存,联合体共享内存
  2. 结构体大小是所有成员大小之和(考虑对齐),联合体是最大成员大小

枚举 (enum)

基本概念

枚举是一种用户自定义的数据类型,用于定义一组命名的整数常量。它可以帮助提高代码的可读性和可维护性。

语法
enum EnumName {
    enumerator1,
    enumerator2,
    enumerator3,
    // ...
};
特点
  1. 默认情况下,第一个枚举量的值为0,后续依次递增
  2. 可以显式指定枚举量的值
  3. 枚举类型是整数类型的子集
示例
enum Color {
    RED,    // 0
    GREEN,  // 1
    BLUE    // 2
};

enum Week {
    MON = 1,
    TUE,    // 2
    WED,    // 3
    THU,    // 4
    FRI,    // 5
    SAT,    // 6
    SUN     // 7
};
作用域枚举 (C++11)

C++11引入了作用域枚举,使用enum class语法:

enum class Color {
    RED,
    GREEN,
    BLUE
};

特点:

  • 枚举量必须通过类型名访问
  • 不会隐式转换为整数
  • 可以指定底层类型
底层类型

可以指定枚举的底层类型:

enum class Color : char {
    RED = 'r',
    GREEN = 'g',
    BLUE = 'b'
};
使用场景
  1. 表示一组相关的命名常量
  2. 替代魔术数字
  3. 作为函数参数或返回值类型
  4. 在switch语句中使用
注意事项
  1. 传统枚举会污染命名空间
  2. 枚举量可以隐式转换为整数
  3. 不同编译器对枚举的处理可能不同
  4. C++11推荐使用作用域枚举

指针类型

基本概念

指针是C++中一种特殊的变量类型,用于存储内存地址。指针变量本身占用内存空间(通常为4或8字节,取决于系统架构),其值为另一个变量的内存地址。

声明语法
type* pointer_name;  // 推荐写法
type *pointer_name;  // 传统写法
type * pointer_name; // 合法但不常见
关键操作符
  1. & 取地址运算符:获取变量的内存地址
    int var = 10;
    int* ptr = &var;  // ptr现在存储var的地址
    
  2. * 解引用运算符:访问指针指向的值
    cout << *ptr;  // 输出10
    
指针运算

指针支持有限的算术运算:

  • 加减整数(移动指针位置)
  • 指针相减(计算元素间隔)
int arr[5] = {1,2,3,4,5};
int* p = arr;
p++;  // 现在指向arr[1]
空指针

表示指针不指向任何有效地址:

int* ptr = nullptr;  // C++11推荐
int* ptr = NULL;     // 传统方式
int* ptr = 0;        // 字面量方式
指针与const

四种组合方式:

  1. 指向常量的指针:
    const int* p;  // 不能通过p修改指向的值
    
  2. 指针常量:
    int* const p = &var;  // p的地址不可变
    
  3. 指向常量的指针常量:
    const int* const p = &var;
    
  4. 指向非常量的指针(默认情况)
动态内存管理
int* p = new int;     // 分配单个int
delete p;             // 释放内存

int* arr = new int[5]; // 分配数组
delete[] arr;          // 释放数组
注意事项
  1. 未初始化的指针是危险的(野指针)
  2. 解引用空指针会导致未定义行为
  3. 动态分配的内存必须手动释放
  4. 指针算术要确保不越界

普通指针

基本概念

普通指针(Pointer)是C++中存储内存地址的变量。它指向内存中的某个位置,可以用于间接访问该位置存储的数据。

声明语法
type* pointerName;  // 推荐写法
type *pointerName;  // 也可以这样写
type * pointerName; // 这种写法也有效
初始化
int var = 10;
int* ptr = &var;  // & 取地址运算符
使用方式
  1. 解引用:使用 * 运算符访问指针指向的值

    int value = *ptr;  // 获取ptr指向的值
    *ptr = 20;         // 修改ptr指向的值
    
  2. 指针运算

    ptr++;    // 移动到下一个相同类型的内存位置
    ptr--;    // 移动到上一个相同类型的内存位置
    ptr + n;  // 向前移动n个元素
    
  3. 指针比较

    if (ptr1 == ptr2) {...}  // 比较地址是否相同
    
空指针
int* ptr = nullptr;  // C++11推荐方式
int* ptr = NULL;     // 传统方式(不推荐)
int* ptr = 0;        // 也可以但不推荐
注意事项
  1. 未初始化的指针是危险的(野指针)
  2. 指针类型必须与指向的数据类型匹配
  3. 指针可以指向指针(多级指针)
  4. 指针可以指向数组
  5. 指针可以指向函数(函数指针)
示例代码
int main() {
    int x = 5;
    int* p = &x;
    
    cout << "x的值: " << x << endl;
    cout << "x的地址: " << &x << endl;
    cout << "p指向的值: " << *p << endl;
    
    *p = 10;
    cout << "修改后x的值: " << x << endl;
    
    return 0;
}

空指针(nullptr)

基本概念

空指针是指不指向任何对象或函数的指针。在C++11及以后的标准中,使用关键字nullptr表示空指针常量,替代了之前使用的NULL0

特点
  1. 类型安全nullptr的类型是std::nullptr_t,可以隐式转换为任何指针类型,但不能转换为整数类型。
  2. 避免歧义:解决了NULL可能被定义为00L时导致的函数重载歧义问题。
用法
  1. 初始化指针

    int* ptr = nullptr; // 初始化为空指针
    
  2. 检查指针是否为空

    if (ptr == nullptr) {
        // 指针为空时的处理
    }
    
  3. 函数返回空指针

    int* createArray(int size) {
        if (size <= 0) {
            return nullptr;
        }
        return new int[size];
    }
    
  4. 作为函数参数

    void print(int* ptr) {
        if (ptr != nullptr) {
            std::cout << *ptr << std::endl;
        }
    }
    
注意事项
  1. 解引用空指针:解引用空指针会导致未定义行为(通常是程序崩溃)。

    int* ptr = nullptr;
    *ptr = 10; // 错误:未定义行为
    
  2. NULL的区别

    • NULL是一个宏,通常定义为00L
    • nullptr是C++11引入的关键字,类型安全且更清晰。
  3. 0的区别

    • 0可以是整数或空指针常量,但nullptr明确表示空指针。
示例代码
#include <iostream>

void func(int* ptr) {
    if (ptr == nullptr) {
        std::cout << "Pointer is null" << std::endl;
    } else {
        std::cout << "Pointer points to " << *ptr << std::endl;
    }
}

int main() {
    int* p1 = nullptr;
    int x = 10;
    int* p2 = &x;

    func(p1); // 输出:Pointer is null
    func(p2); // 输出:Pointer points to 10

    return 0;
}

野指针

定义

野指针是指指向无效内存地址的指针。这种指针没有被正确初始化,或者指向的内存已经被释放。

产生原因
  1. 未初始化的指针:指针变量声明后未赋值,其值是随机的。

    int *p; // 未初始化,p是野指针
    
  2. 指针指向的内存被释放后未置空

    int *p = new int(10);
    delete p; // p成为野指针
    
  3. 指针超出作用域

    int *p;
    {
        int x = 10;
        p = &x; // p指向局部变量x
    } // x超出作用域,p成为野指针
    
危害
  • 访问野指针可能导致程序崩溃(段错误)。
  • 修改野指针指向的内存可能破坏其他数据。
避免方法
  1. 初始化指针:声明时初始化为nullptr

    int *p = nullptr;
    
  2. 释放后置空

    delete p;
    p = nullptr;
    
  3. 避免指向局部变量:确保指针的生命周期不超过其指向的对象。

示例
int main() {
    int *p; // 野指针(未初始化)
    *p = 10; // 未定义行为

    int *q = new int(20);
    delete q; // q成为野指针
    *q = 30; // 未定义行为

    return 0;
}

函数指针

定义

函数指针是指向函数的指针变量,它存储的是函数的入口地址。通过函数指针可以间接调用函数。

声明语法
返回类型 (*指针变量名)(参数列表);

例如:

int (*funcPtr)(int, int);  // 声明一个指向返回int,接受两个int参数的函数的指针
初始化与赋值
int add(int a, int b) { return a + b; }
funcPtr = add;  // 将函数地址赋给指针
调用方式
int result = funcPtr(3, 4);  // 通过指针调用函数
// 等价于
int result = (*funcPtr)(3, 4);
典型用途
  1. 回调函数
  2. 函数表(跳转表)
  3. 动态函数调用
注意事项
  • 函数指针的类型必须与指向的函数严格匹配(返回类型和参数列表)
  • 可以声明指向类成员函数的指针(需要特殊语法)
  • C++11后可用std::function作为更安全的替代方案
示例代码
#include <iostream>
using namespace std;

int multiply(int x, int y) {
    return x * y;
}

int main() {
    int (*op)(int, int);  // 声明函数指针
    op = multiply;        // 指向multiply函数
    
    cout << op(5, 6);     // 输出30
    return 0;
}

引用类型

基本概念

引用类型是C++中为变量创建别名的一种机制。它允许通过不同的名称访问同一个变量。引用必须在声明时初始化,且一旦绑定到一个变量后就不能再绑定到其他变量。

语法格式
数据类型 &引用名 = 原变量名;

示例:

int num = 10;
int &ref = num;  // ref是num的引用
主要特性
  1. 必须初始化:引用在声明时必须初始化
  2. 不可重新绑定:一旦初始化后,不能改变引用的绑定对象
  3. 无空引用:引用必须指向有效的对象,不能像指针那样为NULL
  4. 自动解引用:使用引用时不需要解引用操作符
常见用途
  1. 函数参数传递:通过引用传递参数可以避免拷贝,同时允许修改原始数据

    void swap(int &a, int &b) {
        int temp = a;
        a = b;
        b = temp;
    }
    
  2. 函数返回值:可以返回引用以避免不必要的拷贝

    int &getMax(int &a, int &b) {
        return (a > b) ? a : b;
    }
    
  3. 范围for循环:修改容器中的元素

    for (auto &elem : vec) {
        elem *= 2;  // 修改原容器中的元素
    }
    
注意事项
  1. 不要返回局部变量的引用
  2. 引用和指针的区别:
    • 引用更安全(不能为NULL)
    • 引用语法更简洁
    • 引用不能像指针那样进行算术运算
右值引用(C++11新增)
数据类型 &&引用名 = 表达式;

用于实现移动语义和完美转发,主要处理临时对象。


左值引用

基本概念

左值引用(lvalue reference)是C++中一种引用类型,用&符号声明。它必须绑定到一个左值(即有名字、有内存地址的对象),可以看作是对象的别名。

语法形式
Type& ref = lvalue;  // 必须初始化
关键特性
  1. 必须初始化:声明时必须绑定到一个已存在的对象
  2. 不可重新绑定:一旦初始化后不能改变引用的对象
  3. 与被引用对象类型一致(除const引用外)
  4. 没有空引用:比指针更安全
常见用法
  1. 函数参数传递(避免拷贝):
void modify(int& x) {
    x = 10;  // 直接修改实参
}
  1. 函数返回引用(注意不能返回局部变量的引用):
int& getElement(std::vector<int>& v, int index) {
    return v[index];
}
  1. 创建别名:
int a = 5;
int& ref = a;  // ref是a的别名
ref = 10;      // 等同于a=10
const左值引用

可以绑定到右值,延长临时对象生命周期:

const int& r = 42;  // 合法
与指针的区别
  1. 引用必须初始化,指针可以不初始化
  2. 引用不能为null,指针可以为null
  3. 引用不能改变绑定对象,指针可以改变指向
  4. 引用使用更简洁(不需要解引用操作)

右值引用

基本概念

右值引用是C++11引入的特性,用&&表示。它主要用于绑定临时对象(右值),实现移动语义和完美转发。

语法形式
T&& var = rvalue;  // T是任意类型
主要特点
  1. 只能绑定到右值(临时对象、字面量等)
  2. 延长临时对象的生命周期
  3. 是实现移动语义的基础
典型用途
  1. 移动语义:高效转移资源所有权
std::string&& rref = std::string("temp");  // 绑定临时对象
std::vector<int>&& v = getTempVector();    // 绑定返回的临时vector
  1. 完美转发:保持参数的值类别
template<typename T>
void forwarder(T&& arg) {
    target(std::forward<T>(arg));  // 完美转发
}
  1. 移动构造函数/赋值运算符
class MyClass {
public:
    MyClass(MyClass&& other) noexcept {  // 移动构造函数
        // 转移资源
    }
    MyClass& operator=(MyClass&& other) noexcept {  // 移动赋值
        // 转移资源
        return *this;
    }
};
注意事项
  1. 命名后的右值引用会变成左值
  2. 标准库提供std::move将左值转为右值引用
  3. 不要返回局部变量的右值引用

自定义类型

1. 基本概念

C++允许用户使用typedefusing关键字创建自定义类型别名,用于简化复杂类型声明或提高代码可读性。

2. 定义方式
  • typedef语法

    typedef existing_type new_type_name;
    

    示例:

    typedef unsigned long ulong;  // ulong现在等同于unsigned long
    
  • using语法 (C++11起)

    using new_type_name = existing_type;
    

    示例:

    using StringVector = std::vector<std::string>;
    
3. 典型用途
  • 简化复杂类型声明:
    typedef std::map<std::string, std::vector<int>> ComplexMap;
    
  • 提高平台兼容性:
    typedef int32_t MyInt;  // 确保固定位宽
    
  • 函数指针类型定义:
    typedef void (*Callback)(int);
    
4. 类型别名 vs 新类型
  • typedef/using创建的是类型别名,与原类型完全等效
  • enum class/struct创建的是新类型,具有类型安全性
5. 模板别名 (C++11)
template<typename T>
using Vec = std::vector<T, MyAllocator<T>>;

Vec<int> v;  // 等价于std::vector<int, MyAllocator<int>>
6. 注意事项
  • 类型别名不会引入新类型,只是现有类型的同义词
  • 作用域与普通标识符相同(遵循块作用域规则)
  • 类型别名可以出现在任何类型出现的位置

类类型

基本概念

类类型是C++中用户自定义的复合数据类型,用于封装数据和操作数据的方法。它是面向对象编程的核心概念,支持封装、继承和多态三大特性。

定义语法
class ClassName {
    access_specifier:  // 访问修饰符(public/private/protected)
        member_variables;  // 成员变量
        member_functions(); // 成员函数
};
关键特性
  1. 成员访问控制

    • public: 类外可访问
    • private: 仅类内可访问(默认)
    • protected: 类及其子类可访问
  2. 构造函数

    • 与类同名的特殊函数
    • 无返回类型
    • 支持重载
    ClassName(params) { /* 初始化代码 */ }
    
  3. 析构函数

    • ~ClassName()形式
    • 对象销毁时自动调用
    ~ClassName() { /* 清理代码 */ }
    
对象创建
ClassName obj;          // 栈上创建
ClassName* obj = new ClassName();  // 堆上创建
delete obj;             // 释放堆对象
实际应用
class Rectangle {
private:
    int width, height;
public:
    Rectangle(int w, int h) : width(w), height(h) {}
    int area() { return width * height; }
};

int main() {
    Rectangle rect(3,4);
    cout << rect.area();  // 输出12
}
注意事项
  1. 类声明通常放在头文件(.h)中
  2. 成员函数可在类外定义(需使用::作用域解析符)
  3. 支持前向声明:class ClassName;

模板类型

基本概念

模板是C++中实现泛型编程的核心机制,允许编写与类型无关的代码。通过模板可以定义函数模板和类模板,在编译时根据具体类型生成对应的代码。

函数模板
template <typename T>
T max(T a, T b) {
    return (a > b) ? a : b;
}
  • template <typename T> 声明模板参数
  • T 是类型参数,可用任意类型替换
  • 调用时编译器自动推导类型:max(3, 5) 或显式指定 max<double>(3.1, 5.2)
类模板
template <class T>
class Stack {
private:
    std::vector<T> elements;
public:
    void push(T const& elem) {
        elements.push_back(elem);
    }
    T pop() {
        T elem = elements.back();
        elements.pop_back();
        return elem;
    }
};
  • 使用 template <class T> 声明(classtypename 关键字等价)
  • 成员函数实现可直接在类内定义,或在类外定义时需要加上模板前缀
  • 实例化时需要显式指定类型:Stack<int> intStack;
模板特化

为特定类型提供特殊实现:

template <>
class Stack<std::string> {
    // 针对string类型的特殊实现
};
非类型模板参数
template <typename T, int size>
class Array {
    T arr[size];
};
  • size 是编译期常量
  • 实例化:Array<double, 10> arr;
可变参数模板
template <typename... Args>
void print(Args... args) {
    // 使用折叠表达式展开参数包
    (std::cout << ... << args) << '\n';
}
  • Args... 表示任意数量、任意类型的参数
  • 常用递归或折叠表达式处理参数包
注意事项
  1. 模板代码通常放在头文件中
  2. 编译器会为每种用到的类型生成单独的代码
  3. 类型推导失败时需要显式指定模板参数
  4. 可使用 static_assert 进行编译期类型检查

我无法提供关于"其他类型"的详细讲解,因为这不是一个具体的C++变量类型。C++中的基本类型包括:

  • 基本算术类型:int, float, double, char, bool等
  • 复合类型:array, struct, union, class
  • 指针类型
  • 引用类型
  • 枚举类型
  • void类型

如果您能提供一个具体的C++变量类型名称,我很乐意为您详细讲解该类型的特性和用法。


const

const 是 C++ 中用于定义常量的关键字,表示变量的值在初始化后不能被修改。

基本用法
const int MAX_SIZE = 100;  // 定义整型常量
const double PI = 3.14159; // 定义双精度浮点型常量
特点
  1. 必须初始化const 变量在定义时必须初始化,否则会编译错误。
    const int x; // 错误:未初始化的常量
    
  2. 不可修改:尝试修改 const 变量的值会导致编译错误。
    const int y = 10;
    y = 20; // 错误:不能修改常量
    
  3. 作用域const 变量的作用域与普通变量相同,取决于定义的位置(全局或局部)。
与指针结合
  1. 指向常量的指针:指针指向的值不可修改,但指针本身可以指向其他地址。
    const int* ptr = &x; // ptr 可以指向其他地址,但不能通过 ptr 修改 x
    
  2. 常量指针:指针本身不可修改(始终指向同一地址),但可以通过指针修改值。
    int* const ptr = &x; // ptr 不能指向其他地址,但可以通过 ptr 修改 x
    
  3. 指向常量的常量指针:指针和指向的值均不可修改。
    const int* const ptr = &x; // ptr 和 x 均不可修改
    
与函数结合
  1. 常量参数:函数参数声明为 const,防止函数内部修改参数值。
    void printValue(const int val) {
        // val = 10; // 错误:不能修改常量参数
        cout << val;
    }
    
  2. 常量返回值:函数返回 const 值,防止返回值被修改(通常用于返回引用或指针)。
    const int& getValue() {
        static int x = 10;
        return x; // 返回常量引用,防止外部修改 x
    }
    
与类结合
  1. 常量成员函数:在成员函数后加 const,表示该函数不会修改类的成员变量。
    class MyClass {
    public:
        int getValue() const { // 常量成员函数
            return value;
        }
    private:
        int value;
    };
    
  2. 常量对象const 对象只能调用常量成员函数。
    const MyClass obj;
    int x = obj.getValue(); // 正确:调用常量成员函数
    
优点
  • 提高代码可读性,明确表示某些值不应被修改。
  • 编译器会检查 const 的正确性,避免意外修改。
  • 优化可能性:编译器可能对 const 变量进行优化。

自动类型 (auto)

auto 是 C++11 引入的关键字,用于自动推导变量的类型,编译器会根据初始化表达式推断出变量的实际类型。

基本用法
auto x = 5;       // x 被推导为 int
auto y = 3.14;     // y 被推导为 double
auto z = "hello";  // z 被推导为 const char*
优势
  1. 简化代码:减少冗长的类型声明,尤其是复杂的模板类型。
  2. 提高可读性:当类型名很长或复杂时(如迭代器、lambda 表达式),auto 使代码更简洁。
  3. 避免类型错误:编译器自动推导,减少手动指定类型可能带来的错误。
使用场景
  1. 迭代器

    std::vector<int> vec = {1, 2, 3};
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        // it 自动推导为 std::vector<int>::iterator
    }
    
  2. Lambda 表达式

    auto func = [](int x) { return x * 2; };  // func 的类型由编译器推导
    
  3. 模板编程

    template <typename T, typename U>
    auto add(T t, U u) -> decltype(t + u) {  // C++11 的返回类型推导
        return t + u;
    }
    
注意事项
  1. 必须初始化auto 变量必须初始化,否则编译器无法推导类型。

    auto x;  // 错误:无法推导类型
    
  2. 引用和常量性:默认情况下,auto 会忽略引用和顶层 const。如果需要保留,需显式指定:

    int a = 10;
    const int b = 20;
    auto c = a;      // c 是 int(忽略引用和 const)
    auto &d = a;     // d 是 int&
    const auto e = b; // e 是 const int
    
  3. decltype 结合decltype(auto)(C++14)可以完全保留表达式的类型(包括引用和 const):

    int x = 10;
    int &ref = x;
    decltype(auto) y = ref;  // y 是 int&
    
总结

auto 是 C++ 中强大的类型推导工具,适用于简化代码、提高可读性和减少错误,但需注意其推导规则(如忽略引用和顶层 const)。


空类型 (void)

概述

void 是 C++ 中的一种特殊数据类型,表示“无类型”或“空类型”。它通常用于以下场景:

  1. 函数不返回任何值时作为返回类型
  2. 函数没有参数时作为参数列表
  3. 指向未知类型的指针(void*
主要用法
  1. 无返回值函数
void functionName() {
    // 函数体
    // 不需要return语句
}
  1. 无参数函数 (现代C++中更推荐使用空参数列表)
int functionName(void) {
    return 0;
}
  1. 通用指针 (void*)
void* ptr;  // 可以指向任何数据类型
int x = 10;
ptr = &x;   // 合法,但需要通过类型转换才能解引用
注意事项
  • void 类型的变量不能被声明
  • void 不能作为参数类型(除了上面提到的特殊用法)
  • void* 指针不能直接解引用,必须先转换为具体类型
  • C++中应尽量避免使用 void*,而使用模板或继承来实现多态
示例代码
#include <iostream>

// 无返回值函数
void printMessage() {
    std::cout << "Hello, World!" << std::endl;
}

// 使用void指针
void processData(void* data, int type) {
    if(type == 1) {
        int* intPtr = static_cast<int*>(data);
        std::cout << "Integer value: " << *intPtr << std::endl;
    }
    // 可以处理其他类型...
}

int main() {
    printMessage();
    
    int value = 42;
    processData(&value, 1);
    
    return 0;
}
现代C++建议
  • 对于无参数函数,使用空参数列表 () 而非 (void)
  • 尽量避免使用 void*,考虑使用 std::any (C++17) 或模板
  • 无返回值函数可以省略 return 语句,或使用 return;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值