C++ 快速上手指南

第一部分:基础与项目结构

1. 项目组织结构

一个完整的C++项目通常包含以下文件类型和目录结构。

常见文件类型

后缀 类型 功能
.h / .hpp 头文件 放置各种声明(类型、函数、类等),不建议放实现代码。
.c / .cpp 源文件 放置头文件中声明的定义。通过 #include 关联头文件。
makefile 构建配置 定义项目源码的编译过程。
CMakeLists.txt CMake配置 跨平台的编译配置,可生成makefile
.dll / .so 动态链接库 程序的外部功能支持库。
.o / .obj 编译目标文件 源码直接编译生成的原始二进制文件。
.a / .lib 静态链接库 .o / .obj文件组合而成。

推荐项目目录结构

  • build/:编译目录(可包含 debug/release/ 子目录)。
  • dist/:发布目录。
  • doc/:文档目录。
  • include/:公共头文件目录。
  • lib/:外部依赖库目录。
  • res/:资源目录。
  • samples/:示例代码目录。
  • src/:项目源代码目录。
  • tools/:项目支持工具目录。
  • 根目录:makefileCMakeLists.txt

程序入口点

  • 每个C++应用有且仅有一个 main() 函数。
  • 标准形式:int main(int argc, char *argv[])
    • argc:参数个数。
    • argv:参数字符串数组。

2. 源码文件结构

C++源码分为声明定义两部分。

  • 声明:将名称(变量、函数、类等)引入程序,通常放在头文件(.h)中。
  • 定义:将声明的内容具体实现,通常放在源文件(.cpp)中。
  • 前向声明:为解决交叉引用问题,在定义前先声明类名,但只能用于定义指针、引用和函数形参。

代码组织顺序(推荐)

  1. #include 引用
  2. 预处理指令
  3. 命名空间定义或引用
  4. 自定义类型声明
  5. 声明(类、函数等)
  6. 定义(类成员、函数等)
  7. main() 主函数

第二部分:核心语言特性

1. 预处理器指令

# 开头,在编译前执行。

#include

  • #include <文件名>:在标准库目录中搜索。
  • #include "文件名":在指定文件目录(当前目录或相对路径)中搜索。

#define

  • 对象宏#define 宏名 替代内容。例如:#define PI 3.14
  • 函数宏#define 宏名(参数) (表达式)。例如:#define MAX(a,b) (a>b?a:b)
  • 特殊运算符
    • #:将参数转换为字符串。例如:#define STR(x) #xSTR(123) -> "123"
    • ##:连接两个参数。例如:#define CC(x,y) x##yCC(a, b) -> ab
  • 取消定义#undef 宏名

条件编译

  • #ifdef / #ifndef:检查宏是否已定义。

  • #if#elif#else#endif

  • 头文件保护(防止重复包含)

    1
    2
    3
    4
    #ifndef CLASS_A_H_
    #define CLASS_A_H_
    // 类声明内容
    #endif

2. 命名空间

  • 定义namespace 命名空间名 { ... },用于避免命名冲突。
  • 访问:使用 :: 作用域解析符,例如 Galaxy::stars
  • 简化使用
    • using 命名空间名::名称;:引入单个名称。
    • using namespace 命名空间名;:引入整个命名空间。

3. 数据类型与变量

基本数据类型

类型 关键字 常用修饰符
布尔型 bool true, false
字符型 char signed, unsigned
整型 int short, long, signed, unsigned
浮点型 float 单精度
双精度浮点 double 双精度
无类型 void -
宽字符型 wchar_t -

变量

  • 定义数据类型 变量名;,例如 int a;
  • 初始化int a = 5;int a(5);
  • 作用域
    • 局部变量:在函数或代码块内声明,需手动初始化。
    • 全局变量:在函数外声明,系统自动初始化为默认值(0, \0, nullptr等)。
    • 形式参数:函数定义中声明的参数。

变量修饰符

  • static:保持变量生命周期或限制作用域。
  • extern:声明在其他文件中定义的全局变量或函数。
  • const:定义常量,值不可修改。
  • volatile:通知编译器不要优化,直接从内存读取。
  • mutable:允许被 const 成员函数修改。
  • thread_local:每个线程拥有独立副本。

4. 复合数据类型

数组

  • 定义类型 数组名[大小];
  • 初始化int arr[3] = {1, 2, 3};
  • 访问arr[索引],索引从0开始。
  • 多维数组int arr2d[3][4];,视为“数组的数组”。

字符串

  • C风格字符串:字符数组,以 \0 结尾。char greeting[] = "Hello";
  • C++ string类:需包含 <string>std::string str = "Hello";

结构体 (struct)

  • 用户自定义的聚合数据类型,成员默认是 public
  • 定义struct 结构名 { 成员类型 成员名; };
  • 访问结构变量.成员结构指针->成员

联合体 (union)

  • 所有成员共享同一内存,一次只能使用一个成员。
  • 大小由最大成员决定。

枚举 (enum)

  • 定义一组命名的整数常量。
  • 定义enum 枚举名 { 常量1, 常量2, ... };。默认从0开始递增。
  • C++11强类型枚举enum class 枚举名 { ... };,防止隐式转换和命名污染。

类型别名 (typedef)

  • 定义typedef 原类型 别名;
  • C++11 using别名using 别名 = 原类型;,更适用于模板。

5. 控制结构

分支语句

  • if / else if / else
  • switch / case / default:注意 break 的使用,否则会“穿透”。
  • 三元运算符条件 ? 表达式1 : 表达式2

循环语句

  • for 循环:for (初始化; 条件; 步进) { ... }
  • while 循环:while (条件) { ... }
  • do-while 循环:do { ... } while (条件);,至少执行一次。
  • 循环控制
    • break:立即退出当前循环。
    • continue:跳过本次循环剩余部分,进入下一次迭代。

6. 函数

函数定义

1
2
3
4
返回值类型 函数名(参数列表) {
// 函数体
return 返回值;
}

函数重载

函数名相同,但参数列表(数量或类型)不同。

参数传递

  • 按值传递:传递副本,不修改原值。
  • 按指针传递:传递地址,可修改原值。void func(int *p)
  • 按引用传递:传递别名,可修改原值。void func(int &ref)

参数默认值

在声明时指定:int func(int a, int b = 10);

Lambda表达式 (C++11)

  • 定义[捕获列表](参数列表) -> 返回值类型 { 函数体 }
  • 捕获方式
    • []:不捕获任何外部变量。
    • [=]:以值捕获所有外部变量。
    • [&]:以引用捕获所有外部变量。
    • [a, &b]:a值捕获,b引用捕获。

7. 指针与引用

指针

  • 定义类型 *指针名;,例如 int *p;
  • 操作符
    • &:取地址符,p = &a;
    • *:解引用符,*p = 10;
  • 指针与数组:数组名是常量指针,指向数组首元素。arr[i] 等价于 *(arr + i)
  • 空指针nullptr (C++11),NULL0 (旧式)。
  • 函数指针返回值类型 (*函数指针名)(参数列表);

引用

  • 定义类型 &引用名 = 原变量;,是原变量的别名。
  • 特性
    1. 必须在声明时初始化。
    2. 一旦绑定,不可更改引用的对象。
    3. 不存在空引用。
  • 常用场景:函数参数(避免拷贝,可修改原值)和返回值(返回对象本身)。

8. 动态内存管理

  • 分配
    • 类型 *指针 = new 类型; (单个对象)
    • 类型 *数组 = new 类型[大小]; (对象数组)
  • 释放
    • delete 指针; (单个对象)
    • delete[] 数组指针; (对象数组)
  • 规则
    • 不要重复释放同一内存。
    • delete 空指针是安全的。
    • 务必匹配 newdeletenew[]delete[]
  • C风格malloc()free(),但不会调用构造函数/析构函数。

第三部分:面向对象编程

1. 类 (class)

  • 声明class 类名 { private: ... public: ... }; 成员默认是 private
  • 成员函数定义返回值类型 类名::函数名(参数) { ... }
  • this指针:指向当前对象实例的指针。

2. 构造函数与析构函数

  • 构造函数
    • 与类同名,无返回值,用于初始化对象。
    • 可以重载。
    • 初始化列表类名(参数列表): 成员1(值1), 成员2(值2) { ... }
  • 析构函数
    • 与类同名,前加 ~,无返回值,无参数。
    • 对象销毁时自动调用,用于清理资源。
  • 默认构造函数类名() = default; (C++11)
  • 委托构造函数 (C++11):构造函数调用另一个构造函数。

3. 继承

  • 格式class 子类名 : 访问控制符 基类名 { ... }
  • 访问控制符
    • public:保持基类成员的原有访问级别。
    • protected:基类的 publicprotected 成员变为 protected
    • private:基类所有成员变为 private
  • 构造函数:子类构造函数通过初始化列表调用基类构造函数。Child(参数): Base(参数) { ... }

4. 多态

  • 虚函数:基类中使用 virtual 关键字声明,子类可重写,实现动态绑定。
  • 纯虚函数virtual void func() = 0;,使类成为抽象类,不可实例化。
  • override (C++11):显式声明重写基类的虚函数。
  • final (C++11):阻止类被继承或虚函数被重写。

5. 运算符重载

  • 格式返回值类型 operator运算符(参数列表)
  • 可以重载为成员函数或友元函数。

6. 友元

  • 使用 friend 关键字,允许外部函数或类访问其私有成员。
  • 类型:友元函数、友元类、友元成员函数。

7. 异常处理

  • 抛出throw 异常对象;

  • 捕获

    1
    2
    3
    4
    5
    6
    7
    try {
    // 可能抛出异常的代码
    } catch (异常类型1 &e) {
    // 处理
    } catch (...) {
    // 处理所有其他异常
    }
  • 异常规范

    • noexcept (C++11):函数不会抛出异常。
    • throw(...):旧式规范,已弃用。

8. const 成员函数

  • 定义:在成员函数声明末尾加 const,表示该函数不会修改对象的数据成员。
  • 只能调用其他 const 成员函数,不能修改非 mutable 成员。

9. 模板 (泛型)

  • 函数模板

    1
    2
    template <typename T>
    T max(T a, T b) { return a > b ? a : b; }
  • 类模板

    1
    2
    template <typename T>
    class Stack { ... };
  • 非类型模板形参template <typename T, size_t N> void func(T (&arr)[N]);

第四部分:标准库与构建

1. 输入输出 (IO)

  • 头文件<iostream><iomanip><fstream>
  • 标准流
    • cout:标准输出,配合 <<
    • cin:标准输入,配合 >>
    • cerr / clog:标准错误输出。
  • 格式控制:使用 <iomanip> 中的 setw(), setprecision() 等。

2. 文件操作

  • 头文件<fstream>

  • ifstream(读)、ofstream(写)、fstream(读写)。

  • 打开模式ios::inios::outios::appios::trunc 等。

  • 示例

    1
    2
    3
    ofstream file("test.txt");
    file << "Hello" << endl;
    file.close();

3. 常用容器 (STL)

容器 头文件 特点
vector <vector> 动态数组,快速随机访问。
list <list> 双向链表,快速插入/删除。
deque <deque> 双端队列。
stack <stack> 栈,LIFO。
queue <queue> 队列,FIFO。
map <map> 有序键值对。
unordered_map <unordered_map> 哈希表,无序键值对。

4. 智能指针 (C++11)

  • std::unique_ptr:独占所有权的智能指针。
  • std::shared_ptr:共享所有权的智能指针,通过引用计数管理。
  • std::weak_ptr:配合 shared_ptr 使用,解决循环引用问题。

5. 编译与构建

CMake 基础

  • 最小配置

    1
    2
    3
    cmake_minimum_required(VERSION 3.0)
    project(MyProject)
    add_executable(myapp main.cpp)
  • 常用命令

    • set(CMAKE_CXX_STANDARD 11):设置C++标准。
    • target_include_directories:指定头文件目录。
    • target_link_libraries:链接库。

编译器与链接库

  • 静态库 (.a/.lib):编译时被链接进可执行文件。
  • 动态库 (.so/.dll):运行时被加载,可多程序共享。
  • g++ 常用参数
    • -c:只编译,不链接。
    • -o:指定输出文件名。
    • -I:指定头文件搜索路径。
    • -L:指定库文件搜索路径。
    • -l:链接指定的库。
    • -fPIC:生成位置无关代码(用于动态库)。
    • -shared:生成动态链接库。

第五部分:现代C++特性 (C++11/14)

C++11 重要新特性

  1. 右值引用 (&&) 与移动语义

    • 延长临时对象的生命周期,实现资源转移,避免深拷贝。
    • std::move():将左值转换为右值引用。
  2. 统一初始化

    • 使用大括号 {} 进行初始化,适用于所有类型。
    1
    2
    vector<int> v{1, 2, 3};
    int arr[]{1, 2, 3};
  3. 自动类型推导

    • auto:编译器自动推导变量类型。
    • decltype:获取表达式或变量的类型。
  4. 基于范围的 for 循环

    1
    2
    3
    for (auto &elem : container) {
    // 遍历容器
    }
  5. 空指针 nullptr

    • 替代 NULL,避免与整数0混淆。
  6. 强类型枚举 enum class

    • 作用域限制,防止隐式转换。
  7. 静态断言 static_assert

    • 编译期断言,若条件为假则编译失败。
  8. overridefinal

    • override:显式表明重写基类虚函数。
    • final:阻止类被继承或虚函数被重写。
  9. Lambda 表达式

    • 创建匿名函数对象。
  10. =default=delete

    • =default:显式要求编译器生成默认的特殊成员函数。
    • =delete:禁止编译器生成特殊成员函数。

C++14 新特性

  1. 泛型Lambda

    • Lambda 参数可使用 auto,成为模板。
    1
    auto add = [](auto a, auto b) { return a + b; };
  2. 变量模板

    • 模板化的变量定义。