C++ 从入门到精通教程
本教程面向零基础学习者,从最基础的概念讲起,逐步深入到面向对象编程、模板、STL标准库、智能指针等高级主题,最终通过一个实战项目巩固所学知识。
目录
- C++ 简介与历史
- 开发环境搭建
- 第一个C++程序
- 基本语法
- 函数
- 数组与字符串
- 指针与引用
- 面向对象编程基础——类与对象
- 继承
- 多态
- 封装
- 模板编程
- STL标准模板库
- 智能指针
- 异常处理
- 文件操作
- 实战项目:图书管理系统
- 学习建议与进阶路线
1. C++ 简介与历史
什么是C++?
C++ 是一门通用的、编译型的编程语言,由 Bjarne Stroustup 于1979年在贝尔实验室开始开发。它最初被称为 "C with Classes"(带类的C),在C语言的基础上增加了面向对象的特性。
C++ 的发展历史
| 年份 | 里程碑 |
|---|---|
| 1979 | Bjarne Stroustrup 开始开发 "C with Classes" |
| 1983 | 正式命名为 C++ |
| 1985 | 发布第一个商业版本,出版《The C++ Programming Language》 |
| 1998 | C++98 标准发布(ISO/IEC 14882:1998) |
| 2003 | C++03 标准(修复版) |
| 2011 | C++11 —— 重大更新,引入自动类型推导、智能指针、Lambda、右值引用等 |
| 2014 | C14 —— C11 的小幅改进 |
| 2017 | C++17 —— 引入 std::optional、结构化绑定、文件系统库等 |
| 2020 | C++20 —— 引入概念(Concepts)、协程、范围(Ranges)、模块(Modules) |
| 2023 | C++23 —— 进一步完善标准库 |
为什么学 C++?
- 性能极高:接近硬件层的控制能力,广泛用于游戏引擎、操作系统、嵌入式系统
- 应用广泛:操作系统(Windows/Linux内核部分)、游戏(Unreal Engine)、数据库(MySQL)、浏览器(Chrome)等
- 理解底层:学习C++能帮助你深入理解计算机是如何工作的
- 就业面广:系统开发、游戏开发、金融量化、嵌入式等领域都需要C++
2. 开发环境搭建
方式一:本地安装(推荐)
Windows
- 安装编译器:下载并安装 MinGW-w64 或直接安装 Visual Studio(社区版免费)
- 安装编辑器:推荐 Visual Studio Code + C/C++ 扩展
- 验证安装:打开命令行,输入
g++ --version
macOS
# 安装 Xcode Command Line Tools(自带 clang 编译器)
xcode-select --install
Linux (Ubuntu/Debian)
sudo apt update
sudo apt install g++ build-essential
方式二:在线编译器
如果不想本地安装,可以使用在线编译器快速体验:
编译与运行
# 编译
g++ -o hello hello.cpp
# 运行
./hello
3. 第一个C++程序
#include <iostream> // 引入输入输出流库
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
逐行解析:
#include <iostream>:预处理指令,告诉编译器引入 iostream 库(提供输入输出功能)int main():程序的入口函数,每个C++程序必须有且只有一个 main 函数std::cout:标准输出流对象,<<是输出运算符std::endl:换行并刷新缓冲区return 0:向操作系统返回 0,表示程序正常结束
简化写法(使用命名空间):
#include <iostream>
using namespace std; // 引入 std 命名空间
int main() {
cout << "Hello, World!" << endl;
return 0;
}
建议:初学时可以用
using namespace std;,但在实际项目中建议使用std::前缀,避免命名冲突。
4. 基本语法
4.1 变量与数据类型
变量是用来存储数据的容器。C++ 是静态类型语言,每个变量在使用前必须声明类型。
#include <iostream>
using namespace std;
int main() {
// 整数类型
int age = 25; // 通常 4 字节,范围约 ±21亿
long long bigNum = 10000000000LL; // 8 字节
short smallNum = 100; // 2 字节
// 浮点类型
float price = 9.99f; // 4 字节,约 6-7 位有效数字
double pi = 3.14159265358979; // 8 字节,约 15-16 位有效数字
// 字符类型
char grade = 'A'; // 1 字节
char newline = '\n'; // 转义字符:换行
// 布尔类型
bool isStudent = true; // 1 字节,true 或 false
// 字符串类型(C++ 标准库提供)
string name = "张三"; // 需要 #include <string>
// 输出
cout << "姓名: " << name << endl;
cout << "年龄: " << age << endl;
cout << "成绩: " << grade << endl;
cout << "是否学生: " << isStudent << endl;
return 0;
}
4.2 常量
const double PI = 3.14159265358979; // const 修饰,不可修改
constexpr int MAX_SIZE = 100; // 编译期常量(C++11)
4.3 运算符
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 3;
// 算术运算符
cout << "a + b = " << a + b << endl; // 13
cout << "a - b = " << a - b << endl; // 7
cout << "a * b = " << a * b << endl; // 30
cout << "a / b = " << a / b << endl; // 3(整数除法,截断小数)
cout << "a % b = " << a % b << endl; // 1(取余)
// 比较运算符(返回 bool)
cout << "a > b: " << (a > b) << endl; // 1 (true)
cout << "a == b: " << (a == b) << endl; // 0 (false)
// 逻辑运算符
bool x = true, y = false;
cout << "x && y: " << (x && y) << endl; // 0(与)
cout << "x || y: " << (x || y) << endl; // 1(或)
cout << "!x: " << (!x) << endl; // 0(非)
// 自增自减
int c = 5;
cout << "c++ = " << c++ << endl; // 先使用再自增,输出 5,之后 c=6
cout << "++c = " << ++c << endl; // 先自增再使用,c=7,输出 7
return 0;
}
4.4 条件语句
#include <iostream>
using namespace std;
int main() {
int score;
cout << "请输入成绩: ";
cin >> score;
// if-else if-else
if (score >= 90) {
cout << "优秀" << endl;
} else if (score >= 80) {
cout << "良好" << endl;
} else if (score >= 60) {
cout << "及格" << endl;
} else {
cout << "不及格" << endl;
}
// switch 语句
int day = 3;
switch (day) {
case 1: cout << "周一" << endl; break;
case 2: cout << "周二" << endl; break;
case 3: cout << "周三" << endl; break;
case 4: cout << "周四" << endl; break;
case 5: cout << "周五" << endl; break;
default: cout << "周末" << endl; break;
}
// 三元运算符
int a = 10, b = 20;
int maxVal = (a > b) ? a : b;
cout << "较大值: " << maxVal << endl;
return 0;
}
4.5 循环语句
#include <iostream>
using namespace std;
int main() {
// for 循环
cout << "=== for 循环 ===" << endl;
for (int i = 1; i <= 5; i++) {
cout << "第 " << i << " 次" << endl;
}
// while 循环
cout << "=== while 循环 ===" << endl;
int count = 0;
while (count < 3) {
cout << "count = " << count << endl;
count++;
}
// do-while 循环(至少执行一次)
cout << "=== do-while 循环 ===" << endl;
int num = 10;
do {
cout << "num = " << num << endl;
num--;
} while (num > 7);
// 范围 for 循环(C++11)
cout << "=== 范围 for ===" << endl;
int arr[] = {10, 20, 30, 40, 50};
for (int val : arr) {
cout << val << " ";
}
cout << endl;
// break 与 continue
cout << "=== break 示例 ===" << endl;
for (int i = 0; i < 10; i++) {
if (i == 5) break; // 遇到 5 就跳出循环
cout << i << " ";
}
cout << endl;
cout << "=== continue 示例 ===" << endl;
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) continue; // 跳过偶数
cout << i << " ";
}
cout << endl;
return 0;
}
4.6 输入输出
#include <iostream>
#include <string>
using namespace std;
int main() {
// 基本输入
int age;
cout << "请输入你的年龄: ";
cin >> age;
cout << "你 " << age << " 岁了" << endl;
// 字符串输入
string name;
cout << "请输入你的名字: ";
cin >> name; // 只能读取一个单词
cout << "你好, " << name << "!" << endl;
// 读取整行
string sentence;
cout << "请输入一句话: ";
cin.ignore(); // 清除之前的换行符
getline(cin, sentence);
cout << "你说的是: " << sentence << endl;
// 格式化输出
double value = 3.14159;
cout << "默认: " << value << endl;
cout.precision(2);
cout << "保留2位: " << fixed << value << endl;
return 0;
}
5. 函数
函数是组织代码的基本单元,它将一段可复用的逻辑封装起来。
5.1 函数基础
#include <iostream>
using namespace std;
// 函数声明(原型)
int add(int a, int b);
void greet(string name);
double calculateArea(double radius);
int main() {
int result = add(3, 5);
cout << "3 + 5 = " << result << endl;
greet("小明");
cout << "半径为5的圆面积: " << calculateArea(5.0) << endl;
return 0;
}
// 函数定义
int add(int a, int b) {
return a + b;
}
void greet(string name) {
cout << "你好, " << name << "!" << endl;
}
double calculateArea(double radius) {
const double PI = 3.14159265358979;
return PI * radius * radius;
}
5.2 函数重载
C++ 允许同名函数有不同的参数列表(参数类型或数量不同):
#include <iostream>
using namespace std;
// 重载的 print 函数
void print(int x) {
cout << "整数: " << x << endl;
}
void print(double x) {
cout << "浮点数: " << x << endl;
}
void print(string x) {
cout << "字符串: " << x << endl;
}
int main() {
print(42);
print(3.14);
print("Hello");
return 0;
}
5.3 默认参数与内联函数
#include <iostream>
using namespace std;
// 默认参数(从右往左设置)
void printInfo(string name, int age = 18, string city = "北京") {
cout << name << ", " << age << "岁, " << city << endl;
}
// 内联函数(建议编译器将函数体展开,减少调用开销)
inline int square(int x) {
return x * x;
}
int main() {
printInfo("张三"); // 张三, 18岁, 北京
printInfo("李四", 25); // 李四, 25岁, 北京
printInfo("王五", 30, "上海"); // 王五, 30岁, 上海
cout << "5 的平方: " << square(5) << endl;
return 0;
}
5.4 Lambda 表达式(C++11)
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
// 基本 lambda
auto add = [](int a, int b) -> int {
return a + b;
};
cout << "3 + 4 = " << add(3, 4) << endl;
// 带捕获的 lambda
int factor = 10;
auto multiply = [factor](int x) { return x * factor; };
cout << "5 * 10 = " << multiply(5) << endl;
// 在算法中使用 lambda
vector<int> nums = {5, 2, 8, 1, 9, 3};
sort(nums.begin(), nums.end(), [](int a, int b) {
return a > b; // 降序排序
});
for (int n : nums) cout << n << " ";
cout << endl; // 输出: 9 8 5 3 2 1
return 0;
}
6. 数组与字符串
6.1 数组
#include <iostream>
using namespace std;
int main() {
// 声明并初始化数组
int scores[5] = {90, 85, 78, 92, 88};
// 访问和修改
cout << "第一个成绩: " << scores[0] << endl;
scores[2] = 80; // 修改第三个元素
// 遍历数组
cout << "所有成绩: ";
for (int i = 0; i < 5; i++) {
cout << scores[i] << " ";
}
cout << endl;
// 计算平均值
double sum = 0;
for (int score : scores) {
sum += score;
}
cout << "平均分: " << sum / 5 << endl;
// 二维数组
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
cout << "矩阵:" << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}
return 0;
}
6.2 字符串
#include <iostream>
#include <string>
using namespace std;
int main() {
// C++ string 类(推荐使用)
string s1 = "Hello";
string s2 = "World";
// 拼接
string s3 = s1 + " " + s2;
cout << s3 << endl; // Hello World
// 长度
cout << "长度: " << s3.length() << endl;
// 访问单个字符
cout << "第一个字符: " << s3[0] << endl;
// 查找
size_t pos = s3.find("World");
if (pos != string::npos) {
cout << "找到 'World' 在位置: " << pos << endl;
}
// 子串
string sub = s3.substr(0, 5);
cout << "子串: " << sub << endl; // Hello
// 比较
if (s1 == "Hello") {
cout << "字符串相等" << endl;
}
// 遍历字符串
for (char c : s3) {
cout << c << " ";
}
cout << endl;
return 0;
}
7. 指针与引用
指针是 C++ 最强大也最容易出错的特性之一。理解指针是深入学习 C++ 的关键。
7.1 指针基础
#include <iostream>
using namespace std;
int main() {
int num = 42;
int* ptr = # // ptr 存储 num 的内存地址
cout << "num 的值: " << num << endl; // 42
cout << "num 的地址: " << &num << endl; // 0x7fff...
cout << "ptr 的值: " << ptr << endl; // 同上,存储的是地址
cout << "ptr 指向的值: " << *ptr << endl; // 42(解引用)
// 通过指针修改值
*ptr = 100;
cout << "修改后 num = " << num << endl; // 100
// 空指针
int* nullPtr = nullptr; // C++11 推荐用 nullptr 代替 NULL
if (nullPtr == nullptr) {
cout << "这是一个空指针" << endl;
}
return 0;
}
7.2 动态内存分配
#include <iostream>
using namespace std;
int main() {
// 动态分配单个变量
int* p = new int(42);
cout << *p << endl; // 42
delete p; // 释放内存
p = nullptr;
// 动态分配数组
int n = 5;
int* arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = i * 10;
}
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
delete[] arr; // 释放数组内存
arr = nullptr;
return 0;
}
7.3 引用
引用是变量的别名,必须在声明时初始化,且不能重新绑定:
#include <iostream>
using namespace std;
// 引用作为函数参数(传递引用,避免拷贝)
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
// 引用作为返回值(避免拷贝大型对象)
int& getElement(int arr[], int index) {
return arr[index];
}
int main() {
int x = 10, y = 20;
cout << "交换前: x=" << x << ", y=" << y << endl;
swap(x, y);
cout << "交换后: x=" << x << ", y=" << y << endl;
// 引用即别名
int num = 42;
int& ref = num; // ref 是 num 的别名
ref = 100;
cout << "num = " << num << endl; // 100
return 0;
}
8. 面向对象编程基础——类与对象
面向对象编程(OOP)是 C++ 的核心特性之一。类是对象的蓝图,对象是类的实例。
8.1 定义类
#include <iostream>
#include <string>
using namespace std;
class Student {
private: // 私有成员,外部不可直接访问
string name;
int age;
double score;
public: // 公有成员,外部可以访问
// 构造函数(创建对象时自动调用)
Student(string n, int a, double s) : name(n), age(a), score(s) {}
// 默认构造函数
Student() : name("未知"), age(0), score(0.0) {}
// 析构函数(对象销毁时自动调用)
~Student() {
// 在这里释放资源(如果有动态内存分配)
}
// 成员函数(方法)
void display() const {
cout << "姓名: " << name
<< ", 年龄: " << age
<< ", 成绩: " << score << endl;
}
// Getter 方法
string getName() const { return name; }
int getAge() const { return age; }
double getScore() const { return score; }
// Setter 方法
void setName(const string& n) { name = n; }
void setAge(int a) { age = a; }
void setScore(double s) { score = s; }
// 判断是否及格
bool isPassed() const {
return score >= 60;
}
};
int main() {
// 创建对象
Student stu1("张三", 20, 85.5);
stu1.display();
Student stu2; // 使用默认构造函数
stu2.setName("李四");
stu2.setAge(21);
stu2.setScore(55);
stu2.display();
cout << stu1.getName() << " 是否及格: "
<< (stu1.isPassed() ? "是" : "否") << endl;
cout << stu2.getName() << " 是否及格: "
<< (stu2.isPassed() ? "是" : "否") << endl;
return 0;
}
8.2 构造函数详解
#include <iostream>
using namespace std;
class Rectangle {
private:
double width;
double height;
public:
// 1. 默认构造函数
Rectangle() : width(0), height(0) {
cout << "默认构造函数被调用" << endl;
}
// 2. 参数化构造函数
Rectangle(double w, double h) : width(w), height(h) {
cout << "参数化构造函数被调用" << endl;
}
// 3. 拷贝构造函数
Rectangle(const Rectangle& other)
: width(other.width), height(other.height) {
cout << "拷贝构造函数被调用" << endl;
}
double area() const { return width * height; }
double perimeter() const { return 2 * (width + height); }
void display() const {
cout << "矩形: " << width << " x " << height
<< ", 面积=" << area()
<< ", 周长=" << perimeter() << endl;
}
};
int main() {
Rectangle r1; // 默认构造
Rectangle r2(3.0, 4.0); // 参数化构造
Rectangle r3 = r2; // 拷贝构造
r1.display();
r2.display();
r3.display();
return 0;
}
8.3 this 指针与运算符重载
#include <iostream>
using namespace std;
class Vector2D {
private:
double x, y;
public:
Vector2D(double x = 0, double y = 0) : x(x), y(y) {}
// 运算符重载:向量加法
Vector2D operator+(const Vector2D& other) const {
return Vector2D(x + other.x, y + other.y);
}
// 运算符重载:向量减法
Vector2D operator-(const Vector2D& other) const {
return Vector2D(x - other.x, y - other.y);
}
// 运算符重载:标量乘法
Vector2D operator*(double scalar) const {
return Vector2D(x * scalar, y * scalar);
}
// 运算符重载:输出流
friend ostream& operator<<(ostream& os, const Vector2D& v) {
os << "(" << v.x << ", " << v.y << ")";
return os;
}
// 运算符重载:比较
bool operator==(const Vector2D& other) const {
return x == other.x && y == other.y;
}
// 计算长度
double magnitude() const {
return sqrt(x * x + y * y);
}
};
int main() {
Vector2D v1(3, 4);
Vector2D v2(1, 2);
cout << "v1 = " << v1 << endl;
cout << "v2 = " << v2 << endl;
cout << "v1 + v2 = " << v1 + v2 << endl;
cout << "v1 - v2 = " << v1 - v2 << endl;
cout << "v1 * 2 = " << v1 * 2 << endl;
cout << "|v1| = " << v1.magnitude() << endl;
return 0;
}
9. 继承
继承允许我们基于已有的类创建新类,实现代码复用。
9.1 基本继承
#include <iostream>
#include <string>
using namespace std;
// 基类
class Shape {
protected: // protected 成员可以被子类访问
string color;
public:
Shape(string c) : color(c) {}
virtual ~Shape() {} // 虚析构函数(重要!)
string getColor() const { return color; }
// 虚函数,子类可以重写
virtual double area() const = 0; // 纯虚函数,使 Shape 成为抽象类
virtual void display() const {
cout << "颜色: " << color;
}
};
// 派生类:圆形
class Circle : public Shape {
private:
double radius;
public:
Circle(double r, string c) : Shape(c), radius(r) {}
double area() const override {
return 3.14159265358979 * radius * radius;
}
void display() const override {
Shape::display();
cout << ", 圆形, 半径=" << radius
<< ", 面积=" << area() << endl;
}
};
// 派生类:矩形
class Rectangle : public Shape {
private:
double width, height;
public:
Rectangle(double w, double h, string c) : Shape(c), width(w), height(h) {}
double area() const override {
return width * height;
}
void display() const override {
Shape::display();
cout << ", 矩形, " << width << "x" << height
<< ", 面积=" << area() << endl;
}
};
int main() {
Circle c(5.0, "红色");
Rectangle r(4.0, 6.0, "蓝色");
c.display();
r.display();
// 多态使用
Shape* shapes[] = {&c, &r};
for (const Shape* s : shapes) {
cout << "面积: " << s->area() << endl;
}
return 0;
}
9.2 继承方式
class Base {
public:
int pub;
protected:
int prot;
private:
int priv;
};
// public 继承:保持原有访问权限
class PublicDerived : public Base {
// pub → public, prot → protected, priv → 不可访问
};
// protected 继承:public 和 protected 都变为 protected
class ProtectedDerived : protected Base {
// pub → protected, prot → protected, priv → 不可访问
};
// private 继承:全部变为 private(默认继承方式)
class PrivateDerived : private Base {
// pub → private, prot → private, priv → 不可访问
};
9.3 多重继承
#include <iostream>
using namespace std;
class Flyable {
public:
virtual void fly() { cout << "飞行中..." << endl; }
};
class Swimmable {
public:
virtual void swim() { cout << "游泳中..." << endl; }
};
// 多重继承
class Duck : public Flyable, public Swimmable {
public:
void fly() override { cout << "鸭子在飞!" << endl; }
void swim() override { cout << "鸭子在游泳!" << endl; }
};
int main() {
Duck duck;
duck.fly();
duck.swim();
return 0;
}
10. 多态
多态是 OOP 的核心概念之一,允许用统一的接口处理不同类型的对象。
10.1 虚函数与运行时多态
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Animal {
public:
virtual void speak() const = 0;
virtual string type() const = 0;
virtual ~Animal() {}
};
class Dog : public Animal {
public:
void speak() const override { cout << "汪汪!" << endl; }
string type() const override { return "狗"; }
};
class Cat : public Animal {
public:
void speak() const override { cout << "喵喵!" << endl; }
string type() const override { return "猫"; }
};
class Bird : public Animal {
public:
void speak() const override { cout << "叽叽!" << endl; }
string type() const override { return "鸟"; }
};
void makeSound(const Animal& animal) {
cout << animal.type() << " 说: ";
animal.speak();
}
int main() {
Dog dog;
Cat cat;
Bird bird;
makeSound(dog); // 狗 说: 汪汪!
makeSound(cat); // 猫 说: 喵喵!
makeSound(bird); // 鸟 说: 叽叽!
// 使用容器存储不同类型的对象
vector<unique_ptr<Animal>> zoo;
zoo.push_back(make_unique<Dog>());
zoo.push_back(make_unique<Cat>());
zoo.push_back(make_unique<Bird>());
cout << "\n--- 动物园 ---" << endl;
for (const auto& animal : zoo) {
makeSound(*animal);
}
return 0;
}
10.2 抽象类与接口
#include <iostream>
using namespace std;
// 接口类(纯虚函数)
class Printable {
public:
virtual void print() const = 0;
virtual ~Printable() {}
};
class Serializable {
public:
virtual string serialize() const = 0;
virtual ~Serializable() {}
};
// 实现多个接口
class Document : public Printable, public Serializable {
private:
string title;
string content;
public:
Document(string t, string c) : title(t), content(c) {}
void print() const override {
cout << "=== " << title << " ===" << endl;
cout << content << endl;
}
string serialize() const override {
return "{\"title\":\"" + title + "\",\"content\":\"" + content + "\"}";
}
};
int main() {
Document doc("报告", "这是一份重要的报告。");
doc.print();
cout << "序列化: " << doc.serialize() << endl;
return 0;
}
11. 封装
封装是将数据和操作数据的方法绑定在一起,并隐藏内部实现细节。
11.1 访问控制
#include <iostream>
using namespace std;
class BankAccount {
private: // 只有类内部可以访问
string owner;
double balance;
static int totalAccounts; // 静态成员,所有对象共享
public: // 外部可以访问
// 构造函数
BankAccount(string name, double initial)
: owner(name), balance(initial) {
totalAccounts++;
}
// 析构函数
~BankAccount() {
totalAccounts--;
}
// 公共接口
void deposit(double amount) {
if (amount > 0) {
balance += amount;
cout << "存入 " << amount << " 元,余额: " << balance << " 元" << endl;
} else {
cout << "存款金额必须大于0" << endl;
}
}
bool withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
cout << "取出 " << amount << " 元,余额: " << balance << " 元" << endl;
return true;
}
cout << "取款失败!余额不足或金额无效" << endl;
return false;
}
double getBalance() const { return balance; }
string getOwner() const { return owner; }
static int getTotalAccounts() { return totalAccounts; }
};
// 静态成员初始化
int BankAccount::totalAccounts = 0;
int main() {
BankAccount acc1("张三", 1000);
BankAccount acc2("李四", 500);
acc1.deposit(500);
acc1.withdraw(200);
acc1.withdraw(2000); // 余额不足
cout << "\n当前账户总数: " << BankAccount::getTotalAccounts() << endl;
return 0;
}
12. 模板编程
模板是 C++ 泛型编程的基础,允许编写与类型无关的代码。
12.1 函数模板
#include <iostream>
#include <string>
using namespace std;
// 函数模板
template <typename T>
T maxValue(T a, T b) {
return (a > b) ? a : b;
}
// 多类型参数的模板
template <typename T, typename U>
void printPair(T first, U second) {
cout << "(" << first << ", " << second << ")" << endl;
}
// 模板特化
template <>
string maxValue(string a, string b) {
return (a.length() > b.length()) ? a : b;
}
int main() {
cout << maxValue(10, 20) << endl; // 20
cout << maxValue(3.14, 2.71) << endl; // 3.14
cout << maxValue(string("Hello"), string("Hi")) << endl; // Hello(长度比较)
printPair("年龄", 25);
printPair(3.14, "是圆周率");
return 0;
}
12.2 类模板
#include <iostream>
#include <stdexcept>
using namespace std;
template <typename T>
class Stack {
private:
static const int MAX_SIZE = 100;
T data[MAX_SIZE];
int top;
public:
Stack() : top(-1) {}
void push(const T& item) {
if (top >= MAX_SIZE - 1) {
throw overflow_error("栈溢出");
}
data[++top] = item;
}
T pop() {
if (isEmpty()) {
throw underflow_error("栈为空");
}
return data[top--];
}
T peek() const {
if (isEmpty()) {
throw underflow_error("栈为空");
}
return data[top];
}
bool isEmpty() const { return top == -1; }
int size() const { return top + 1; }
};
int main() {
// 整数栈
Stack<int> intStack;
intStack.push(10);
intStack.push(20);
intStack.push(30);
cout << "栈顶: " << intStack.peek() << endl; // 30
cout << "弹出: " << intStack.pop() << endl; // 30
cout << "弹出: " << intStack.pop() << endl; // 20
// 字符串栈
Stack<string> strStack;
strStack.push("Hello");
strStack.push("World");
cout << "弹出: " << strStack.pop() << endl; // World
return 0;
}
13. 标准模板库(STL)
STL 是 C++ 标准库的核心组成部分,提供了丰富的容器、算法和迭代器。
13.1 顺序容器
vector(动态数组)
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 创建与初始化
vector<int> v1; // 空 vector
vector<int> v2(5, 10); // 5 个元素,每个都是 10
vector<int> v3 = {1, 2, 3, 4, 5}; // 初始化列表
// 添加元素
v1.push_back(100);
v1.push_back(200);
v1.push_back(300);
// 访问元素
cout << "v1[0] = " << v1[0] << endl;
cout << "v1.at(1) = " << v1.at(1) << endl; // at() 会做边界检查
cout << "v1.front() = " << v1.front() << endl;
cout << "v1.back() = " << v1.back() << endl;
// 容量相关
cout << "大小: " << v1.size() << endl;
cout << "容量: " << v1.capacity() << endl;
// 遍历
cout << "遍历 v3: ";
for (int x : v3) cout << x << " ";
cout << endl;
// 使用迭代器遍历
cout << "迭代器遍历 v1: ";
for (auto it = v1.begin(); it != v1.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// 插入和删除
v3.insert(v3.begin() + 2, 99); // 在索引2处插入99
v3.erase(v3.begin()); // 删除第一个元素
cout << "修改后的 v3: ";
for (int x : v3) cout << x << " ";
cout << endl;
return 0;
}
list(双向链表)
#include <iostream>
#include <list>
using namespace std;
int main() {
list<int> lst = {3, 1, 4, 1, 5, 9};
// 添加元素
lst.push_front(0); // 头部添加
lst.push_back(10); // 尾部添加
// 排序
lst.sort();
cout << "排序后: ";
for (int x : lst) cout << x << " ";
cout << endl;
// 去重(需要先排序)
lst.unique();
cout << "去重后: ";
for (int x : lst) cout << x << " ";
cout << endl;
// 反转
lst.reverse();
cout << "反转后: ";
for (int x : lst) cout << x << " ";
cout << endl;
return 0;
}
deque(双端队列)
#include <iostream>
#include <deque>
using namespace std;
int main() {
deque<int> dq = {2, 3, 4};
dq.push_front(1); // 头部插入
dq.push_back(5); // 尾部插入
cout << "deque: ";
for (int x : dq) cout << x << " ";
cout << endl;
dq.pop_front();
dq.pop_back();
cout << "弹出首尾后: ";
for (int x : dq) cout << x << " ";
cout << endl;
return 0;
}
13.2 关联容器
map(键值对映射)
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> scores;
// 插入元素
scores["张三"] = 85;
scores["李四"] = 92;
scores["王五"] = 78;
scores.insert({"赵六", 88});
// 访问元素
cout << "张三的成绩: " << scores["张三"] << endl;
// 遍历
cout << "所有成绩:" << endl;
for (const auto& pair : scores) {
cout << " " << pair.first << ": " << pair.second << endl;
}
// 查找
auto it = scores.find("李四");
if (it != scores.end()) {
cout << "找到李四: " << it->second << endl;
}
// 统计大小
cout << "总人数: " << scores.size() << endl;
// 删除
scores.erase("王五");
// 检查是否存在
if (scores.count("王五") == 0) {
cout << "王五已被删除" << endl;
}
return 0;
}
set(集合)
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s = {5, 3, 8, 1, 3, 5}; // 自动去重和排序
s.insert(10);
s.insert(2);
cout << "set 元素(自动排序): ";
for (int x : s) cout << x << " ";
cout << endl;
// 查找
if (s.find(5) != s.end()) {
cout << "找到 5" << endl;
}
cout << "集合大小: " << s.size() << endl;
return 0;
}
13.3 常用算法
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
int main() {
vector<int> nums = {5, 2, 8, 1, 9, 3, 7, 4, 6};
// 排序
sort(nums.begin(), nums.end());
cout << "升序: ";
for (int x : nums) cout << x << " ";
cout << endl;
sort(nums.begin(), nums.end(), greater<int>());
cout << "降序: ";
for (int x : nums) cout << x << " ";
cout << endl;
// 查找
auto it = find(nums.begin(), nums.end(), 8);
if (it != nums.end()) {
cout << "找到 8,位置: " << distance(nums.begin(), it) << endl;
}
// 二分查找(需要已排序)
sort(nums.begin(), nums.end());
bool found = binary_search(nums.begin(), nums.end(), 5);
cout << "二分查找 5: " << (found ? "找到" : "未找到") << endl;
// 计数
int cnt = count_if(nums.begin(), nums.end(), [](int x) { return x > 5; });
cout << "大于5的元素个数: " << cnt << endl;
// 累加
int sum = accumulate(nums.begin(), nums.end(), 0);
cout << "总和: " << sum << endl;
// 最大最小值
auto [minIt, maxIt] = minmax_element(nums.begin(), nums.end());
cout << "最小值: " << *minIt << ", 最大值: " << *maxIt << endl;
// 反转
reverse(nums.begin(), nums.end());
cout << "反转后: ";
for (int x : nums) cout << x << " ";
cout << endl;
// 去重(需要先排序)
sort(nums.begin(), nums.end());
auto last = unique(nums.begin(), nums.end());
nums.erase(last, nums.end());
cout << "去重后: ";
for (int x : nums) cout << x << " ";
cout << endl;
return 0;
}
13.4 迭代器
#include <iostream>
#include <vector>
#include <list>
using namespace std;
int main() {
vector<int> vec = {10, 20, 30, 40, 50};
// 正向迭代器
cout << "正向遍历: ";
for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// auto 简化
cout << "反向遍历: ";
for (auto it = vec.rbegin(); it != vec.rend(); ++it) {
cout << *it << " ";
}
cout << endl;
// const 迭代器(只读)
cout << "只读遍历: ";
for (auto it = vec.cbegin(); it != vec.cend(); ++it) {
cout << *it << " ";
// *it = 100; // 错误!const 迭代器不能修改
}
cout << endl;
// 迭代器算术
auto it = vec.begin();
advance(it, 2); // 前进2步
cout << "第3个元素: " << *it << endl;
return 0;
}
14. 智能指针
C++11 引入的智能指针自动管理动态内存,避免内存泄漏。
14.1 unique_ptr(独占所有权)
#include <iostream>
#include <memory>
using namespace std;
class Resource {
string name;
public:
Resource(string n) : name(n) {
cout << "Resource " << name << " 已创建" << endl;
}
~Resource() {
cout << "Resource " << name << " 已销毁" << endl;
}
void use() { cout << "使用 Resource " << name << endl; }
};
int main() {
// 创建 unique_ptr
unique_ptr<Resource> ptr1 = make_unique<Resource>("A");
ptr1->use();
// 不能拷贝,只能移动
// unique_ptr<Resource> ptr2 = ptr1; // 编译错误!
unique_ptr<Resource> ptr2 = move(ptr1); // 移动所有权
if (!ptr1) {
cout << "ptr1 已为空" << endl;
}
ptr2->use();
// 离开作用域时自动释放内存
return 0;
}
14.2 shared_ptr(共享所有权)
#include <iostream>
#include <memory>
using namespace std;
int main() {
shared_ptr<int> sp1 = make_shared<int>(42);
cout << "值: " << *sp1 << endl;
cout << "引用计数: " << sp1.use_count() << endl; // 1
{
shared_ptr<int> sp2 = sp1; // 共享所有权
cout << "引用计数: " << sp1.use_count() << endl; // 2
shared_ptr<int> sp3 = sp1;
cout << "引用计数: " << sp1.use_count() << endl; // 3
} // sp2 和 sp3 离开作用域
cout << "引用计数: " << sp1.use_count() << endl; // 1
return 0;
}
14.3 weak_ptr(弱引用,解决循环引用)
#include <iostream>
#include <memory>
using namespace std;
class B; // 前向声明
class A {
public:
shared_ptr<B> bPtr;
~A() { cout << "A 被销毁" << endl; }
};
class B {
public:
weak_ptr<A> aPtr; // 使用 weak_ptr 避免循环引用
~B() { cout << "B 被销毁" << endl; }
};
int main() {
{
auto a = make_shared<A>();
auto b = make_shared<B>();
a->bPtr = b;
b->aPtr = a;
cout << "A 引用计数: " << a.use_count() << endl;
cout << "B 引用计数: " << b.use_count() << endl;
} // 离开作用域,A 和 B 都能正常销毁
cout << "作用域结束" << endl;
return 0;
}
使用建议:
- 优先使用
unique_ptr(独占所有权,零开销)- 需要共享时使用
shared_ptr- 打破循环引用时使用
weak_ptr- 永远不要对同一个原始指针创建多个智能指针
15. 异常处理
异常处理机制让程序在遇到错误时能够优雅地处理,而不是直接崩溃。
15.1 基本异常处理
#include <iostream>
#include <stdexcept>
using namespace std;
double divide(double a, double b) {
if (b == 0) {
throw invalid_argument("除数不能为零!");
}
return a / b;
}
int main() {
try {
cout << "10 / 3 = " << divide(10, 3) << endl;
cout << "10 / 0 = " << divide(10, 0) << endl; // 这里会抛出异常
cout << "这行不会执行" << endl;
}
catch (const invalid_argument& e) {
cerr << "参数错误: " << e.what() << endl;
}
catch (const exception& e) {
cerr << "标准异常: " << e.what() << endl;
}
catch (...) {
cerr << "未知异常" << endl;
}
cout << "程序继续执行" << endl;
return 0;
}
15.2 自定义异常
#include <iostream>
#include <exception>
#include <string>
using namespace std;
class InsufficientFundsException : public exception {
private:
string message;
public:
InsufficientFundsException(double balance, double amount)
: message("余额不足!余额: " + to_string(balance)
+ ", 取款: " + to_string(amount)) {}
const char* what() const noexcept override {
return message.c_str();
}
};
class BankAccount {
double balance;
public:
BankAccount(double b) : balance(b) {}
void withdraw(double amount) {
if (amount > balance) {
throw InsufficientFundsException(balance, amount);
}
balance -= amount;
cout << "取款 " << amount << " 成功,余额: " << balance << endl;
}
double getBalance() const { return balance; }
};
int main() {
BankAccount account(1000);
try {
account.withdraw(500);
account.withdraw(300);
account.withdraw(500); // 余额不足
}
catch (const InsufficientFundsException& e) {
cerr << "交易失败: " << e.what() << endl;
}
return 0;
}
15.3 异常安全与 RAII
#include <iostream>
#include <fstream>
#include <memory>
using namespace std;
// RAII:资源获取即初始化
// 资源在构造函数中获取,在析构函数中释放
class FileHandler {
private:
ofstream file;
public:
FileHandler(const string& filename) {
file.open(filename);
if (!file.is_open()) {
throw runtime_error("无法打开文件: " + filename);
}
cout << "文件已打开" << endl;
}
~FileHandler() {
if (file.is_open()) {
file.close();
cout << "文件已关闭" << endl;
}
}
void write(const string& content) {
file << content << endl;
}
// 禁止拷贝
FileHandler(const FileHandler&) = delete;
FileHandler& operator=(const FileHandler&) = delete;
};
int main() {
try {
FileHandler fh("test.txt");
fh.write("Hello, RAII!");
fh.write("异常安全的文件操作");
}
catch (const exception& e) {
cerr << "错误: " << e.what() << endl;
}
// 离开作用域时,即使发生异常,析构函数也会被调用,文件会被正确关闭
return 0;
}
16. 文件操作
16.1 文本文件读写
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main() {
// ===== 写入文件 =====
ofstream outFile("example.txt");
if (!outFile) {
cerr << "无法创建文件" << endl;
return 1;
}
outFile << "第一行:Hello, File!" << endl;
outFile << "第二行:C++ 文件操作" << endl;
outFile << "第三行:这是最后一行" << endl;
outFile.close();
cout << "文件写入完成" << endl;
// ===== 读取文件(逐行) =====
ifstream inFile("example.txt");
if (!inFile) {
cerr << "无法打开文件" << endl;
return 1;
}
string line;
int lineNum = 1;
cout << "\n=== 文件内容 ===" << endl;
while (getline(inFile, line)) {
cout << lineNum++ << ": " << line << endl;
}
inFile.close();
// ===== 追加写入 =====
ofstream appendFile("example.txt", ios::app);
appendFile << "第四行:追加的内容" << endl;
appendFile.close();
return 0;
}
16.2 二进制文件读写
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
struct Student {
char name[50];
int age;
double score;
};
int main() {
// 写入二进制文件
Student students[] = {
{"张三", 20, 85.5},
{"李四", 21, 92.0},
{"王五", 19, 78.3}
};
ofstream binOut("students.dat", ios::binary);
binOut.write(reinterpret_cast<char*>(students), sizeof(students));
binOut.close();
cout << "二进制文件写入完成" << endl;
// 读取二进制文件
ifstream binIn("students.dat", ios::binary);
Student readStudents[3];
binIn.read(reinterpret_cast<char*>(readStudents), sizeof(readStudents));
binIn.close();
cout << "\n=== 读取的数据 ===" << endl;
for (const auto& s : readStudents) {
cout << "姓名: " << s.name
<< ", 年龄: " << s.age
<< ", 成绩: " << s.score << endl;
}
return 0;
}
16.3 字符串流
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
// 字符串解析
string data = "张三 20 85.5";
istringstream iss(data);
string name;
int age;
double score;
iss >> name >> age >> score;
cout << "解析结果: " << name << ", " << age << ", " << score << endl;
// 字符串构建
ostringstream oss;
oss << "姓名: " << name << ", 年龄: " << age << ", 成绩: " << score;
string result = oss.str();
cout << "构建的字符串: " << result << endl;
// 类型转换
string numStr = "12345";
int num;
istringstream(numStr) >> num;
cout << "转换为整数: " << num << endl;
return 0;
}
17. 实战项目:图书管理系统
综合运用前面所学知识,实现一个功能完整的控制台图书管理系统。
17.1 项目结构
library-system/
├── main.cpp # 主程序入口
├── Book.h # 图书类定义
├── Library.h # 图书馆类定义
└── utils.h # 工具函数
17.2 完整代码
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <memory>
#include <iomanip>
#include <limits>
using namespace std;
// ==================== Book 类 ====================
class Book {
private:
string isbn; // ISBN 号
string title; // 书名
string author; // 作者
string publisher; // 出版社
int year; // 出版年份
bool available; // 是否可借
public:
Book() : year(0), available(true) {}
Book(string isbn, string title, string author, string publisher, int year)
: isbn(isbn), title(title), author(author),
publisher(publisher), year(year), available(true) {}
// Getters
string getISBN() const { return isbn; }
string getTitle() const { return title; }
string getAuthor() const { return author; }
string getPublisher() const { return publisher; }
int getYear() const { return year; }
bool isAvailable() const { return available; }
// Setters
void setAvailable(bool status) { available = status; }
// 显示图书信息
void display() const {
cout << "| " << setw(14) << left << isbn
<< "| " << setw(20) << left << title
<< "| " << setw(12) << left << author
<< "| " << setw(10) << left << year
<< "| " << setw(8) << left << (available ? "可借" : "已借出")
<< "|" << endl;
}
// 序列化为字符串(用于文件存储)
string serialize() const {
ostringstream oss;
oss << isbn << "|" << title << "|" << author << "|"
<< publisher << "|" << year << "|" << available;
return oss.str();
}
// 从字符串反序列化
static Book deserialize(const string& data) {
istringstream iss(data);
string token;
Book book;
getline(iss, book.isbn, '|');
getline(iss, book.title, '|');
getline(iss, book.author, '|');
getline(iss, book.publisher, '|');
getline(iss, token, '|');
book.year = stoi(token);
getline(iss, token, '|');
book.available = (token == "1");
return book;
}
};
// ==================== Library 类 ====================
class Library {
private:
string name;
map<string, Book> books; // ISBN -> Book
// 打印分隔线
void printSeparator() const {
cout << "+----------------+--------------------+------------+"
"----------+--------+" << endl;
}
// 打印表头
void printHeader() const {
printSeparator();
cout << "| " << setw(14) << left << "ISBN"
<< "| " << setw(20) << left << "书名"
<< "| " << setw(12) << left << "作者"
<< "| " << setw(10) << left << "年份"
<< "| " << setw(8) << left << "状态"
<< "|" << endl;
printSeparator();
}
public:
Library(string name) : name(name) {}
string getName() const { return name; }
// 添加图书
bool addBook(const Book& book) {
if (books.count(book.getISBN()) > 0) {
cout << "❌ 错误:ISBN " << book.getISBN() << " 已存在!" << endl;
return false;
}
books[book.getISBN()] = book;
cout << "✅ 图书《" << book.getTitle() << "》添加成功!" << endl;
return true;
}
// 删除图书
bool removeBook(const string& isbn) {
auto it = books.find(isbn);
if (it == books.end()) {
cout << "❌ 未找到 ISBN 为 " << isbn << " 的图书" << endl;
return false;
}
cout << "✅ 图书《" << it->second.getTitle() << "》已删除" << endl;
books.erase(it);
return true;
}
// 借书
bool borrowBook(const string& isbn) {
auto it = books.find(isbn);
if (it == books.end()) {
cout << "❌ 未找到该图书" << endl;
return false;
}
if (!it->second.isAvailable()) {
cout << "❌ 该图书已被借出" << endl;
return false;
}
it->second.setAvailable(false);
cout << "✅ 成功借出《" << it->second.getTitle() << "》" << endl;
return true;
}
// 还书
bool returnBook(const string& isbn) {
auto it = books.find(isbn);
if (it == books.end()) {
cout << "❌ 未找到该图书" << endl;
return false;
}
if (it->second.isAvailable()) {
cout << "⚠️ 该图书未被借出" << endl;
return false;
}
it->second.setAvailable(true);
cout << "✅ 成功归还《" << it->second.getTitle() << "》" << endl;
return true;
}
// 按书名搜索
void searchByTitle(const string& keyword) const {
printHeader();
int count = 0;
for (const auto& pair : books) {
if (pair.second.getTitle().find(keyword) != string::npos) {
pair.second.display();
count++;
}
}
printSeparator();
cout << "找到 " << count << " 本图书" << endl;
}
// 按作者搜索
void searchByAuthor(const string& keyword) const {
printHeader();
int count = 0;
for (const auto& pair : books) {
if (pair.second.getAuthor().find(keyword) != string::npos) {
pair.second.display();
count++;
}
}
printSeparator();
cout << "找到 " << count << " 本图书" << endl;
}
// 显示所有图书
void displayAll() const {
if (books.empty()) {
cout << "📚 图书馆暂无藏书" << endl;
return;
}
cout << "\n📚 " << name << " - 馆藏图书列表" << endl;
printHeader();
for (const auto& pair : books) {
pair.second.display();
}
printSeparator();
cout << "共 " << books.size() << " 本图书" << endl;
}
// 显示统计信息
void displayStats() const {
int total = books.size();
int available = 0;
for (const auto& pair : books) {
if (pair.second.isAvailable()) available++;
}
cout << "\n📊 统计信息:" << endl;
cout << " 总藏书量: " << total << endl;
cout << " 可借数量: " << available << endl;
cout << " 已借出: " << (total - available) << endl;
}
// 保存到文件
bool saveToFile(const string& filename) const {
ofstream file(filename);
if (!file) {
cerr << "❌ 无法打开文件进行写入" << endl;
return false;
}
for (const auto& pair : books) {
file << pair.second.serialize() << endl;
}
file.close();
cout << "✅ 数据已保存到 " << filename << endl;
return true;
}
// 从文件加载
bool loadFromFile(const string& filename) {
ifstream file(filename);
if (!file) {
cout << "⚠️ 数据文件不存在,将创建新图书馆" << endl;
return false;
}
string line;
int count = 0;
while (getline(file, line)) {
if (!line.empty()) {
Book book = Book::deserialize(line);
books[book.getISBN()] = book;
count++;
}
}
file.close();
cout << "✅ 从文件加载了 " << count << " 本图书" << endl;
return true;
}
};
// ==================== 工具函数 ====================
void clearInput() {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
void pauseScreen() {
cout << "\n按 Enter 键继续...";
clearInput();
cin.get();
}
// ==================== 主菜单 ====================
void showMenu() {
cout << "\n╔══════════════════════════════════════╗" << endl;
cout << "║ 📚 图书管理系统 v1.0 ║" << endl;
cout << "╠══════════════════════════════════════╣" << endl;
cout << "║ 1. 添加图书 ║" << endl;
cout << "║ 2. 删除图书 ║" << endl;
cout << "║ 3. 借阅图书 ║" << endl;
cout << "║ 4. 归还图书 ║" << endl;
cout << "║ 5. 按书名搜索 ║" << endl;
cout << "║ 6. 按作者搜索 ║" << endl;
cout << "║ 7. 显示所有图书 ║" << endl;
cout << "║ 8. 统计信息 ║" << endl;
cout << "║ 9. 保存数据 ║" << endl;
cout << "║ 0. 退出系统 ║" << endl;
cout << "╚══════════════════════════════════════╝" << endl;
cout << "请选择操作 (0-9): ";
}
int main() {
Library library("我的图书馆");
const string dataFile = "library_data.txt";
// 启动时自动加载数据
library.loadFromFile(dataFile);
int choice;
bool running = true;
while (running) {
showMenu();
cin >> choice;
if (cin.fail()) {
clearInput();
cout << "❌ 请输入有效的数字!" << endl;
continue;
}
clearInput();
switch (choice) {
case 1: {
// 添加图书
string isbn, title, author, publisher;
int year;
cout << "\n--- 添加图书 ---" << endl;
cout << "ISBN: "; getline(cin, isbn);
cout << "书名: "; getline(cin, title);
cout << "作者: "; getline(cin, author);
cout << "出版社: "; getline(cin, publisher);
cout << "出版年份: "; cin >> year;
clearInput();
Book book(isbn, title, author, publisher, year);
library.addBook(book);
pauseScreen();
break;
}
case 2: {
// 删除图书
string isbn;
cout << "\n--- 删除图书 ---" << endl;
cout << "请输入 ISBN: "; getline(cin, isbn);
library.removeBook(isbn);
pauseScreen();
break;
}
case 3: {
// 借阅
string isbn;
cout << "\n--- 借阅图书 ---" << endl;
cout << "请输入 ISBN: "; getline(cin, isbn);
library.borrowBook(isbn);
pauseScreen();
break;
}
case 4: {
// 归还
string isbn;
cout << "\n--- 归还图书 ---" << endl;
cout << "请输入 ISBN: "; getline(cin, isbn);
library.returnBook(isbn);
pauseScreen();
break;
}
case 5: {
// 按书名搜索
string keyword;
cout << "\n--- 书名搜索 ---" << endl;
cout << "请输入关键词: "; getline(cin, keyword);
library.searchByTitle(keyword);
pauseScreen();
break;
}
case 6: {
// 按作者搜索
string keyword;
cout << "\n--- 作者搜索 ---" << endl;
cout << "请输入关键词: "; getline(cin, keyword);
library.searchByAuthor(keyword);
pauseScreen();
break;
}
case 7: {
library.displayAll();
pauseScreen();
break;
}
case 8: {
library.displayStats();
pauseScreen();
break;
}
case 9: {
library.saveToFile(dataFile);
pauseScreen();
break;
}
case 0: {
// 退出前自动保存
library.saveToFile(dataFile);
cout << "\n👋 感谢使用图书管理系统,再见!" << endl;
running = false;
break;
}
default:
cout << "❌ 无效选择,请重新输入" << endl;
pauseScreen();
}
}
return 0;
}
17.3 项目知识点总结
这个实战项目综合运用了以下 C++ 知识点:
| 知识点 | 在项目中的应用 |
|---|---|
| 类与对象 | Book 类和 Library 类的设计 |
| 封装 | private 成员 + public 接口 |
| STL 容器 | map 存储图书,vector 管理数据 |
| 字符串处理 | string、stringstream 的使用 |
| 文件操作 | 图书数据的保存与加载 |
| 异常处理 | 文件操作的错误处理 |
| 智能指针 | 可扩展为 shared_ptr 管理图书对象 |
| 算法 | find、count_if 等搜索统计 |
| 格式化输出 | setw、left 对齐输出 |
17.4 编译与运行
g++ -std=c++17 -o library main.cpp
./library
18. 学习建议与进阶路线
学习建议
- 多写代码:光看不练是学不会编程的,每个知识点都要亲手敲代码
- 理解原理:不要只记语法,要理解背后的原理(如内存模型、编译过程)
- 善用调试:学会使用
gdb或 IDE 的调试器,观察程序运行过程 - 阅读优秀代码:GitHub 上有很多高质量的 C++ 开源项目
- 循序渐进:不要跳过基础直接学高级特性
进阶路线
基础语法 → 面向对象 → STL → 模板 → 现代C++(C++11/14/17/20)
↓
并发编程 ← 内存模型 ← 智能指针
↓
设计模式 ← 性能优化 ← 系统编程
推荐学习资源
书籍:
- 《C++ Primer》(第5版)—— 最经典的 C++ 入门书
- 《Effective C++》—— 55 条改善程序设计的建议
- 《C++ 标准库》—— 全面的 STL 参考
- 《STL 源码剖析》—— 深入理解 STL 实现
在线资源:
- cppreference.com —— 最权威的 C++ 参考文档
- learncpp.com —— 优秀的免费教程
- C++ Core Guidelines —— C++ 最佳实践指南
练习项目建议
| 难度 | 项目 | 涉及知识点 |
|---|---|---|
| ⭐ | 学生成绩管理系统 | 类、文件IO、基本算法 |
| ⭐⭐ | 简易计算器 | 运算符重载、异常处理 |
| ⭐⭐ | 贪吃蛇游戏 | 二维数组、循环、条件判断 |
| ⭐⭐⭐ | 通讯录管理系统 | STL容器、文件操作、搜索 |
| ⭐⭐⭐ | 简易 HTTP 服务器 | 网络编程、多线程 |
| ⭐⭐⭐⭐ | 数据库引擎 | 文件系统、B树、序列化 |
| ⭐⭐⭐⭐⭐ | 游戏引擎 | 设计模式、内存管理、性能优化 |
写在最后:C++ 是一门博大精深的语言,即使是经验丰富的开发者也在不断学习。保持好奇心,持续实践,你一定能掌握它。祝你学习愉快!🚀