解码C++基础——从C到C++
C++ 概述
C++ 是多范式编程语言,支持过程化编程、面向对象编程(OOP)和泛型编程,兼容 C 语言且增强了类型检查与功能特性。核心优势包括封装 / 继承 / 多态、模板与泛型编程、异常处理、标准模板库(STL)。
最简 C++ 程序与结构
#include <iostream> // 包含C++标准输入输出头文件
using namespace std; // 导入std命名空间,简化符号使用
int main() {
cout << "Hello World!" << endl; // 标准输出流输出字符串
return 0; // 程序正常结束返回0
}
程序核心结构:
- 头文件:提供函数 / 类的声明,C++ 标准头文件无
.h后缀(如<iostream>),兼容 C 头文件(如<stdio.h>可写为<cstdio>)。 - 命名空间:解决符号命名冲突,
std是 C++ 标准库的命名空间。 - main 函数:程序入口,返回
int类型表示运行状态(0 为正常)。
名字空间(Namespace)
基本概念
名字空间是 C++ 中用于划分自定义作用域的机制,核心目的是解决大型程序开发中全局符号命名冲突问题(如不同库、模块间的变量、函数重名)。不同名字空间内的同名符号相互独立,互不干扰,能有效管理代码模块的边界。
定义与使用
定义名字空间
名字空间通过namespace关键字定义,内部可包含变量、函数、类、甚至嵌套名字空间等元素:
// 定义名字空间:数学工具模块
namespace mathUtils {
int baseValue = 1; // 基础数值(语义化命名)
float calculateHalf(int inputNum) { // 计算输入值的一半
return inputNum / 2.0f;
}
}
访问名字空间符号
需通过 ** 作用域解析符::** 指定符号所属的名字空间,格式为名字空间名::符号名:
#include <iostream>// 头文件中声明名字空间符号(遵循声明-定义分离原则)
namespace mathUtils {
extern int baseValue;
extern float calculateHalf(int inputNum);
}
int main() {
std::cout << mathUtils::baseValue << std::endl; // 输出1
std::cout << mathUtils::calculateHalf(8) << std::endl; // 输出4
return 0;
}
using 语句(简化访问)
频繁使用名字空间名::符号名会增加代码冗余,可通过using语句简化访问:
导入整个名字空间
using namespace mathUtils; // 导入mathUtils中所有符号
int main() {
std::cout << baseValue << std::endl; // 直接访问baseValue
std::cout << calculateHalf(8) << std::endl; // 直接访问calculateHalf
return 0;
}
导入指定符号
避免导入全部符号导致的 “名字空间污染”(未使用的符号成为潜在冲突源):
using mathUtils::baseValue; // 仅导入baseValue
using mathUtils::calculateHalf;// 仅导入calculateHalf
int main() {
std::cout << baseValue << std::endl; // 合法
std::cout << calculateHalf(8) << std::endl; // 合法
return 0;
}
进阶语法
内嵌名字空间
名字空间支持嵌套定义,形成层级化的作用域结构,访问时需逐层指定:
namespace project { // 项目根名字空间
int globalConfig = 1; // 全局配置值
namespace calculateModule { // 计算模块子空间
int localConfig = 2; // 局部配置值
int resultCode = 100; // 结果状态码
}
}
int main() {
std::cout << project::globalConfig << std::endl; // 输出1
std::cout << project::calculateModule::localConfig << std::endl; // 输出2
std::cout << project::calculateModule::resultCode << std::endl; // 输出100
return 0;
}
名字空间的扩展性
同一名字空间可在不同位置补充定义,最终会合并为一个完整的作用域:
// 初始定义
namespace mathUtils {
int baseValue = 1;
}
// 扩展定义(新增符号)
namespace mathUtils {
int maxLimit = 666; // 新增最大值限制
}
int main() {
std::cout << mathUtils::baseValue << std::endl; // 输出1(原有符号)
std::cout << mathUtils::maxLimit << std::endl; // 输出666(新增符号)
return 0;
}
全局作用域
全局作用域是匿名的,若局部符号与全局符号重名,可通过::符号名访问全局符号:
int globalCounter = 100; // 全局计数器
int main() {
int globalCounter = 200; // 局部计数器(覆盖全局)
std::cout << globalCounter << std::endl; // 输出200(局部)
std::cout << ::globalCounter << std::endl; // 输出100(全局)
return 0;
}
实战问题:名字冲突解决
问题场景:自定义函数与标准库函数重名(如max)。解决方案:将自定义函数放入独立名字空间,避免冲突:
#include <iostream>
namespace customMath { // 自定义数学工具空间
int maxValue; // 存储最大值
void findMax(float firstNum, float secondNum) { // 寻找两数最大值
maxValue = firstNum > secondNum ? firstNum : secondNum;
}
}
int main() {
customMath::findMax(3.0f, 4.0f); // 明确调用自定义函数
std::cout << customMath::maxValue << std::endl; // 输出4
return 0;
}
输入输出流(cin/cout)
C++ 通过标准流对象实现输入输出,比 C 的scanf/printf更安全、易用。
核心流对象
- cout:标准输出流,输出数据到控制台,支持自动类型推导。
- cin:标准输入流,从控制台读取数据,自动匹配变量类型。
- cerr:标准错误流,无缓冲区,直接输出错误信息(用法同
cout)。
示例
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main() {
int a;
double b;
string s;
cout << "输入整数、浮点数、字符串:" << endl;
cin >> a >> b >> s; // 一次性读取多种类型
cout << "整数:" << a << endl;
cout << "浮点数:" << b << endl;
cout << "字符串:" << s << endl;
cerr << "错误信息示例" << endl; // 错误输出
return 0;
}
对比 C 输入输出
- 类型安全:
cin/cout自动匹配类型,scanf/printf需手动指定格式(易出错)。 - 扩展性:
cin/cout支持运算符重载(自定义类型可直接输出),scanf/printf需手动格式化。
数据类型与字符串
基础数据类型
C++ 兼容 C 的所有基础类型(char/short/int/long/float/double),新增bool类型(取值true/false)。
字符串类型(string)
C 语言用char[]/char*管理字符串(需手动处理内存),C++ 提供std::string(自动管理内存,支持动态扩容)。
#include <iostream>
#include <string> // 需包含string头文件
using std::cin;
using std::cout;
using std::string;
using std::endl;
int main() {
string s1 = "Hello";
string s2 = "World";
string s3 = s1 + " " + s2; // 字符串拼接(运算符重载)
cout << "拼接结果:" << s3 << endl; // 输出:Hello World
cout << "长度:" << s3.size() << endl; // 输出:11
cout << "子串:" << s3.substr(0, 5) << endl; // 输出:Hello
// 比较字符串
if (s1 == "Hello") {
cout << "s1等于Hello" << endl;
}
return 0;
}
优势
- 自动内存管理,避免缓冲区溢出(如 C 的
strcpy风险)。 - 支持运算符重载(
+拼接、=赋值、==比较等)。
引用机制
概念
引用是已存在变量的别名,与原变量共享内存地址,操作引用等价于操作原变量。
语法与特性
#include <iostream>
using namespace std;
int main() {
int a = 10;
int& ref = a; // 定义引用,必须初始化(ref是a的别名)
ref = 20; // 等价于a=20,a的值变为20
cout << "a = " << a << endl; // 输出:a = 20
cout << "ref = " << ref << endl; // 输出:ref = 20
cout << "a的地址:" << &a << endl;
cout << "ref的地址:" << &ref << endl; // 与a的地址相同
// 引用不可重新绑定
int b = 30;
ref = b; // 这是赋值,不是重新绑定!a的值变为30,ref仍指向a
cout << "a = " << a << endl; // 输出:a = 30
return 0;
}
核心规则
- 必须初始化:定义引用时必须绑定有效变量(
int& ref;非法)。 - 不可重新绑定:初始化后无法切换指向的变量。
- 无独立内存:引用是别名,不占用额外内存(编译器优化为指针常量
int* const)。 - 无空引用:必须绑定有效对象(
int& ref = NULL;非法)。
引用的应用
函数传参(避免拷贝,提升效率)
/**
* 交换两个整数的函数
* @brief 通过引用传参直接操作原变量,避免拷贝
* @param a 第一个整数的引用
* @param b 第二个整数的引用
* @return void 无返回值
*/
void swap(int& a, int& b) {
int tmp = a;
a = b;
b = tmp;
}
int main() {
int x = 5, y = 10;
swap(x, y);
cout << "x = " << x << ", y = " << y << endl; // 输出:x=10,y=5
return 0;
}
函数返回值(返回全局 / 静态变量的引用)
/**
* 返回静态变量的引用
* @brief 静态变量生命周期与程序一致,返回引用安全
* @return int& 静态变量A的引用
*/
int& getStaticVar() {
static int A = 10; // 静态变量,存储在全局区
return A;
}
int main() {
int& ref = getStaticVar();
ref = 20; // 修改静态变量的值
cout << getStaticVar() << endl; // 输出:20
return 0;
}
注意:避免返回局部变量的引用(局部变量在函数结束后销毁,引用变为 “悬空引用”)。
常量引用(只读访问,兼容临时对象)
/**
* 打印字符串的函数
* @brief 常量引用避免拷贝,且可绑定临时对象(如字面量)
* @param s 字符串的常量引用(只读,不可修改)
* @return void 无返回值
*/
void print(const string& s) {
cout << s << endl;
}
int main() {
print("Hello World"); // 常量引用可绑定临时字符串(合法)
string str = "Test";
print(str); // 也可绑定普通字符串
return 0;
}
引用与指针对比
| 特性 | 引用 | 指针 |
|---|---|---|
| 初始化 | 必须初始化 | 可空或后续赋值 |
| 语法 | 无需*/-> |
需*解引用、->访问成员 |
| 内存占用 | 无额外内存 | 占用内存(32 位 4B,64 位 8B) |
| 安全性 | 无空引用风险 | 需检查空指针 |
| 多级访问 | 仅支持一级引用 | 支持多级指针(如int**) |
类型转换
C++ 兼容 C 的旧式转换(如(int)f),新增新式类型转换(更安全、可读性更高)。
const_cast(去除 const/volatile 属性)
用途:仅用于指针或引用,去除其const/volatile限定。
#include <iostream>using namespace std;
int main() {
const int a = 10;
const int* p = &a;
// 错误:p是常目标指针,无法修改指向的内容
// *p = 20;
// 使用const_cast去除const属性
int* q = const_cast<int*>(p);
*q = 20; // 现在可修改(注意:若a是真正的常量,可能触发未定义行为)
cout << "a = " << a << endl; // 输出:a=20(a为普通const变量时生效)
// 处理引用
const int& ref = a;
// ref = 30; // 错误
const_cast<int&>(ref) = 30; // 合法
cout << "a = " << a << endl; // 输出:a=30
return 0;
}
注意:不能去除变量本身的const(如const int a=10;的a本质是常量,强制修改可能崩溃),仅能去除指针 / 引用的const属性。
static_cast(静态类型转换)
用途:用于兼容类型的转换(如数值类型、父类子类指针),编译期检查类型安全性。
#include <iostream>
using namespace std;
int main() {
float f = 3.14;
int i = static_cast<int>(f); // 浮点转整型(截断小数)
cout << "i = " << i << endl; // 输出:i=3
// 错误:不兼容类型转换,static_cast会报错(比旧式转换安全)
// int* p = static_cast<int*>(&f);
// 父类子类转换(上行转换安全)
class Base {};
class Derived : public Base {};
Derived d;
Base* b = static_cast<Base*>(&d); // 子类转父类(合法)
return 0;
}
优势:比旧式转换更易识别,且能阻止不兼容类型的转换(如float*转int*)。
dynamic_cast(动态类型转换)
用途:仅用于类的继承体系,运行期检查类型(需类有虚函数),实现安全的下行转换(父类转子类)。
reinterpret_cast(重解释转换)
用途:强制转换任意类型的指针 / 引用(风险高,如int*转char*),仅用于底层操作。
关键字 auto
auto让编译器自动推导变量类型,简化代码(尤其适用于复杂类型)。
#include <iostream>
#include <vector>
using namespace std;
int main() {
auto a = 10; // 推导为int
auto b = 3.14; // 推导为double
auto c = "Hello"; // 推导为const char*
vector<int> vec = {1,2,3};
for (auto it = vec.begin(); it != vec.end(); ++it) { // it推导为vector<int>::iterator
cout << *it << " ";
}
return 0;
}
注意:auto变量必须初始化(编译器需通过初始值推导类型)。
命名规范
C++ 无强制命名规范,但通用规则可提升代码可读性:
- 类名 / 结构体名:大驼峰式(首字母大写),如
AppleTree、Student。 - 变量 / 函数名:小驼峰式(首字母小写),如
studentName、calculateSum。 - 常量名:全大写 + 下划线,如
MAX_SIZE、PI。 - 命名空间名:小写,如
my_space。
函数特性
默认参数
函数参数可指定默认值,调用时若未传参则使用默认值。
/**
* 计算圆锥体体积
* @brief 高度默认值为1,半径必须传参
* @param r 圆锥底部半径(无默认值)
* @param h 圆锥高度(默认值1)
* @return double 圆锥体积(公式:1/3 * π * r² * h)
*/
double coneVolume(double r, double h = 1.0) {
const double PI = 3.1415926;
return (1.0 / 3) * PI * r * r * h;
}
int main() {
cout << "体积(h=默认):" << coneVolume(2) << endl; // h=1,输出≈4.1888
cout << "体积(h=3):" << coneVolume(2, 3) << endl; // h=3,输出≈12.5664
return 0;
}
规则:
- 默认参数必须从右到左连续定义(
int func(int a=1, int b);非法)。 - 声明和定义中默认参数不可重复(声明写默认值,定义不写)。
占位参数
函数参数仅声明类型,无参数名,用于预留接口或兼容旧代码。
/**
* 占位参数示例
* @brief 第二个参数为占位符,调用时需传值但函数内无法使用
* @param a 第一个参数(可用)
* @param int 第二个参数(占位,无名称)
* @return void 无返回值
*/
void func(int a, int) {
cout << "a = " << a << endl;
}
int main() {
func(10, 20); // 必须传第二个参数(20),但函数内无法访问
return 0;
}
函数重载
同一作用域内,同名函数的参数类型 / 个数 / 顺序不同,可形成重载(编译器根据参数区分调用)。
合法重载情形
#include <iostream>using namespace std;
// 参数个数不同
void print(int a) {
cout << "整数:" << a << endl;
}
void print(int a, int b) {
cout << "两个整数:" << a << "," << b << endl;
}
// 参数类型不同
void print(double a) {
cout << "浮点数:" << a << endl;
}
// 类方法const属性不同
class MyClass {
public:
void show() { // 普通方法
cout << "普通show()" << endl;
}
void show() const { // const方法(this指针为const)
cout << "const show()" << endl;
}
};
// 普通指针与常目标指针不同
void func(char* p) {
cout << "普通指针:" << p << endl;
}
void func(const char* p) {
cout << "常目标指针:" << p << endl;
}
int main() {
print(10); // 调用print(int)
print(3.14); // 调用print(double)
print(10, 20); // 调用print(int,int)
MyClass obj;
const MyClass constObj;
obj.show(); // 调用普通show()
constObj.show(); // 调用const show()
char* s = "test";
const char* cs = "const test";
func(s); // 调用func(char*)
func(cs); // 调用func(const char*)
return 0;
}
非法重载情形
- 返回值不同:
int func();与double func();无法重载。 - static 修饰不同:
static int func();与int func();无法重载。 - 参数 const 修饰不同(非指针 / 引用):
void func(int a);与void func(const int a);无法重载(参数本质相同)。 - 引用与值的歧义:
void func(int a);与void func(int& a);调用func(10)时会二义性(10 是常量,无法绑定普通引用)。
堆内存管理
C 语言用malloc/free管理堆内存,C++ 提供new/delete(更安全,支持对象构造 / 析构)。
单个对象的 new/delete
#include <iostream>
using namespace std;
int main() {
// 动态分配int类型内存,初始化为10
int* p = new int(10);
cout << *p << endl; // 输出:10
delete p; // 释放内存(必须配对,否则内存泄漏)
p = nullptr; // 避免悬空指针
// 动态分配对象
class Test {
public:
Test() { cout << "Test构造" << endl; }
~Test() { cout << "Test析构" << endl; }
};
Test* t = new Test(); // 调用构造函数
delete t; // 调用析构函数+释放内存
return 0;
}
数组的 new []/delete []
int main() {
// 动态分配int数组(5个元素)
int* arr = new int[5]{1,2,3,4,5}; // C++11支持初始化
for (int i=0; i<5; i++) {
cout << arr[i] << " ";
}
cout << endl;
delete[] arr; // 释放数组(必须用delete[],否则仅释放第一个元素)
arr = nullptr;
return 0;
}
对比 malloc/free
new/delete是运算符,malloc/free是函数。new自动调用构造函数,delete自动调用析构函数(malloc/free不支持)。new返回对应类型指针(无需强制转换),malloc返回void*(需转换)。
枚举与范围 for 循环
枚举(enum/enum class)
普通枚举
enum Color {
Red, // 默认0
Green, // 1
Blue // 2
};
int main() {
Color c = Red;
cout << c << endl; // 输出:0
return 0;
}
强类型枚举(enum class)
C++11 新增,避免枚举值冲突,类型安全。
enum class Direction {
Left,
Right
};
int main() {
Direction d = Direction::Left;
// cout << d << endl; // 错误:强类型枚举不能直接输出
cout << static_cast<int>(d) << endl; // 输出:0
return 0;
}
范围 for 循环(C++11)
遍历数组、容器等可迭代对象,简化循环代码。
#include <iostream>
#include <vector>
using namespace std;
int main() {
int arr[] = {1,2,3,4,5};
// 遍历数组
for (int num : arr) {
cout << num << " ";
}
cout << endl;
vector<string> vec = {"a", "b", "c"};
// 遍历vector(引用避免拷贝)
for (auto& s : vec) {
cout << s << " ";
}
cout << endl;
return 0;
}
extern "C" 机制
C++ 支持调用 C 语言代码,需用extern "C"禁用 C++ 的名称修饰(Name Mangling),确保 C++ 编译器按 C 规则处理函数名。
// C语言头文件(c_func.h)
#ifdef __cplusplus
extern "C" { // 仅在C++编译器中生效
#endif
void c_function(int x); // C语言函数声明
#ifdef __cplusplus
}
#endif
// C语言实现(c_func.c)
#include "c_func.h"
#include <stdio.h>
void c_function(int x) {
printf("C函数:x=%d\n", x);
}
// C++调用(main.cpp)
#include "c_func.h"
using namespace std;
int main() {
c_function(10); // 调用C语言函数
return 0;
}
原理:C++ 为支持函数重载,会修改函数名(如add(int)变为_Z3addi),而 C 语言不修饰函数名。extern "C"让 C++ 编译器按 C 规则生成函数名,保证链接成功。
内存分区
C++ 程序运行时内存分为 5 个区域:
| 内存分区 | 存储内容 | 生命周期 | 管理方式 |
|---|---|---|---|
| 栈区 | 局部变量、函数参数、返回地址 | 函数结束自动释放 | 编译器自动分配释放 |
| 堆区 | new/malloc 分配的对象 | 手动 delete/free 释放 | 程序员手动管理 |
| 全局 / 静态区 | 全局变量、static 变量 | 程序启动分配,结束释放 | 编译器静态分配 |
| 常量区 | 字符串常量、const 全局常量 | 程序运行期间 | 只读,不可修改 |
| 代码区 | 二进制指令、函数体代码 | 程序运行期间 | 只读,共享内存 |
异常处理(Exception)
基本概念
异常是程序运行过程中出现的非正常情况(如除零错误、空指针访问、参数非法等)。C++ 通过 “抛出 - 捕获” 机制处理异常:throw抛出异常,try-catch捕获并处理,避免程序直接崩溃,提升鲁棒性。
异常的抛出与捕获
抛出异常(throw)
使用throw关键字抛出异常,可抛出任意类型(字面量、对象、标准异常类):
/**
* 除法函数:计算两数相除
* @param dividend 被除数
* @param divisor 除数
* @return float 除法结果
* @throw const char* 除数为0时抛出异常信息
*/
float divideNumbers(float dividend, float divisor) {
if (divisor == 0) {
throw "除数不能为零"; // 抛出字符串类型异常
}
return dividend / divisor;
}
捕获异常(try-catch)
try块:包裹可能抛出异常的代码;catch块:按类型捕获异常并处理,可设置多个catch匹配不同类型;catch(...):捕获所有未匹配的异常(兜底处理)。
#include <iostream>
using namespace std;
int main() {
float inputDividend, inputDivisor, calculateResult;
while (true) {
cin >> inputDividend >> inputDivisor;
try {
calculateResult = divideNumbers(inputDividend, inputDivisor);
cout << calculateResult << endl;
} catch (const char* errorMsg) { // 捕获字符串类型异常
cout << "错误:" << errorMsg << endl;
break;
} catch (...) { // 捕获所有其他类型异常
cout << "未知错误" << endl;
}
}
return 0;
}
异常的类型
可通过不同类型区分异常场景,catch块按类型匹配执行:
#include <iostream>
#include <stdexcept> // 标准异常类头文件
using namespace std;
void checkInput(int inputNum) { // 检查输入值合法性
if (inputNum == 1) throw 666; // 整数错误码
if (inputNum == 2) throw 3.14f; // 浮点错误码
if (inputNum == 3) throw runtime_error("参数超出合法范围"); // 标准异常类
}
int main() {
int userInput;
cin >> userInput;
try {
checkInput(userInput);
} catch (int intErrorCode) { // 匹配整数类型异常
cout << "整数错误:" << intErrorCode << endl;
} catch (float floatErrorCode) { // 匹配浮点类型异常
cout << "浮点错误:" << floatErrorCode << endl;
} catch (runtime_error& standardError) { // 匹配标准异常类
cout << "标准异常:" << standardError.what() << endl; // what()返回异常描述
}
return 0;
}
标准异常类
C++ 标准库提供了一系列异常类(继承自exception),常用的有:
invalid_argument:参数非法;out_of_range:越界访问;runtime_error:运行时错误;logic_error:逻辑错误(如前置条件不满足)。
示例:使用标准异常类抛出异常
#include <iostream>
#include <stdexcept>
using namespace std;
float divideNumbers(float dividend, float divisor) {
if (divisor == 0) {
throw invalid_argument("除数不能为零(标准异常)"); // 抛出标准异常对象
}
return dividend / divisor;
}
int main() {
try {
divideNumbers(10, 0);
} catch (invalid_argument& e) {
cout << e.what() << endl; // 输出:除数不能为零(标准异常)
}
return 0;
}
异常与返回错误值的区别
| 特性 | 返回错误值 | 异常处理 |
|---|---|---|
| 传播性 | 需手动传递错误码(如返回值层层传递) | 自动向上传播(直到被捕获) |
| 强制性 | 易忽略(如未检查返回值) | 必须处理(否则程序终止) |
| 信息承载 | 仅支持基础类型(如 int 错误码) | 支持类对象,可携带详细信息 |
| 代码可读性 | 错误处理与业务逻辑混杂 | 错误处理与业务逻辑分离 |
析构函数中的异常
析构函数抛出异常可能导致程序崩溃(如栈展开时触发双重异常),因此析构函数内需捕获所有异常:
#include <iostream>
using namespace std;
bool dbConnectionStatus = false; // 数据库连接状态
void closeDbConnection() { // 模拟关闭数据库连接
if (!dbConnectionStatus) throw 100; // 连接未启用时抛异常
else cout << "数据库连接正常关闭" << endl;
}
class DbConnector { // 管理数据库连接的类
bool isClosed = false; // 是否已关闭
public:
~DbConnector() { // 析构函数自动关闭连接
if (!isClosed) {
try {
closeDbConnection(); // 尝试关闭
} catch (...) { // 捕获所有异常,避免崩溃
cout << "析构时关闭数据库失败" << endl;
}
}
}
void manualCloseDb() { // 手动关闭(用户可处理异常)
closeDbConnection();
isClosed = true;
}
};
int main() {
DbConnector dbInstance;
try {
dbInstance.manualCloseDb(); // 手动关闭,主动处理异常
} catch (...) {
cout << "手动关闭失败,修复连接状态" << endl;
dbConnectionStatus = true; // 修复状态
}
return 0;
}
Lambda 函数(匿名函数)
基本概念
Lambda 函数(匿名函数)是 C++11 引入的函数对象,可直接定义在代码中,无需显式命名,支持捕获外部变量、作为参数传递、作为返回值等特性。常用于简化代码(如一次性函数)、实现函数式编程。
语法结构
[capture list](parameter list) mutable -> return type { function body }
- capture list(捕获列表):指定捕获外部变量的方式(值捕获 / 引用捕获);
- parameter list(参数列表):函数参数(同普通函数);
- mutable:允许修改值捕获的变量(默认值捕获为只读);
- return type(返回类型):可省略,编译器自动推导;
- function body(函数体):业务逻辑代码。
捕获列表的用法
值捕获([变量名])
捕获外部变量的副本,Lambda 内部修改不影响外部变量:
#include <iostream>
using namespace std;
int main() {
int firstNum = 1, secondNum = 2;
// 值捕获firstNum和secondNum,计算两数之和
auto sumTwoNumbers = [firstNum, secondNum]() {
return firstNum + secondNum;
};
cout << sumTwoNumbers() << endl; // 输出3
return 0;
}
引用捕获([& 变量名])
捕获外部变量的引用,Lambda 内部修改会影响外部变量:
int main() {
int num = 10;
// 引用捕获num,修改其值
auto modifyNum = [&num]() {
num *= 2;
};
modifyNum();
cout << num << endl; // 输出20
return 0;
}
捕获所有外部变量
[=]:值捕获所有外部变量;[&]:引用捕获所有外部变量。
int main() {
int a = 1, b = 2;
// 值捕获所有外部变量
auto printAll = [=]() {
cout << "a=" << a << ", b=" << b << endl;
};
printAll(); // 输出:a=1, b=2
// 引用捕获所有外部变量
auto modifyAll = [&]() {
a += b;
b *= 2;
};
modifyAll();
cout << "a=" << a << ", b=" << b << endl; // 输出:a=3, b=4
return 0;
}
Lambda 函数的使用场景
作为函数参数
常用于 STL 算法(如sort、count_if),简化谓词逻辑:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> numVector = {3, 1, 4, 1, 5, 9};
// 统计偶数个数:Lambda作为count_if的谓词参数
int evenCount = count_if(numVector.begin(), numVector.end(),
[](int currentNum) { // 参数由count_if自动传递
return currentNum % 2 == 0;
});
cout << "偶数个数:" << evenCount << endl; // 输出2
return 0;
}
作为函数返回值
Lambda 可作为函数返回值(需用auto推导类型):
/**
* 创建加法器:返回Lambda函数
* @param fixedAddend 固定加数
* @return auto 加法器(接收一个int参数,返回两数之和)
*/
auto createAdder(int fixedAddend) {
return [fixedAddend](int variableAddend) {
return fixedAddend + variableAddend;
};
}
int main() {
auto addFive = createAdder(5); // 生成“加5”的加法器
cout << addFive(3) << endl; // 输出8(5+3)
cout << addFive(10) << endl; // 输出15(5+10)
return 0;
}
高阶函数调用
Lambda 作为参数传递给自定义高阶函数:
/**
* 检查数字是否满足条件
* @param targetNum 目标数字
* @param checkCondition 检查条件(Lambda函数)
*/
void checkNumber(int targetNum, auto checkCondition) {
if (checkCondition(targetNum)) {
cout << targetNum << "满足条件" << endl;
} else {
cout << targetNum << "不满足条件" << endl;
}
}
int main() {
// 检查是否为奇数
checkNumber(5, [](int num) {
return num % 2 != 0;
});
// 检查是否大于10
checkNumber(8, [](int num) {
return num > 10;
});
return 0;
}
函数式编程简介
Lambda 是函数式编程的基础,函数式编程强调数据映射而非 “步骤指令”,核心特点:
- 函数是一等公民(可作为参数、返回值);
- 避免可变状态,推崇纯函数(输入确定则输出确定);
示例:函数式实现字符串翻转
#include <string>
using namespace std;
// 函数式:通过递归映射实现字符串翻转
string reverseString(const string& inputStr) {
return inputStr.empty() ? inputStr :
reverseString(inputStr.substr(1)) + inputStr[0];
}
int main() {
string str = "abcdef";
cout << reverseString(str) << endl; // 输出:fedcba
return 0;
}
Lambda 的注意事项
- 捕获列表为空时,需写
[](不可省略); - 值捕获的变量默认只读,需
mutable才能修改; - Lambda 的生命周期与普通变量一致,捕获的外部变量若销毁,Lambda 访问会导致未定义行为。

浙公网安备 33010602011771号