完整教程:解码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++ 无强制命名规范,但通用规则可提升代码可读性:

  • 类名 / 结构体名:大驼峰式(首字母大写),如AppleTreeStudent
  • 变量 / 函数名:小驼峰式(首字母小写),如studentNamecalculateSum
  • 常量名:全大写 + 下划线,如MAX_SIZEPI
  • 命名空间名:小写,如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 算法(如sortcount_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; // 输出1
        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 访问会导致未定义行为。
posted @ 2025-12-28 09:08  yangykaifa  阅读(3)  评论(0)    收藏  举报