第十六章 实战项目:把前面学的都用起来

← 返回目录

本章目标:三个完整可运行的项目,覆盖大部分知识点。 每个项目都给出完整代码,请亲手敲一遍、改一遍、跑一遍。

项目一:词频统计器(文件分析)

功能:读入文本文件,统计每个单词出现次数,输出 TOP 10。 知识点:文件 IO、string、map、sort、lambda、format。

#include <print>
#include <fstream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <cctype>

int main(int argc, char* argv[]) {
    if (argc < 2) {
        std::println("用法:./wordfreq 文件名");
        return 1;
    }
    std::ifstream in(argv[1]);
    if (!in) {
        std::println("打不开文件:{}", argv[1]);
        return 1;
    }

    std::map<std::string, int> freq;
    std::string word;
    while (in >> word) {
        std::string clean;
        for (char c : word) {
            if (std::isalpha(static_cast<unsigned char>(c)))
                clean.push_back(std::tolower(static_cast<unsigned char>(c)));
        }
        if (!clean.empty()) ++freq[clean];
    }

    std::vector<std::pair<std::string, int>> items(freq.begin(), freq.end());
    std::sort(items.begin(), items.end(),
              [](const auto& a, const auto& b) {
                  return a.second > b.second;   // 次数降序
              });

    std::println("单词总数:{},不同单词:{}", freq.size(), items.size());
    for (int i = 0; i < 10 && i < (int)items.size(); ++i) {
        std::println("{:>4}. {:<15} {}", i + 1, items[i].first, items[i].second);
    }
}

运行:

clang++ -std=c++26 wordfreq.cpp -o wordfreq
./wordfreq 06_字符串与输入输出.txt

项目二:TODO 任务管理器(交互式)

功能:增删查改任务,支持优先级排序,保存到文件。 知识点:struct、vector、optional、variant、错误处理、序列化。

#include <print>
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <optional>
#include <algorithm>

struct Task {
    std::string title;
    int priority = 0;      // 0 最低,5 最高
    bool done = false;
};

using TaskList = std::vector<Task>;

void save(const TaskList& tasks, const std::string& file) {
    std::ofstream out(file);
    for (const auto& t : tasks)
        out << t.done << ' ' << t.priority << ' ' << t.title << '\n';
}

std::optional<TaskList> load(const std::string& file) {
    std::ifstream in(file);
    if (!in) return std::nullopt;
    TaskList tasks;
    Task t;
    while (in >> t.done >> t.priority) {
        std::getline(in, t.title);
        if (!t.title.empty() && t.title.front() == ' ')
            t.title.erase(0, 1);        // 去掉开头空格
        tasks.push_back(t);
    }
    return tasks;
}

void show(const TaskList& tasks) {
    if (tasks.empty()) { std::println("(没有任务)"); return; }
    for (std::size_t i = 0; i < tasks.size(); ++i) {
        const auto& t = tasks[i];
        std::println("{} [{}{}] [P{}] {}",
                     i + 1, t.done ? "✓" : " ", t.done ? " ]" : "  ",
                     t.priority, t.title);
    }
}

int main() {
    const std::string file = "tasks.txt";
    auto tasks = load(file).value_or(TaskList{});
    std::string cmd;

    while (true) {
        std::println("\n命令:add 标题 | done 编号 | del 编号 | list | save | quit");
        std::print("> ");
        std::getline(std::cin, cmd);

        if (cmd == "quit") { save(tasks, file); break; }
        if (cmd == "list") { show(tasks); }
        else if (cmd == "save") { save(tasks, file); }
        else if (cmd.rfind("add ", 0) == 0) {
            tasks.push_back({cmd.substr(4), 1, false});
        }
        else if (cmd.rfind("done ", 0) == 0) {
            int i = std::stoi(cmd.substr(5)) - 1;
            if (i >= 0 && i < (int)tasks.size()) tasks[i].done = true;
        }
        else if (cmd.rfind("del ", 0) == 0) {
            int i = std::stoi(cmd.substr(4)) - 1;
            if (i >= 0 && i < (int)tasks.size())
                tasks.erase(tasks.begin() + i);
        }
        else std::println("看不懂,试试 add 买牛奶");
    }
    std::println("再见!");
}

项目三:素数相关的小工具集(数值算法)

功能:埃氏筛求质数、分解质因数、判断素数。 知识点:vector、算法、函数、模板、constexpr。

#include <print>
#include <vector>
#include <cstdint>

std::vector<std::int64_t> sieve_prime_factors(std::int64_t n) {
    std::vector<std::int64_t> factors;
    for (std::int64_t p = 2; p * p <= n; ++p) {
        while (n % p == 0) { factors.push_back(p); n /= p; }
    }
    if (n > 1) factors.push_back(n);
    return factors;
}

std::vector<int> primes_below(int limit) {     // 埃氏筛
    std::vector<bool> composite(limit + 1, false);
    std::vector<int> primes;
    for (int i = 2; i <= limit; ++i) {
        if (!composite[i]) {
            primes.push_back(i);
            for (std::int64_t j = (std::int64_t)i * i; j <= limit; j += i)
                composite[j] = true;
        }
    }
    return primes;
}

template <std::integral T>
constexpr bool is_prime(T n) {
    if (n < 2) return false;
    for (T i = 2; i * i <= n; ++i)
        if (n % i == 0) return false;
    return true;
}

int main() {
    constexpr bool p = is_prime(97);   // 编译期就算好了
    static_assert(p == true);

    std::println("100 以内的质数有 {} 个", primes_below(100).size());
    for (std::int64_t n : {100, 360, 97, 123456789}) {
        auto f = sieve_prime_factors(n);
        std::println("{} = {}", n,
                     std::format("{}", f) );   // 直接打印 vector
    }
}

运行需要 #include <print> 和 <concepts>(std::format 支持直接格式化 vector)。

可选进阶:新版 libc++ 支持 views::transform + join_with,打印成 "2 * 2 * 5 * 5" 这种形式;你的环境版本旧,用 format 打 vector 最简单。

如何继续进阶(路标)

学完本书,你已经掌握现代 C++ 的主体。继续前进的路标:

  1. 多线程与并发:<thread>、<mutex>、<condition_variable>、

std::async、原子操作、无锁编程(进阶)

  1. 网络编程:asio / Boost.Asio、WebSocket、HTTP 客户端
  2. 模板元编程深入:traits、编译期 if 的更多用法、CRTP
  3. 性能优化:缓存友好、SSO、inline、编译期计算、内存池
  4. 工程化:CMake 构建、测试(Catch2/GoogleTest)、

包管理(vcpkg/conan)、CI

  1. 项目实战:写一个 JSON 解析器、内存池、游戏引擎核心、

数据库引擎、渲染器——以作品代练习

推荐开源项目阅读顺序(GitHub 上搜):

最终寄语

C++ 学的是"控制"与"责任"的平衡。掌握现代 C++(17+), 你可以写出和 Python 一样清晰、和 C 一样快的程序。 把这本书当成工具书:概念忘了就翻对应章节, 关键是动手——把每个练习敲出来、改一改、跑起来。 你已经在正确的道路上了,加油。