C++ 快速指南
C++ 快速指南:现代概览
Section titled “C++ 快速指南:现代概览”C++ 是一种功能强大的、静态类型、编译型、多范式编程语言。它支持面向过程、面向对象、泛型和函数式编程风格。它以其高性能而闻名,广泛应用于系统编程、游戏开发、高频交易、嵌入式系统和大型应用程序。
C++ 被视为一种中级语言,它既提供低级内存操作能力(如 C 语言),也提供高级抽象(如类和模板)。C++ 通过标准不断发展(C++11, C++14, C++17, C++20, C++23…),现代 C++ 强调安全性、表达性和性能。
C++ 编译器
Section titled “C++ 编译器”你需要一个 C++ 编译器来将你的源代码(通常在 .cpp 文件中)翻译成可执行程序。流行的现代编译器包括:
- GCC (GNU Compiler Collection): 免费、开源,广泛用于 Linux、macOS(通过 Xcode Command Line Tools 或包管理器)和 Windows(通过 MinGW 或 Cygwin)。
- Clang: 免费、开源编译器(LLVM 项目的一部分),以快速编译和出色的诊断闻名。可在主要平台上使用。
- MSVC (Microsoft Visual C++): Windows 上 Visual Studio 的一部分。提供免费的 Community 版本。
确保你的编译器支持最新的 C++ 标准(推荐 C++17 或更高版本以使用现代特性)。
基本程序结构
Section titled “基本程序结构”一个最小的 C++ 程序:
// 包含标准库功能所需的头文件#include <iostream> // 用于输入/输出流 (例如 std::cout)
// main() 是程序执行的入口点。// 它应该返回一个整数状态码 (通常 0 表示成功)。int main() { // std::cout 是标准输出流 (通常是控制台)。 // << 是流插入运算符。 // std::endl 插入换行符并刷新输出缓冲区。 std::cout << "Hello, Modern C++!" << std::endl;
return 0; // 表示成功执行}C++ 中的注释
Section titled “C++ 中的注释”注释会被编译器忽略,用于解释代码。
// 这是单行注释。它会延伸到行尾。
/* 这是多行注释。 它可以跨越多行。*/基本数据类型
Section titled “基本数据类型”C++ 有几种内置(原始)数据类型:
| 类型 | 关键字 | 典型用途 |
|---|---|---|
| 布尔型 | bool | 真/假值 (true, false) |
| 字符型 | char | 单个字符 (例如 ‘a’, ’$’)。也用于小整数。 |
| 整型 | int | 整数 (例如 10, -5, 0) |
| 浮点型 | float | 单精度小数 (例如 3.14f) |
| 双精度浮点型 | double | 双精度小数 (例如 3.14159) |
| 无值型 | void | 表示无类型 (用于函数返回类型、指针) |
| 宽字符型 | wchar_t | 用于更大字符集 (实现定义) 的字符 |
修饰符 (signed, unsigned, short, long, long long) 可以改变这些类型的范围和大小(参见 cpp_modifier_types.json)。
变量定义与初始化
Section titled “变量定义与初始化”变量定义指定其类型和名称,并分配内存。初始化赋予其初始值。
#include <string>#include <vector>
int main() { int score = 90; // C 风格初始化 double temperature(25.5); // 构造函数风格初始化 bool isActive{true}; // 统一初始化 (在现代 C++ 中更推荐) std::string playerName = "Alex"; // 使用字符串字面量初始化 std::vector<int> numbers{1, 2, 3}; // 容器的统一初始化
// 使用 'auto' 进行类型推导 (C++11) auto count = 10; // count 被推导为 int auto message = "Processing..."; // message 被推导为 const char* auto pi = 3.14; // pi 被推导为 double
return 0;}始终初始化你的变量,以避免使用不确定的值。
作用域定义了变量可以在何处被访问:
- 局部作用域 (Local Scope): 在函数或块 (
{}) 内声明的变量只能在该函数/块内访问。 - 全局作用域 (Global Scope): 在任何函数外部声明的变量具有全局作用域,可以在文件中的任何地方(在声明之后)访问。谨慎使用全局变量。
- 类作用域 (Class Scope): 类的成员可以在类方法内访问(以及可能在外部,取决于访问说明符)。
- 命名空间作用域 (Namespace Scope): 在命名空间内声明的变量。
常量和字面量
Section titled “常量和字面量”字面量是代码中固定的值(例如 10, 3.14f, 'a', "Hello")。常量是初始化后其值不能更改的变量。
const double PI = 3.14159; // 'const' 关键字用于运行时常量constexpr int MAX_USERS = 100; // 'constexpr' 用于编译时常量
// PI = 3.14; // 错误:无法赋值给 const 变量// MAX_USERS = 99; // 错误:无法赋值给 constexpr 变量使用 const 和 constexpr 可以提高代码安全性并启用优化。
存储类说明符决定变量的生命周期和链接属性:
auto(作为存储类已过时,关键字在 C++11 中重新用于类型推导)register(对编译器的提示,很大程度上被现代优化器忽略)static: 在函数/块内部,将其生命周期延长到整个程序持续时间。在全局/命名空间作用域,限制链接到当前翻译单元。extern: 声明在别处(通常在另一个文件)定义的变量,启用链接。thread_local(C++11): 指定变量具有线程局部存储期。mutable: 允许声明为mutable的类成员即使在const成员函数内或通过const对象也能被修改。
C++ 提供了丰富的运算符集合:
- 算术运算符 (Arithmetic):
+,-,*,/,%(取模),++(自增),--(自减) - 关系运算符 (Relational):
==(等于),!=(不等于),>,<,>=,<= - 逻辑运算符 (Logical):
&&(与),||(或),!(非) - 位运算符 (Bitwise):
&(按位与),|(按位或),^(按位异或),~(按位非),<<(左移),>>(右移) - 赋值运算符 (Assignment):
=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>= - 成员访问运算符 (Member Access):
.(对象成员),->(指针成员) - 其他运算符 (Other):
sizeof,&(取地址),*(解引用),?:(三元条件运算符),,(逗号),()(函数调用),[](数组下标),typeid, 转换运算符 (static_cast,dynamic_cast,const_cast,reinterpret_cast),new,delete,::(作用域解析)
控制流:循环
Section titled “控制流:循环”循环重复执行代码块:
| 循环类型 | 描述 |
|---|---|
while 循环 | 当条件为真时重复执行(在每次迭代之前检查)。 |
for 循环 | 执行指定次数(初始化、条件、更新)。 |
do...while 循环 | 当条件为真时重复执行(在每次迭代之后检查;循环体总是至少执行一次)。 |
基于范围的 for 循环 (Range-based for, C++11) | 迭代范围内的所有元素(例如,容器、数组)。简单的迭代场景首选。 |
#include <vector>#include <iostream>
int main() { std::vector<int> nums = {10, 20, 30}; // 基于范围的 for 循环 (现代 C++) for (int num : nums) { std::cout << num << " "; // 输出: 10 20 30 } std::cout << std::endl;
// 传统 for 循环 for (size_t i = 0; i < nums.size(); ++i) { std::cout << nums[i] << " "; // 输出: 10 20 30 } std::cout << std::endl; return 0;}控制流:条件判断
Section titled “控制流:条件判断”根据条件控制执行的语句:
| 语句 | 描述 |
|---|---|
if 语句 | 如果条件为真则执行代码。 |
if...else 语句 | 如果条件为真则执行一个代码块,否则执行另一个。 |
if...else if...else | 链式处理多个条件。 |
switch 语句 | 将变量与一系列常量值 (case) 进行比较测试。 |
三元运算符 (?:) | 简单 if-else 表达式的缩写形式。 |
函数将代码组织在一起以执行特定任务。
// 函数定义return_type function_name(parameter_list) { // 函数体 return value; // 可选,取决于 return_type}return_type: 函数返回值的类型(如果无返回值,则为void)。function_name: 函数的标识符。parameter_list: 用逗号分隔的输入参数列表(类型和名称)。function body: 函数被调用时执行的代码。
函数提高了代码复用性和模块化。
使用原始类型 (int, float, double) 表示数字。包含 <cmath> 以使用数学函数。
#include <cmath> // 用于数学函数#include <iostream>
int main() { double angle_degrees = 45.0; double angle_radians = angle_degrees * M_PI / 180.0; // M_PI 通常需要 _USE_MATH_DEFINES 或类似定义
std::cout << "Square root of 16: " << std::sqrt(16.0) << std::endl; // 输出: 4 std::cout << "2 raised to power 10: " << std::pow(2.0, 10.0) << std::endl; // 输出: 1024 std::cout << "Cosine of 45 degrees: " << std::cos(angle_radians) << std::endl; // 输出: ~0.7071 return 0;}对于高质量的随机数,请使用 <random> 头文件(参见 cpp_numbers.json)。
数组存储固定大小的元素序列。在现代 C++ 中,优先使用 std::vector 或 std::array,而非原始 C 风格数组。
#include <vector> // 用于 std::vector (动态大小)#include <array> // 用于 std::array (固定大小, 栈分配)#include <iostream>#include <numeric> // 用于 std::iota
int main() { // C 风格数组 (谨慎使用) int c_array[5]; c_array[0] = 10;
// std::array (固定大小, 使用 .at() 进行边界检查) std::array<int, 5> modern_array; std::iota(modern_array.begin(), modern_array.end(), 100); // 填充 100, 101, ... std::cout << "std::array element: " << modern_array.at(1) << std::endl; // 输出: 101
// std::vector (动态大小, 自行管理内存) std::vector<int> dynamic_vector; dynamic_vector.push_back(10); dynamic_vector.push_back(20); dynamic_vector.push_back(30); std::cout << "Vector size: " << dynamic_vector.size() << std::endl; // 输出: 3 std::cout << "Vector element: " << dynamic_vector[1] << std::endl; // 输出: 20
// 使用基于范围的 for 循环迭代 for (int val : dynamic_vector) { std::cout << val << " "; // 输出: 10 20 30 } std::cout << std::endl;
return 0;}使用 <string> 头文件中的 std::string 类进行文本操作。对于一般的字符串处理,避免使用 C 风格的字符数组 (char[])。
#include <string>#include <iostream>
int main() { std::string greeting = "Hello"; std::string name = "World"; std::string message;
// 字符串连接 message = greeting + ", " + name + "!"; std::cout << message << std::endl; // 输出: Hello, World!
// 长度/大小 std::cout << "Message length: " << message.length() << std::endl;
// 子串 std::cout << "Substring: " << message.substr(0, 5) << std::endl; // 输出: Hello
return 0;}类是对象的蓝图,封装了数据(成员)和行为(方法)。
#include <iostream>#include <string>
class Box {private: // 数据成员通常是私有的 (Encapsulation - 封装) double length = 1.0; double breadth = 1.0; double height = 1.0;
public: // 方法 (和构造函数) 通常是公有的 // 构造函数 (初始化对象) Box(double l, double b, double h) : length(l), breadth(b), height(h) { std::cout << "Box created with dimensions: " << l << ", " << b << ", " << h << std::endl; }
// 成员函数 (方法) double getVolume() const { // const 表示该方法不修改对象 return length * breadth * height; }
// 析构函数 (对象销毁时进行清理) ~Box() { std::cout << "Box destroyed." << std::endl; }};
int main() { // 创建 Box 类的一个对象 (实例) Box myBox(5.0, 6.0, 7.0);
// 使用点 (.) 运算符访问公有成员 std::cout << "Volume of myBox: " << myBox.getVolume() << std::endl;
return 0; // myBox 在此处超出作用域,调用析构函数 ~Box()}关键的面向对象编程 (OOP) 概念,如封装 (Encapsulation)、抽象 (Abstraction)、继承 (Inheritance) 和多态 (Polymorphism),是 C++ 的核心(参见 cpp_object_oriented.json)。
允许基于现有类(基类)创建新类(派生类),提高代码复用性并体现“is-a”关系。
class Shape { // 基类public: virtual double getArea() const = 0; // 纯虚函数 (使 Shape 成为抽象类) virtual ~Shape() = default; // 虚析构函数!};
class Rectangle : public Shape { // 派生类private: double width, height;public: Rectangle(double w, double h) : width(w), height(h) {} double getArea() const override { // 实现基类虚函数,使用 'override' return width * height; }};有关访问说明符、虚函数、override、final 和多重继承的详细信息,请参阅 cpp_inheritance.json。
允许多个不同派生类的对象通过共同的基类接口进行处理,通常使用指针或引用。
#include <iostream>#include <memory> // 用于 std::unique_ptr#include <vector>
// 使用来自继承示例的 Shape 和 Rectangle...
void printArea(const Shape& shape) { // 接收基类引用 std::cout << "Area: " << shape.getArea() << std::endl;}
int main() { Rectangle rect(10, 5); // Circle circ(7); // 假设有一个从 Shape 派生的 Circle 类
printArea(rect); // 调用 Rectangle::getArea() // printArea(circ); // 会调用 Circle::getArea()
// 使用基类指针 (首选智能指针) std::vector<std::unique_ptr<Shape>> shapes; shapes.push_back(std::make_unique<Rectangle>(4, 3)); // shapes.push_back(std::make_unique<Circle>(2));
for (const auto& shapePtr : shapes) { printArea(*shapePtr); // 通过虚派发调用适当的 getArea() }
return 0;}需要在基类中包含 virtual 函数。对于打算用于多态的基类,请始终包含 virtual 析构函数。
允许具有相同名称但不同参数的多个函数或运算符(编译时多态)。
void display(int i) { std::cout << "Int: " << i << std::endl; }void display(double d) { std::cout << "Double: " << d << std::endl; }void display(const std::string& s) { std::cout << "String: " << s << std::endl; }
display(10); // 调用 int 版本display(3.14); // 调用 double 版本display("Test"); // 调用 string 版本使用 <fstream> 进行文件 I/O(std::ifstream 用于输入,std::ofstream 用于输出)。
#include <fstream> // 用于文件流#include <iostream> // 用于控制台 I/O#include <string> // 用于 std::string#include <vector>
int main() { std::string filename = "mydata.txt";
// 写入文件 (使用 RAII 和 ofstream) { std::ofstream outfile(filename); // 在构造函数中打开文件 if (!outfile) { // 始终检查文件是否成功打开 std::cerr << "Error opening " << filename << " for writing." << std::endl; return 1; } outfile << "Line 1: Hello from C++\n"; outfile << "Line 2: Files are useful.\n"; } // outfile 超出作用域,文件自动关闭
// 从文件读取 { std::ifstream infile(filename); if (!infile) { std::cerr << "Error opening " << filename << " for reading." << std::endl; return 1; } std::string line; std::cout << "\nReading from file:" << std::endl; while (std::getline(infile, line)) { // 逐行读取 std::cout << line << std::endl; } } // infile 超出作用域,文件自动关闭
return 0;}始终检查文件流是否成功打开。RAII(直接使用流对象)确保即使发生错误也能关闭文件。
本快速指南提供了一个起点。C++ 是一门博大精深的语言;请查阅 cppreference.com 等资源和专门的教程以获取更多信息。