C++20 高级编程 002:夯实现代C++底层基本功

前言

不少刚上手现代 C++ 的开发者,还停留在 C 语言式的老旧写法里,既错过 C++20 带来的便捷新特性,又容易踩各种隐性 bug。今天我们把 C++20 最核心的入门语法串讲一遍,涵盖模块化编程、各类分支控制、新式运算符、函数设计、编译属性、数组容器六大板块,搭配可直接运行的示例代码,轻松吃透现代 C++ 基础语法,避开无数新手高频坑✨

Bilibili 同步视频

C++20 高级编程 002:夯实现代C++底层基本功

一、告别头文件混乱:C++20 Module 模块系统

在 C++20 之前,项目依赖.h头文件反复包含,宏污染、重复引入、编译缓慢都是家常便饭。而模块(module) 彻底重构了代码导入导出逻辑,核心靠export控制对外可见内容。

核心规则

  1. export module xxx; 定义独立模块;

  2. export修饰结构体、函数,外部导入后才能访问;不加export仅模块内部可用;

  3. 导入标准库用尖括号import <xxx>,导入自定义模块禁止尖括号,直接写模块名。

完整可运行示例

cpp 复制代码
// employee.ixx 模块接口文件
export module employee;

// 导出结构体,外部模块可直接使用
export struct Employee {
    char firstInitial;
    char lastInitial;
    int employeeNumber;
    int salary;
};
cpp 复制代码
// main.cpp
import <iostream>;
import <format>;
import employee;

using namespace std;

int main() {
    // 实例化员工结构体并赋值
    Employee staff{};
    staff.firstInitial = 'L';
    staff.lastInitial = 'W';
    staff.employeeNumber = 1001;
    staff.salary = 150000;

    // format格式化输出,可读性远优于老式printf
    cout << format("员工简称:{}{}n", staff.firstInitial, staff.lastInitial);
    cout << format("工号:{}n", staff.employeeNumber);
    cout << format("年薪:${}n", staff.salary);
    return 0;
}

对比传统头文件,模块不会产生全局污染,编译速度大幅提升,大型工程维护体验直接拉满。

二、分支控制全解:if/else、switch 双巨头,C++20 新增初始化语法

业务逻辑离不开条件判断,C++ 提供两套分支体系,同时新增初始化器语法,大幅精简代码层级。

1. if/else:级联判断 + 内置初始化器

普通 if-else if-else 逻辑无需多讲,记住一条铁律:表达式中0 等价 false,非 0 全部视为 true 。 而 C++17 起支持if(初始化语句; 判断条件),初始化的变量生命周期仅限整条 if 分支,局部性更强,减少无用变量污染全局作用域。

示例场景:读取员工信息,同时判断薪资阈值

cpp 复制代码
// 复用上方Employee结构体
int getEmployee() {
    return 9000;
}

int main() {
    // if内置初始化:临时获取薪资,仅分支内可用
    if (int salary = getEmployee(); salary > 10000) {
        cout << format("高薪员工,薪资:{}n", salary);
    } else if (salary > 5000) {
        cout << format("普通薪资,薪资:{}n", salary);
    } else {
        cout << format("基础薪资,薪资:{}n", salary);
    }
    // 此处无法访问salary,变量生命周期已结束
    return 0;
}

2. switch 语句:枚举匹配、穿透处理、同样支持初始化

switch 匹配类型受限:仅整型、可转整型类型、枚举、强枚举,只能和常量对比。

高频坑:case 穿透 fallthrough

如果 case 末尾不写break,代码会顺序执行下一个 case 逻辑,绝大多数场景是 bug;但如果是刻意穿透,必须加[[fallthrough]]属性消除编译器警告。

cpp 复制代码
enum class Mode { Custom, Standard, Default };

int main() {
    Mode runMode = Mode::Custom;
    int value = 0;

    switch (runMode) {
        using enum Mode;
        case Custom:
            value = 84;
            // 刻意穿透,标记属性避免告警
            [[fallthrough]];
        case Standard:
        case Default:
            cout << format("当前配置数值:{}n", value);
            break;
        default:
            cout << "未知运行模式n";
            break;
    }
    return 0;
}

另外 switch 同样支持初始化语法:switch(变量初始化; 匹配表达式),适合读取配置后直接分支判断。

三、简洁万能表达式:三元条件运算符?:

if 语句是语句 ,不能嵌入赋值、打印等表达式场景;而三元运算符是纯正表达式,随时随地可用,语法模板: 判断条件 ? 条件成立取值 : 条件不成立取值

cpp 复制代码
int num = 10;
// 直接嵌入cout输出,代码极度精简
cout << (num > 5 ? "数字大于5" : "数字小于等于5") << endl;

// 用于赋值场景
std::string desc = num % 2 == 0 ? "偶数" : "奇数";
cout << desc << endl;

小技巧:问号可以理解为提问,num>5?翻译为 "num 大于 5 吗?",记忆零难度。

四、逻辑与比较运算符:短路求值 + 太空飞船 <=> 运算符

1. 基础运算符清单 & 短路特性

运算符 作用 关键注意点
== 判断相等 切勿和赋值=混淆,新手高频 bug
!= 不等于 -
< <= > >= 大小比较 -
! 逻辑非(取反) 一元运算符,单操作数
&& 逻辑与 左侧 false 直接短路,右侧不执行
` ` 逻辑或 左侧 true 直接短路,右侧不执行

短路是一把双刃剑👍: 优势:做指针判空、边界校验,避免非法访问;减少多余判断,提升运行效率; 隐患:若右侧包含函数调用、变量自增,短路后代码不会执行,隐藏难以复现的隐性 bug。

2. C++20 王牌:三向比较运算符 <=>(太空飞船运算符)

传统写法判断两个数字大小,至少需要两次比较;<=>一次运算就能区分小于、等于、大于三种关系,返回标准化排序类型。

  • 整数:std::strong_ordering(less / equal / greater)

  • 浮点数:std::partial_ordering(存在 unordered,对应 NaN 无效数值)

配套<compare>头文件工具函数is_eq/is_lt/is_gt,简化结果判断:

cpp 复制代码
#include <compare>
#include <iostream>

int main() {
    int a = 11, b = 5;
    auto res = a <=> b;

    if (std::is_lt(res)) cout << "a < bn";
    else if (std::is_eq(res)) cout << "a == bn";
    else if (std::is_gt(res)) cout << "a > bn";
    return 0;
}

大型自定义类对比场景优势巨大:仅执行一次比较逻辑,代替两次昂贵的成员比对,性能收益显著。

五、现代 C++ 函数体系:自动返回值、重载、编译期内置变量

函数是代码拆分的核心单元,C++ 在 C 基础上拓展了大量实用特性。

1. 基础声明与定义

声明(函数原型)仅描述调用规则,定义携带函数实体;无返回值标注void,无参数直接空括号,无需写void(和 C 区分)。

2. auto 自动推导返回类型

不用手动写返回值,编译器根据return表达式自动推导;多 return 语句返回类型必须统一。

cpp 复制代码
// 自动推导返回值为int
auto add(int a, int b) {
    return a + b;
}

3. func 获取当前函数名

内置局部变量,快速实现日志埋点,调试神器:

cpp 复制代码
auto add(int a, int b) {
    std::cout << format("进入函数:{}n", __func__);
    return a + b;
}

4. 函数重载

同名函数依靠参数数量 / 参数类型区分,仅返回值不同无法重载,编译器会根据实参自动匹配版本:

cpp 复制代码
// 整数重载
int calc(int a, int b) { return a + b; }
// 浮点重载
double calc(double a, double b) { return a + b; }

六、编译器属性 \[xxx]:给编译器传递提示,规避警告、优化分支

C++11 标准化双方括号属性,用来给编译器附加额外提示,日常开发最常用 5 种:

  1. \[nodiscard] 修饰带返回值函数,调用时忽略返回值会触发编译警告,C++20 支持附加说明文字,专门用来防止遗漏错误码:
cpp 复制代码
[[nodiscard("返回错误码,不可忽略")]] int checkAuth() {
    return 1;
}

int main() {
    checkAuth(); // 编译器抛出警告,提醒丢弃返回值
    return 0;
}
  1. \[maybe_unused] 屏蔽 "变量 / 参数未使用" 警告,接口预留占位参数必备:
cpp 复制代码
void test(int a, [[maybe_unused]] int reserveParam) {
    cout << a << endl;
}
  1. \[noreturn] 标记函数永远不会返回调用方(程序退出、抛出异常),消除 "分支无返回值" 编译报错:
cpp 复制代码
#include <cstdlib>
[[noreturn]] void exitApp() {
    std::exit(-1);
}
  1. \[deprecated ("替换为 newFunc 接口")] 标记接口废弃,调用时告警,用于版本迭代淘汰旧 API。

  2. \[likely] / \[unlikely] 标记高 / 低概率分支,辅助编译器做底层指令优化,仅极致性能场景使用。

七、数组选型:摒弃老旧 C 数组,优先 std::array

1. C 风格原生数组痛点

  • 长度必须是常量,不支持变量动态长度;

  • 下标从 0 开始,极易越界;

  • 隐式转为普通指针,丢失长度信息,传递后无法获取大小; 初始化示例:

cpp 复制代码
int arr[5]{}; // 全部初始化为0
int arr2[]{1,2,3}; // 编译器自动推导长度为3

获取长度两种方式:

cpp 复制代码
#include <array>
int arr[5]{};
size_t len1 = std::size(arr); // 现代标准推荐
size_t len2 = sizeof(arr) / sizeof(arr[0]); // 老式写法

2. std::array 标准固定数组容器(推荐首选)

定义于<array>,对 C 数组轻量封装,解决原生数组全部缺陷:自带 size ()、不会隐式转指针、支持迭代器,模板格式std::array<元素类型, 固定长度>

cpp 复制代码
#include <array>
#include <iostream>
#include <format>

int main() {
    std::array<int, 4> nums{10, 20, 30, 40};
    cout << format("容器长度:{}n", nums.size());
    cout << format("第二个元素:{}n", nums[1]);
    return 0;
}

结语

以上覆盖了 C++20 入门阶段最核心的语法体系,从模块化工程管理、分支逻辑、新式运算符,到函数规范、编译属性、容器数组,每一块都配套可直接编译运行的代码。 现代 C++ 早已摆脱 C 语言粗糙的语法束缚,合理运用模块、初始化分支、<=>运算符、std::array 等新特性,既能减少 80% 新手 bug,又能提升代码可读性与运行性能。后续我们可以基于这些基础,继续深挖类、模板、标准容器等进阶内容,逐步构建完整的现代 C++ 知识栈。

相关推荐
老赵的博客1 小时前
可维护性 可扩展性 可复用性
开发语言·c++
不正经学生3 小时前
C语言大小端字节序:内存里字节的排列顺序
c语言·开发语言·arm开发·c++·算法·c#
小则又沐风a3 小时前
负载均衡式在线OJ---------第二幕
linux·c++·后端
a3535413823 小时前
C++项目如何架构优化
java·c++·架构
键盘会跳舞4 小时前
C++:智能指针源码级深度拆解——从 RAII 思想到引用计数的内存安全体系
c++·智能指针·unique_ptr·shared_ptr·weak_ptr
SNAKEpc121384 小时前
OpenGL(十三)- Mip贴图
c语言·c++·图形渲染·贴图
会周易的程序员17 小时前
aiDgePLC — IEC61131-3 ST PLC 虚拟机调试与运行环境
c++·物联网·虚拟机·st·工业协议·iec61131·梯形图
wuminyu18 小时前
JVM利用io_uring优化堆外内存性能原理剖析
java·linux·c语言·jvm·c++
gumichef18 小时前
第二章:C/C++内存管理
c++·内存管理