chengaofeng
发布于 2024-09-11 / 5 阅读
0
0

C++编程:从入门到精通

前言

  • 书籍介绍

  • 学习方法简介(西蒙学习法、费曼学习法、艾宾浩斯记忆曲线)

  • 如何使用本书

第一部分:C++基础

第1章:C++简介
  • C++的历史和特点

  • 开发环境搭建

  • 第一个C++程序:Hello, World!

第2章:基本数据类型和运算符
  • 变量和数据类型

  • 常量

  • 运算符和表达式

第3章:控制结构
  • 条件语句(if, switch)

  • 循环语句(for, while, do-while)

第4章:函数
  • 函数定义和调用

  • 参数和返回值

  • 作用域和存储类别

第二部分:C++进阶

第5章:数组和字符串
  • 一维数组

  • 二维数组

  • C++字符串和标准库

第6章:指针和引用
  • 指针基础

  • 指针和数组

  • 引用

第7章:内存管理
  • 动态内存分配(new, delete)

  • 内存泄漏和野指针

第8章:面向对象编程基础
  • 类和对象

  • 构造函数和析构函数

  • 访问控制

第三部分:高级特性

第9章:继承和多态
  • 继承的概念

  • 多态性

  • 虚函数和纯虚函数

第10章:模板
  • 函数模板

  • 类模板

  • 模板特化

第11章:标准模板库(STL)
  • 容器(vector, list, map等)

  • 迭代器

  • 算法

第12章:异常处理
  • 异常的概念

  • 异常处理机制

  • 自定义异常

第四部分:C++应用开发

第13章:文件操作
  • 文件的打开和关闭

  • 文件的读写操作

  • 文件流

第14章:网络编程
  • 套接字基础

  • TCP/IP编程

  • UDP编程

第15章:并发编程
  • 线程基础

  • 同步机制

  • 并发数据结构

第五部分:项目实战

第16章:项目1:基础项目实战
  • 项目概述

  • 项目设计

  • 项目实现

第17章:项目2:中级项目实战
  • 项目概述

  • 项目设计

  • 项目实现

第18章:项目3:高级项目实战
  • 项目概述

  • 项目设计

  • 项目实现

附录

  • A. C++关键字

  • B. 常用库函数

  • C. 常见问题解答

参考文献

索引

后记

学习方法应用

  • 每章末尾提供复习题和实践项目,应用西蒙学习法和费曼学习法。

  • 定期回顾前文内容,应用艾宾浩斯记忆曲线。

前言

欢迎阅读《C++编程:从入门到精通》,这是一本旨在帮助读者从基础到高级掌握C++编程语言的教程。无论您是编程新手还是希望提升C++技能的开发者,本书都将为您提供全面的指导和实践机会。

书籍介绍

本书分为五个部分,涵盖了C++的基础知识、进阶特性、高级应用以及实际项目开发。每一部分都精心设计,以确保您能够逐步建立起坚实的C++编程基础,并能够应用这些知识解决实际问题。

学习方法简介

为了帮助您更有效地学习,本书采用了以下三种学习方法:

  1. 西蒙学习法:通过分块学习和逐步增加难度,帮助您系统地掌握C++的各个方面。

  2. 费曼学习法:鼓励您通过教授他人来巩固自己的理解,这种方法已被证明可以显著提高学习效率。

  3. 艾宾浩斯记忆曲线:通过定期复习,帮助您长期记忆C++的知识点。

如何使用本书

  • 循序渐进:按照本书的章节顺序进行学习,确保您不会错过任何重要概念。

  • 实践为主:每章末尾都配有练习题和项目,通过实践来巩固您的学习。

  • 定期复习:利用艾宾浩斯记忆曲线,定期回顾已学内容,以加强记忆。

  • 社区参与:加入C++编程社区,与其他学习者和开发者交流心得,共同进步。

致谢

在本书的编写过程中,我们得到了许多专家和读者的宝贵意见。我们对他们的贡献表示衷心的感谢。同时,我们也期待您的反馈,以便我们不断改进和更新本书内容。

第一部分:C++基础

第1章:C++简介

1.1 C++的历史

C++是一种通用的、静态类型的、大小写敏感的、自由格式的编程语言,支持过程化编程、面向对象编程和泛型编程。它最初由Bjarne Stroustrup在1980年代设计,作为C语言的超集,增加了面向对象的特性。

1.2 C++的特点

  • 面向对象:支持类、继承、封装和多态等面向对象的特性。

  • 泛型编程:通过模板支持泛型编程,提高了代码的复用性。

  • 性能:提供了对硬件的直接操作能力,可以编写高效的程序。

  • 标准库:拥有丰富的标准库,包括STL(标准模板库),提供了常用的数据结构和算法。

1.3 开发环境搭建

在本节中,我们将指导您如何搭建C++的开发环境。无论是使用GCC、Clang还是Visual Studio,我们都会提供详细的步骤。

1.4 第一个C++程序:Hello, World!

#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

这是C++中最著名的程序,它展示了如何输出文本到控制台。我们将逐步解释代码的每一部分,确保您能够理解其工作原理。

1.5 总结

在本章中,我们介绍了C++的背景、特点以及如何搭建开发环境。我们还编写了第一个C++程序,为后续的学习打下了基础。

1.6 练习题

  1. 修改“Hello, World!”程序,使其输出您自己的名字。

  2. 尝试使用不同的输出语句,例如std::cout << "C++ is fun!" << std::endl;

第2章:基本数据类型和运算符

在C++中,数据类型是程序设计的基础。它们定义了变量可以存储的数据种类以及这些数据如何被处理。本章将介绍C++中的基本数据类型和运算符,这是编写任何C++程序的基石。

2.1 变量和数据类型

变量是程序中用于存储数据的容器。在C++中,变量必须先声明后使用,声明时需要指定数据类型。

2.1.1 基本数据类型
  • 整型(int):用于存储整数,如 -1, 0, 1。

  • 浮点型(float, double):用于存储小数,如 3.14, -0.001。

  • 字符型(char):用于存储单个字符,如 'A', '5', '\n'。

2.1.2 声明变量
int age;
float salary;
char initial;
2.1.3 初始化变量

在声明变量时,可以同时进行初始化:

int age = 25;
float salary = 3000.50;
char initial = 'J';

2.2 常量

常量是程序中的固定值,一旦赋值后不能被修改。

2.2.1 定义常量

使用const关键字定义常量:

const int MAX_USERS = 100;

2.3 运算符和表达式

运算符是用于执行操作的特殊符号,而表达式是由变量、常量和运算符组合而成的。

2.3.1 算术运算符
  • + 加法

  • - 减法

  • * 乘法

  • / 除法

  • % 取模(求余)

2.3.2 赋值运算符
  • = 赋值

2.3.3 比较运算符
  • == 等于

  • != 不等于

  • > 大于

  • < 小于

  • >= 大于等于

  • <= 小于等于

2.3.4 逻辑运算符
  • && 逻辑与

  • || 逻辑或

  • ! 逻辑非

2.4 示例:使用运算符

int a = 10;
int b = 5;
int sum = a + b; // 算术运算
int difference = a - b; // 算术运算
bool isEqual = (a == b); // 比较运算
bool isNotEqual = (a != b); // 比较运算

2.5 总结

本章介绍了C++中的基本数据类型、变量的声明和初始化、常量以及各种运算符。这些是构建任何C++程序的基础。

2.6 练习题

  1. 声明并初始化三个不同类型的变量。

  2. 使用算术运算符计算两个数的和、差、积、商和余数。

  3. 使用比较运算符比较两个数,并使用逻辑运算符组合这些比较。

第3章:控制结构

控制结构是编程中用于控制程序流程的语句。在C++中,控制结构包括条件语句和循环语句,它们允许程序根据不同的条件执行不同的代码块。

3.1 条件语句

条件语句允许程序根据条件的真假来执行不同的代码路径。

3.1.1 if语句

if语句是最基本的条件语句,它根据条件表达式的真假来决定是否执行特定的代码块。

int score = 75;
if (score > 70) {
    std::cout << "Pass" << std::endl;
} else {
    std::cout << "Fail" << std::endl;
}
3.1.2 if...else语句

if...else语句允许在条件为假时执行另一段代码。

int score = 55;
if (score > 70) {
    std::cout << "Pass" << std::endl;
} else {
    std::cout << "Fail" << std::endl;
}
3.1.3 switch语句

switch语句用于基于不同的情况执行不同的代码块。

char grade = 'B';
switch (grade) {
    case 'A':
        std::cout << "Excellent" << std::endl;
        break;
    case 'B':
        std::cout << "Good" << std::endl;
        break;
    case 'C':
        std::cout << "Average" << std::endl;
        break;
    default:
        std::cout << "Fail" << std::endl;
}

3.2 循环语句

循环语句允许程序重复执行一段代码,直到满足特定条件。

3.2.1 for循环

for循环用于在给定的起始条件和终止条件之间重复执行代码。

for (int i = 0; i < 5; i++) {
    std::cout << "Iteration " << i << std::endl;
}
3.2.2 while循环

while循环在条件为真时重复执行代码。

int i = 0;
while (i < 5) {
    std::cout << "Iteration " << i << std::endl;
    i++;
}
3.2.3 do...while循环

do...while循环至少执行一次代码块,然后检查条件是否为真,如果是,则继续循环。

int i = 0;
do {
    std::cout << "Iteration " << i << std::endl;
    i++;
} while (i < 5);

3.3 循环控制语句

循环控制语句用于改变循环的执行流程。

3.3.1 break语句

break语句用于立即退出循环。

for (int i = 0; i < 5; i++) {
    if (i == 3) {
        break; // Exit the loop when i is 3
    }
    std::cout << "Iteration " << i << std::endl;
}
3.3.2 continue语句

continue语句用于跳过当前循环的剩余部分,并继续下一次迭代。

for (int i = 0; i < 5; i++) {
    if (i % 2 == 0) {
        continue; // Skip even numbers
    }
    std::cout << "Iteration " << i << std::endl;
}

3.4 总结

本章介绍了C++中的条件和循环控制结构,这些结构是控制程序流程的关键工具。通过这些结构,您可以编写出能够根据条件执行不同操作的程序。

3.5 练习题

  1. 使用if...else语句编写一个程序,根据用户输入的年龄判断是否成年。

  2. 使用for循环打印出1到100之间的所有奇数。

  3. 使用while循环实现一个简单的计数器,从1数到10。

第4章:函数

函数是封装一段代码的单元,可以被重复调用以执行特定的任务。在C++中,函数不仅可以提高代码的可读性和可维护性,还能增强代码的复用性。

4.1 函数定义和调用

函数由两部分组成:定义和调用。

4.1.1 定义函数

函数定义指定了函数的名称、参数、返回类型和函数体。

int add(int a, int b) {
    return a + b;
}

这个函数名为add,接受两个整数参数ab,返回它们的和。

4.1.2 调用函数

调用函数是使用函数的名称和实际参数来执行函数体中的代码。

int result = add(5, 3);
std::cout << "The result is: " << result << std::endl;

这里,我们调用了add函数,传递了两个整数5和3作为参数,并打印了返回的结果。

4.2 参数和返回值

参数是传递给函数的值,而返回值是函数执行完毕后返回的结果。

4.2.1 形式参数和实际参数
  • 形式参数:在函数定义中使用的参数。

  • 实际参数:在调用函数时传递给函数的参数。

4.2.2 返回值

函数可以返回一个值,这个值的类型由函数的返回类型决定。

int multiply(int x, int y) {
    return x * y;
}

这个multiply函数返回两个整数的乘积。

4.3 作用域和存储类别

作用域决定了变量的可见性和生命周期。

4.3.1 局部变量

局部变量是在函数内部定义的变量,它们只在该函数内部可见。

void printNumbers() {
    int num = 10; // 局部变量
    std::cout << num << std::endl;
}
4.3.2 全局变量

全局变量是在函数外部定义的变量,它们在整个程序中都是可见的。

int globalNum = 5; // 全局变量

void printGlobal() {
    std::cout << globalNum << std::endl;
}

4.4 函数的高级特性

C++提供了一些高级的函数特性,如默认参数、重载和递归。

4.4.1 默认参数

函数可以为参数提供默认值,这样在调用函数时可以省略这些参数。

void printMessage(const std::string& message, int times = 1) {
    for (int i = 0; i < times; i++) {
        std::cout << message << std::endl;
    }
}
4.4.2 函数重载

函数重载允许在相同的作用域内定义多个同名函数,只要它们的参数列表不同。

int add(int a, int b) {
    return a + b;
}

double add(double a, double b) {
    return a + b;
}
4.4.3 递归函数

递归函数是调用自身的函数,通常用于解决分治问题。

int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

4.5 总结

本章介绍了C++中的函数定义、调用、参数、返回值以及一些高级特性。理解这些概念对于编写模块化和可重用的代码至关重要。

4.6 练习题

  1. 编写一个函数,计算两个数的最大公约数。

  2. 使用默认参数编写一个函数,打印任意长度的字符串特定次数。

  3. 实现一个递归函数,计算斐波那契数列的第n项。

第5章:数组和字符串

数组和字符串是编程中常用的数据结构,用于存储和操作一系列数据。

5.1 一维数组

一维数组是相同数据类型的元素集合,可以通过索引访问每个元素。

5.1.1 声明一维数组
int numbers[5]; // 声明一个包含5个整数的数组
5.1.2 初始化一维数组
int numbers[5] = {1, 2, 3, 4, 5}; // 初始化数组
5.1.3 访问数组元素
std::cout << numbers[0]; // 访问第一个元素

5.2 二维数组

二维数组可以视为数组的数组,常用于表示表格数据。

5.2.1 声明二维数组
int matrix[3][2]; // 声明一个3行2列的数组
5.2.2 初始化二维数组
int matrix[3][2] = {{1, 2}, {3, 4}, {5, 6}}; // 初始化二维数组

5.3 C++字符串和标准库

C++提供了std::string类来处理字符串,它是标准库中的一部分。

5.3.1 声明和初始化字符串
std::string greeting = "Hello"; // 声明并初始化一个字符串
5.3.2 字符串操作

C++标准库提供了丰富的字符串操作函数,如连接、比较、查找等。

std::string str1 = "Hello, ";
std::string str2 = "World!";
std::string combined = str1 + str2; // 字符串连接

5.4 字符串和数组的关系

字符串可以被视为字符数组,但std::string类提供了更高级的操作。

5.4.1 字符数组和字符串
char charArray[] = "Hello"; // 字符数组
std::string str = "Hello"; // 字符串
5.4.2 字符串的动态操作

std::string支持动态修改,而字符数组通常需要手动管理内存。

str += " World!"; // 动态添加字符串

5.5 总结

本章介绍了C++中的数组和字符串处理。数组是存储一系列相同类型数据的结构,而std::string类提供了更高级的字符串操作功能。

5.6 练习题

  1. 声明并初始化一个包含10个整数的数组,并计算其总和。

  2. 创建一个3x3的二维数组,用于存储一个3x3的矩阵,并打印对角线元素的和。

  3. 使用std::string类编写一个函数,反转一个字符串并返回结果。

第6章:指针和引用

指针和引用是C++中用于直接访问和操作内存地址的特性。它们在性能优化和资源管理中扮演着重要角色。

6.1 指针基础

指针是一个变量,其存储的是另一个变量的内存地址。

6.1.1 声明指针
int *ptr; // 声明一个整型指针
6.1.2 初始化指针
int var = 10;
int *ptr = &var; // ptr 现在指向 var 的地址
6.1.3 指针解引用
std::cout << *ptr; // 输出 var 的值,即 10

6.2 指针和数组

指针常用于数组,因为数组名在很多情况下可以被解释为指向数组第一个元素的指针。

6.2.1 遍历数组
int arr[5] = {1, 2, 3, 4, 5};
for (int *p = arr; p < arr + 5; p++) {
    std::cout << *p << " "; // 输出数组元素
}

6.3 引用

引用是另一个变量的别名,它提供了一种间接访问变量的方式。

6.3.1 声明引用
int var = 10;
int &ref = var; // ref 是 var 的引用
6.3.2 使用引用
ref = 20; // 实际上是修改 var 的值
std::cout << var << " " << ref; // 输出 20 20

6.4 指针和动态内存分配

指针在动态内存分配中非常重要,它们用于管理newdelete操作的内存。

6.4.1 使用 new 分配内存
int *ptr = new int(10); // 分配一个整数并初始化为 10
6.4.2 使用 delete 释放内存
delete ptr; // 释放 ptr 指向的内存

6.5 指针和函数

指针在函数中用于传递大型数据结构,以及实现回调函数。

6.5.1 传递指针到函数
void modify(int *p) {
    *p = 50;
}

int main() {
    int var = 10;
    modify(&var);
    std::cout << var; // 输出 50
    return 0;
}

6.6 总结

本章介绍了C++中的指针和引用,包括它们的声明、初始化、使用以及在动态内存分配和函数中的应用。这些概念是理解C++中高级特性的基础。

6.7 练习题

  1. 编写一个函数,使用指针参数交换两个整数变量的值。

  2. 使用动态内存分配创建一个整数数组,并使用指针遍历这个数组。

  3. 编写一个函数,计算并返回一个整数数组的最大值和最小值,使用指针参数。

第7章:内存管理

在C++中,内存管理是一个关键话题,涉及到如何分配和释放内存,以及如何避免常见的内存错误。

7.1 动态内存分配

动态内存分配允许程序在运行时分配和释放内存。

7.1.1 使用 new 分配内存
int *ptr = new int; // 分配一个整数的内存
*ptr = 10; // 初始化内存
7.1.2 使用 delete 释放内存
delete ptr; // 释放内存
7.1.3 使用 new[] 和 delete[]

对于数组,应使用new[]delete[]来分配和释放内存。

int *arr = new int[5]; // 分配一个整数数组
delete[] arr; // 释放数组内存

7.2 内存泄漏

内存泄漏发生在分配了内存但没有正确释放时。

7.2.1 避免内存泄漏

确保每次new操作都有对应的delete操作,每次new[]操作都有对应的delete[]操作。

7.3 野指针

野指针是指向已释放或未初始化内存的指针。

7.3.1 避免野指针
  • 总是初始化指针。

  • 在不再需要时,将指针设置为nullptr

7.4 智能指针

C++11引入了智能指针,它们自动管理内存,帮助避免内存泄漏。

7.4.1 std::unique_ptr
std::unique_ptr<int> uniquePtr(new int(10)); // 自动释放内存
7.4.2 std::shared_ptr
std::shared_ptr<int> sharedPtr(new int(10)); // 引用计数自动释放内存

7.5 内存池

内存池是一种优化技术,用于减少内存分配和释放的开销。

7.5.1 使用内存池

内存池通常在性能要求高的应用程序中使用,如游戏和实时系统。

7.6 总结

本章介绍了C++中的内存管理技术,包括动态内存分配、内存泄漏、野指针、智能指针和内存池。掌握这些技术对于编写高效和稳定的C++程序至关重要。

7.7 练习题

  1. 编写一个程序,使用newdelete动态分配和释放一个整数数组。

  2. 使用std::unique_ptr管理一个动态分配的整数数组,并展示其用法。

  3. 讨论并实现一个简单的内存池,用于管理固定大小的内存块。

第8章:面向对象编程基础

面向对象编程(OOP)是C++的核心特性之一,它允许程序员通过使用对象和类来模拟现实世界的概念。

8.1 类和对象

类是对象的蓝图,而对象是类的实例。

8.1.1 定义类
class Person {
public:
    std::string name;
    int age;

    void greet() {
        std::cout << "Hello, my name is " << name << " and I am " << age << " years old." << std::endl;
    }
};
8.1.2 创建对象
Person person1;
person1.name = "Alice";
person1.age = 30;
person1.greet();

8.2 构造函数和析构函数

构造函数用于初始化对象,而析构函数用于在对象生命周期结束时进行清理。

8.2.1 定义构造函数
class Person {
public:
    std::string name;
    int age;

    // 构造函数
    Person(std::string n, int a) : name(n), age(a) {}
};
8.2.2 定义析构函数
class Person {
public:
    ~Person() {
        std::cout << "Person " << name << " is being destroyed." << std::endl;
    }
};

8.3 访问控制

C++中的类成员可以是公开的(public)或私有的(private),这决定了它们是否可以被类外部的代码访问。

8.3.1 公开和私有访问
class Person {
private:
    std::string name;
    int age;

public:
    void setName(std::string n) { name = n; }
    void setAge(int a) { age = a; }
    void greet() const {
        std::cout << "Hello, my name is " << name << " and I am " << age << " years old." << std::endl;
    }
};

8.4 继承

继承允许一个类(子类)继承另一个类(基类)的属性和方法。

8.4.1 定义继承
class Employee : public Person {
public:
    std::string jobTitle;

    void describe() {
        greet();
        std::cout << "I work as a " << jobTitle << "." << std::endl;
    }
};

8.5 多态

多态性允许使用基类指针或引用来指向子类对象,并在运行时确定调用哪个类的方法。

8.5.1 定义虚函数
class Person {
public:
    virtual void greet() const {
        std::cout << "Hello!" << std::endl;
    }
    virtual ~Person() {}
};

class Employee : public Person {
public:
    void greet() const override {
        std::cout << "Hello, I am an employee." << std::endl;
    }
};

8.6 总结

本章介绍了C++中的面向对象编程基础,包括类和对象、构造函数和析构函数、访问控制、继承和多态性。这些概念是构建复杂C++应用程序的基础。

8.7 练习题

  1. 定义一个Car类,包含品牌、型号和颜色属性,并实现一个打印这些属性的方法。

  2. 创建一个ElectricCar类,继承自Car类,并添加一个表示电池寿命的属性。

  3. 使用虚函数实现多态性,展示如何通过基类指针调用子类的方法。

第9章:继承和多态

继承和多态性是面向对象编程的核心概念,它们允许我们创建可扩展和可维护的代码。

9.1 继承的概念

继承是一种创建新类的方式,新类可以从现有类中继承属性和方法。

9.1.1 公有继承

公有继承是最常见的继承方式,它允许子类继承父类的公有成员。

class Base {
public:
    void show() { std::cout << "Base show" << std::endl; }
};

class Derived : public Base {
    void display() { std::cout << "Derived display" << std::endl; }
};

int main() {
    Derived obj;
    obj.show(); // 调用基类的公有成员函数
    obj.display();
    return 0;
}
9.1.2 保护继承和私有继承

保护继承和私有继承限制了继承成员的访问级别。

9.2 多态性

多态性允许我们以统一的方式处理不同类型的对象。

9.2.1 虚函数和纯虚函数

虚函数允许在派生类中重写函数,而纯虚函数用于定义抽象基类。

class Shape {
public:
    virtual void draw() const = 0; // 纯虚函数
};

class Circle : public Shape {
public:
    void draw() const override {
        std::cout << "Drawing a circle" << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void draw() const override {
        std::cout << "Drawing a rectangle" << std::endl;
    }
};
9.2.2 动态多态性

动态多态性允许在运行时确定调用哪个函数。

void drawShape(const Shape& shape) {
    shape.draw();
}

int main() {
    Circle circle;
    Rectangle rectangle;

    drawShape(circle); // 输出 "Drawing a circle"
    drawShape(rectangle); // 输出 "Drawing a rectangle"
    return 0;
}

9.3 虚继承

虚继承用于解决钻石继承问题,确保基类只有一个实例。

class Base {
public:
    int baseVar;
};

class Derived1 : virtual public Base {
public:
    int derived1Var;
};

class Derived2 : virtual public Base {
public:
    int derived2Var;
};

class MostDerived : public Derived1, public Derived2 {
public:
    int mostDerivedVar;
};

int main() {
    MostDerived obj;
    std::cout << obj.baseVar << std::endl;
    return 0;
}

9.4 接口和抽象类

接口是抽象类的一种,它包含纯虚函数。

class IDrawable {
public:
    virtual void draw() const = 0;
};

class ConcreteClass : public IDrawable {
public:
    void draw() const override {
        std::cout << "ConcreteClass draw" << std::endl;
    }
};

9.5 总结

本章介绍了C++中的继承和多态性,包括公有继承、保护继承、私有继承、虚函数、纯虚函数、动态多态性、虚继承、接口和抽象类。这些特性使得C++非常适合构建可扩展和可维护的应用程序。

9.6 练习题

  1. 创建一个基类Animal和两个派生类DogCat,实现多态性。

  2. 使用虚继承解决钻石继承问题。

  3. 定义一个接口ITransport,并创建实现该接口的类。

第10章:模板

模板是C++中实现泛型编程的工具,允许编写与数据类型无关的代码。

10.1 函数模板

函数模板允许创建可接受任何数据类型的函数。

10.1.1 定义函数模板
template <typename T>
void print(T value) {
    std::cout << value << std::endl;
}
10.1.2 使用函数模板
print(10);      // int
print(3.14);    // double
print("Hello"); // string

10.2 类模板

类模板允许创建与数据类型无关的类。

10.2.1 定义类模板
template <typename T>
class Stack {
private:
    std::vector<T> elements;

public:
    void push(const T& element) {
        elements.push_back(element);
    }

    T pop() {
        if (elements.empty()) {
            throw std::out_of_range("Stack<>::pop(): empty stack");
        }
        T elem = elements.back();
        elements.pop_back();
        return elem;
    }
};
10.2.2 使用类模板
Stack<int> intStack;
intStack.push(1);
intStack.push(2);

Stack<std::string> stringStack;
stringStack.push("Hello");
stringStack.push("World");

10.3 模板特化

模板特化允许为特定类型提供特定的实现。

10.3.1 全特化
template <>
void print<double>(double value) {
    std::cout << "Double: " << value << std::endl;
}
10.3.2 偏特化
template <typename T1, typename T2>
class Pair {
public:
    T1 first;
    T2 second;
};

// 偏特化
template <typename T>
class Pair<T, int> {
public:
    T first;
    int second;
};

10.4 模板的高级特性

C++11及更高版本提供了更多模板的高级特性,如自动类型推导、变长模板参数等。

10.4.1 自动类型推导
auto func = [](int x, int y) { return x + y; };
10.4.2 变长模板参数
template <typename... Args>
void print(Args... args) {
    (std::cout << ... << args) << std::endl;
}

10.5 总结

本章介绍了C++中的模板,包括函数模板、类模板、模板特化以及模板的高级特性。模板是实现泛型编程的关键工具,它们使得C++代码更加灵活和可重用。

10.6 练习题

  1. 创建一个函数模板,实现两个参数的交换。

  2. 定义一个类模板,实现一个简单的链表。

  3. 为特定类型特化一个函数模板。

第11章:标准模板库(STL)

C++标准模板库(STL)是一套预先定义的模板类和函数,用于实现常见的数据结构和算法。

11.1 容器(Containers)

STL容器是用于存储和管理数据集合的类模板。

11.1.1 序列容器
  • std::vector

  • std::deque

  • std::list

  • std::forward_list

11.1.2 容器适配器
  • std::stack

  • std::queue

  • std::priority_queue

11.1.3 关联容器
  • std::set

  • std::map

  • std::multiset

  • std::multimap

  • std::unordered_set

  • std::unordered_map

  • std::unordered_multiset

  • std::unordered_multimap

11.1.4 使用容器
std::vector<int> vec = {1, 2, 3, 4, 5};
std::cout << "Vector contains: ";
for (int elem : vec) {
    std::cout << elem << " ";
}
std::cout << std::endl;

11.2 迭代器(Iterators)

迭代器是用于遍历容器元素的对象。

11.2.1 迭代器类别
  • 输入迭代器

  • 输出迭代器

  • 前向迭代器

  • 双向迭代器

  • 随机访问迭代器

11.2.2 使用迭代器
std::vector<int> vec = {1, 2, 3, 4, 5};
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
    std::cout << *it << " ";
}
std::cout << std::endl;

11.3 算法(Algorithms)

STL提供了一组算法,用于操作容器中的数据。

11.3.1 常用算法
  • std::sort

  • std::find

  • std::copy

  • std::transform

  • std::accumulate

11.3.2 使用算法
std::vector<int> vec = {5, 3, 9, 1, 6};
std::sort(vec.begin(), vec.end());
std::cout << "Sorted vector: ";
for (int elem : vec) {
    std::cout << elem << " ";
}
std::cout << std::endl;

11.4 函数对象(Functors)

函数对象是行为类似于函数的对象,它们可以作为算法的参数。

11.4.1 定义函数对象
struct Square {
    void operator()(int& n) const {
        n *= n;
    }
};

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::for_each(vec.begin(), vec.end(), Square());
    for (int elem : vec) {
        std::cout << elem << " ";
    }
    return 0;
}

11.5 总结

本章介绍了C++的STL,包括容器、迭代器、算法和函数对象。STL是C++中非常强大的工具,它提供了一组丰富的、可复用的组件,用于处理常见的编程任务。

11.6 练习题

  1. 使用std::map创建一个映射,将整数映射到字符串。

  2. 使用std::sort和自定义比较函数对象对std::vector进行排序。

  3. 使用std::accumulate计算std::vector中所有元素的总和。

第12章:异常处理

异常处理是C++中用于处理程序执行中发生的意外情况的一种机制。它允许程序在遇到错误时,优雅地处理这些错误,而不是让程序崩溃。

12.1 异常的概念

异常是程序运行时发生的错误条件,它允许程序控制流从错误发生的地方跳转到程序中专门处理这种情况的代码块。

12.1.1 抛出异常

使用throw关键字可以抛出一个异常。

void divide(int numerator, int denominator) {
    if (denominator == 0) {
        throw std::invalid_argument("Denominator cannot be zero.");
    }
    std::cout << "Result: " << numerator / denominator << std::endl;
}

int main() {
    try {
        divide(10, 0);
    } catch (const std::invalid_argument& e) {
        std::cerr << "Exception caught: " << e.what() << std::endl;
    }
    return 0;
}

12.2 异常处理机制

异常处理机制包括try块、catch块、throw语句和finally行为(通过std::finally实现)。

12.2.1 try和catch块

try块是可能抛出异常的代码区域,而catch块用于捕获和处理异常。

try {
    // 尝试执行的代码
} catch (const SomeException& e) {
    // 处理SomeException类型的异常
} catch (...) {
    // 处理所有其他类型的异常
}
12.2.2 嵌套的try块

try块可以嵌套,以处理不同级别的异常。

try {
    try {
        // 内部try块
    } catch (...) {
        // 内部异常处理
    }
} catch (...) {
    // 外部异常处理
}

12.3 标准异常类

C++标准库定义了一系列标准异常类,这些类继承自std::exception

  • std::exception

  • std::runtime_error

  • std::invalid_argument

  • std::out_of_range

  • std::logic_error

  • std::domain_error

  • std::future_error

12.4 自定义异常

除了使用标准异常类,还可以定义自己的异常类。

class MyException : public std::exception {
private:
    std::string message;
public:
    MyException(const std::string& msg) : message(msg) {}
    const char* what() const noexcept override {
        return message.c_str();
    }
};

void riskyFunction() {
    throw MyException("Something went wrong!");
}

12.5 异常的传播

异常可以跨越多个函数调用栈被传播,直到被捕获。

12.6 总结

本章介绍了C++中的异常处理机制,包括异常的抛出、捕获、标准异常类、自定义异常以及异常的传播。掌握异常处理对于编写健壮的C++程序至关重要。

12.7 练习题

  1. 创建一个自定义异常类,用于处理文件读取错误。

  2. 在函数中抛出异常,并在主函数中捕获和处理这个异常。

  3. 使用标准异常类处理可能发生的逻辑错误。

第13章:文件操作

文件操作是程序设计中的基本需求,C++提供了一套完整的文件流(fstream)库来处理文件的输入输出。

13.1 文件的打开和关闭

在C++中,文件操作通常涉及打开文件、读写文件内容以及关闭文件。

13.1.1 打开文件

使用std::ifstreamstd::ofstreamstd::fstream来打开文件。

std::ofstream outFile("example.txt");
if (!outFile) {
    std::cerr << "Unable to open file";
    exit(1);
}
13.1.2 关闭文件

使用close()函数关闭文件。

outFile.close();

13.2 文件的读写操作

C++提供了多种方式来读写文件。

13.2.1 写入文件

使用插入运算符<<向文件写入数据。

outFile << "Hello, file!" << std::endl;
13.2.2 读取文件

使用提取运算符>>从文件读取数据。

std::ifstream inFile("example.txt");
std::string line;
while (std::getline(inFile, line)) {
    std::cout << line << std::endl;
}
inFile.close();

13.3 文件流

文件流是C++中处理文件I/O的类,包括std::ifstreamstd::ofstreamstd::fstream

13.3.1 使用文件流
std::fstream fileStream("example.txt", std::ios::in | std::ios::out);
if (!fileStream) {
    std::cerr << "Unable to open file";
    exit(1);
}

13.4 文件操作的高级特性

C++还提供了一些高级文件操作特性,如随机访问和文件流操作。

13.4.1 随机访问

使用文件流的seekgseekp成员函数进行随机访问。

inFile.seekg(10); // 从文件开始位置向后移动10个字符
outFile.seekp(20); // 从文件当前位置向后移动20个字符
13.4.2 文件流操作

使用eof()fail()good()等成员函数检查文件流的状态。

if (inFile.eof()) {
    std::cout << "End of file reached" << std::endl;
}

13.5 错误处理

文件操作中的错误处理非常重要,C++提供了多种方式来处理文件I/O错误。

13.5.1 检查错误

使用文件流的状态成员函数检查错误。

if (!outFile) {
    std::cerr << "Error opening file" << std::endl;
}

13.6 总结

本章介绍了C++中的文件操作,包括文件的打开和关闭、读写操作、文件流的使用、高级特性以及错误处理。掌握这些技能对于进行有效的文件I/O至关重要。

13.7 练习题

  1. 创建一个程序,将用户输入的文本写入文件。

  2. 编写一个程序,从文件中读取数据并显示在控制台上。

  3. 使用随机访问功能,从一个文本文件中读取特定行。

第14章:网络编程

网络编程是现代软件开发中不可或缺的一部分,C++通过套接字(sockets)提供了丰富的网络通信功能。

14.1 套接字基础

套接字是网络通信的端点,用于在网络中的设备之间发送和接收数据。

14.1.1 套接字类型
  • 流式套接字(SOCK_STREAM):提供顺序、可靠、双向连接,基于TCP。

  • 数据报套接字(SOCK_DGRAM):提供无连接服务,每个消息都有独立的路由和传输,基于UDP。

14.1.2 创建套接字

使用socket()函数创建套接字。

int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
    std::cerr << "Socket creation failed" << std::endl;
}

14.2 TCP/IP编程

TCP/IP是互联网的基础通信协议,C++通过套接字API支持TCP和IP协议。

14.2.1 服务器端

服务器监听特定端口,等待客户端的连接。

struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8080);
serverAddr.sin_addr.s_addr = INADDR_ANY;

if (bind(sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
    std::cerr << "Bind failed" << std::endl;
}

if (listen(sock, 5) < 0) {
    std::cerr << "Listen failed" << std::endl;
}
14.2.2 客户端

客户端连接到服务器的IP地址和端口。

struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);

int serverSock = connect(sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
if (serverSock < 0) {
    std::cerr << "Connection failed" << std::endl;
}

14.3 UDP编程

UDP编程使用数据报套接字,它是一种无连接的通信方式。

14.3.1 发送和接收数据
// 发送数据
struct sockaddr_in serverAddr;
// 初始化 serverAddr
char *message = "Hello, server";
sendto(sock, message, strlen(message), 0, (struct sockaddr *)&serverAddr, sizeof(serverAddr));

// 接收数据
char buffer[1024];
int len = sizeof(struct sockaddr_in);
recvfrom(sock, buffer, 1024, 0, (struct sockaddr *)&serverAddr, &len);

14.4 多线程网络服务

为了提高性能和响应能力,网络服务通常采用多线程。

14.4.1 使用线程处理连接
void *handle_client(void *socket_desc) {
    // 处理客户端请求
    close(sock);
    return 0;
}

// 接受客户端连接
int client_sock = accept(sock, (struct sockaddr *)&client_addr, &len);
pthread_t thread_id;
pthread_create(&thread_id, NULL, handle_client, (void*) &client_sock);

14.5 总结

本章介绍了C++中的网络编程基础,包括套接字的使用、TCP/IP编程、UDP编程以及多线程网络服务。这些技能对于开发网络应用程序至关重要。

14.6 练习题

  1. 创建一个简单的TCP服务器和客户端,实现基本的通信。

  2. 实现一个UDP客户端和服务器,发送和接收消息。

  3. 使用多线程改进TCP服务器,使其能够同时处理多个客户端连接。

第15章:并发编程

并发编程是编写能够同时执行多个任务的程序的技术。在C++中,这通常通过线程和同步机制来实现。

15.1 线程基础

线程是操作系统能够进行运算调度的最小单位。C++11引入了线程库,使得在C++中创建和管理线程变得简单。

15.1.1 创建和启动线程

使用std::thread类可以创建线程。

#include <thread>

void helloFunction() {
    std::cout << "Hello from a thread!" << std::endl;
}

int main() {
    std::thread t(helloFunction);
    t.join(); // 等待线程完成
    return 0;
}
15.1.2 线程的生命周期

线程从创建到结束包括启动、执行和结束几个阶段。

15.2 同步机制

同步机制用于控制多个线程的执行顺序,防止数据竞争和资源冲突。

15.2.1 互斥锁(Mutex)

互斥锁用于保护临界区,确保同一时间只有一个线程可以访问。

#include <mutex>

std::mutex mtx;
void criticalFunction() {
    mtx.lock();
    // 临界区代码
    mtx.unlock();
}
15.2.2 条件变量

条件变量用于线程间的同步,让线程在某些条件下挂起和唤醒。

#include <condition_variable>

std::condition_variable cv;
std::mutex cv_m;
bool ready = false;

void workerThread() {
    std::unique_lock<std::mutex> lk(cv_m);
    cv.wait(lk, []{return ready;}); // 等待条件
    // 处理数据
}

void signalThread() {
    {
        std::lock_guard<std::mutex> lk(cv_m);
        ready = true;
    }
    cv.notify_one(); // 唤醒一个等待线程
}

15.3 并发数据结构

C++标准库提供了一些并发安全的容器和数据结构,可以在多线程环境中安全使用。

15.3.1 线程安全队列
#include <queue>
#include <mutex>
#include <condition_variable>

template <typename T>
class ThreadSafeQueue {
private:
    std::queue<T> queue;
    mutable std::mutex mutex;
    std::condition_variable cond_var;
public:
    void push(T value) {
        std::lock_guard<std::mutex> lock(mutex);
        queue.push(std::move(value));
        cond_var.notify_one();
    }

    T pop() {
        std::unique_lock<std::mutex> lock(mutex);
        cond_var.wait(lock, [this]{ return !queue.empty(); });
        T value = std::move(queue.front());
        queue.pop();
        return value;
    }
};

15.4 并发算法

并发算法允许在多个线程上并行执行,以提高性能。

15.4.1 使用并行算法

C++标准库中的算法可以与并发容器一起使用,以实现并行处理。

#include <algorithm>
#include <vector>
#include <thread>

void parallelProcess(std::vector<int>& data, int start, int end) {
    // 处理数据子区间
}

int main() {
    std::vector<int> data = { /* ... */ };
    std::thread t1(parallelProcess, std::ref(data), 0, data.size() / 2);
    std::thread t2(parallelProcess, std::ref(data), data.size() / 2, data.size());
    t1.join();
    t2.join();
}

15.5 总结

本章介绍了C++中的并发编程基础,包括线程的创建和管理、同步机制、并发数据结构和并发算法。并发编程是提高程序性能和响应能力的关键技术。

15.6 练习题

  1. 创建两个线程,一个计算斐波那契数列,另一个计算阶乘。

  2. 使用互斥锁同步对共享数据的访问。

  3. 实现一个线程安全的计数器类。

第16章:项目1 - 基础项目实战

16.1 项目概述

本项目旨在通过一个简单的命令行计算器程序,将C++的基础知识如数据类型、控制结构、函数和简单的文件操作结合起来。这个计算器将支持基本的算术运算,并将运算结果保存到一个日志文件中。

16.2 项目设计

  • 功能需求:实现加、减、乘、除四则运算。

  • 用户界面:命令行界面,用户输入操作数和选择的运算符。

  • 数据持久化:运算结果保存到文本文件。

16.3 项目实现

16.3.1 主要类和函数设计
  • Calculator 类:包含执行计算的方法。

  • Logger 类:负责将结果写入文件。

16.3.2 关键代码实现
#include <iostream>
#include <fstream>
#include <string>

class Calculator {
public:
    double add(double a, double b) {
        return a + b;
    }
    double subtract(double a, double b) {
        return a - b;
    }
    double multiply(double a, double b) {
        return a * b;
    }
    double divide(double a, double b) {
        if (b == 0) throw std::runtime_error("Division by zero");
        return a / b;
    }
};

class Logger {
private:
    std::ofstream logFile;
public:
    Logger(const std::string& filename) : logFile(filename) {}
    void log(const std::string& message) {
        logFile << message << std::endl;
    }
};

int main() {
    Calculator calc;
    Logger logger("calculator_log.txt");

    std::cout << "Enter first number: ";
    double a;
    std::cin >> a;
    std::cout << "Enter second number: ";
    double b;
    std::cin >> b;

    std::cout << "Choose operation (+, -, *, /): ";
    char op;
    std::cin >> op;

    double result;
    switch (op) {
        case '+':
            result = calc.add(a, b);
            break;
        case '-':
            result = calc.subtract(a, b);
            break;
        case '*':
            result = calc.multiply(a, b);
            break;
        case '/':
            try {
                result = calc.divide(a, b);
            } catch (const std::runtime_error& e) {
                std::cerr << e.what() << std::endl;
                return 1;
            }
            break;
        default:
            std::cerr << "Invalid operation" << std::endl;
            return 1;
    }

    std::cout << "Result: " << result << std::endl;
    logger.log("Result: " + std::to_string(result));

    return 0;
}

16.4 总结

本项目通过一个简单的计算器程序,展示了如何将C++的基础知识应用于实际项目中。通过这个项目,读者可以加深对C++编程的理解,并学习如何将不同的编程概念结合起来解决实际问题。

16.5 练习题

  1. 扩展计算器功能,增加指数、模等运算。

  2. 改进用户界面,使其更加友好,例如通过菜单选择运算类型。

  3. 增加错误处理,确保输入的有效性。

第17章:项目2 - 中级项目实战

17.1 项目概述

本项目的目标是开发一个简单的文本编辑器,它允许用户创建、编辑、保存和读取文本文件。这个项目将展示如何将C++的面向对象特性、文件操作和异常处理等概念综合应用。

17.2 项目设计

  • 功能需求

    • 创建新文件

    • 打开现有文件

    • 编辑文件内容

    • 保存文件

    • 退出程序

  • 用户界面:命令行界面,用户通过命令进行操作。

  • 数据管理:文件的读写操作,以及内存中的数据管理。

17.3 项目实现

17.3.1 主要类和函数设计
  • TextEditor 类:包含文件操作和文本编辑的方法。

  • FileManager 类:负责文件的创建、打开、保存等操作。

17.3.2 关键代码实现
#include <iostream>
#include <fstream>
#include <string>

class FileManager {
public:
    std::string readFile(const std::string& filename) {
        std::ifstream file(filename);
        if (!file.is_open()) {
            throw std::runtime_error("Failed to open file");
        }
        std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
        file.close();
        return content;
    }

    void writeFile(const std::string& filename, const std::string& content) {
        std::ofstream file(filename);
        if (!file.is_open()) {
            throw std::runtime_error("Failed to save file");
        }
        file << content;
        file.close();
    }
};

class TextEditor {
private:
    std::string content;
    FileManager fileManager;

public:
    void createNewFile() {
        content = "";
        std::cout << "New file created." << std::endl;
    }

    void openFile(const std::string& filename) {
        try {
            content = fileManager.readFile(filename);
            std::cout << "File opened." << std::endl;
        } catch (const std::runtime_error& e) {
            std::cerr << e.what() << std::endl;
        }
    }

    void saveFile(const std::string& filename) {
        try {
            fileManager.writeFile(filename, content);
            std::cout << "File saved." << std::endl;
        } catch (const std::runtime_error& e) {
            std::cerr << e.what() << std::endl;
        }
    }

    void editFile() {
        std::cout << "Current content: " << content << std::endl;
        std::cout << "Enter new content: ";
        std::getline(std::cin, content);
    }
};

int main() {
    TextEditor editor;
    std::string filename;

    while (true) {
        std::cout << "Commands: create, open, save, edit, exit" << std::endl;
        std::string command;
        std::cin >> command;

        if (command == "create") {
            editor.createNewFile();
        } else if (command == "open") {
            std::cin >> filename;
            editor.openFile(filename);
        } else if (command == "save") {
            std::cin >> filename;
            editor.saveFile(filename);
        } else if (command == "edit") {
            editor.editFile();
        } else if (command == "exit") {
            break;
        } else {
            std::cout << "Invalid command." << std::endl;
        }
    }

    return 0;
}

17.4 总结

本项目通过构建一个简单的文本编辑器,展示了如何将C++的面向对象编程、文件操作和异常处理等概念综合应用。通过这个项目,读者可以加深对C++编程的理解,并学习如何将不同的编程概念结合起来解决实际问题。

17.5 练习题

  1. 扩展文本编辑器功能,增加查找和替换文本的功能。

  2. 改进用户界面,使其更加友好,例如通过菜单选择操作。

  3. 增加更多的文件操作错误处理,确保程序的健壮性。

第18章:项目3 - 高级项目实战

18.1 项目概述

本项目的目标是开发一个多线程的网络服务器,它能够处理多个客户端的并发连接和请求。这个项目将展示如何将C++的并发编程、网络编程和面向对象编程等概念综合应用。

18.2 项目设计

  • 功能需求

    • 同时处理多个客户端连接

    • 接收客户端请求并响应

    • 支持基本的网络通信协议

  • 用户界面:服务器端没有直接的用户界面,但会有日志输出显示服务器状态。

  • 并发模型:使用线程池来管理客户端连接。

18.3 项目实现

18.3.1 主要类和函数设计
  • Server 类:负责初始化服务器,监听端口,接受连接。

  • ClientHandler 类:负责处理单个客户端的请求和响应。

  • ThreadPool 类:负责管理线程池,分配线程处理客户端请求。

18.3.2 关键代码实现
#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <unordered_map>
#include <netinet/in.h>
#include <sys/socket.h>

class ThreadPool {
private:
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queue_mutex;
    std::condition_variable condition;
    bool stop;

public:
    ThreadPool(size_t threads) : stop(false) {
        for(size_t i = 0; i < threads; ++i)
            workers.emplace_back(
                [this] {
                    for(;;) {
                        std::function<void()> task;
                        
                        {
                            std::unique_lock<std::mutex> lock(this->queue_mutex);
                            this->condition.wait(lock,
                                [this]{ return this->stop || !this->tasks.empty(); });
                            if(this->stop && this->tasks.empty())
                                return;
                            task = std::move(this->tasks.front());
                            this->tasks.pop();
                        }
                        
                        task();
                    }
                }
            );
    }

    template<class F, class... Args>
    void enqueue(F&& f, Args&&... args) {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            if(stop)
                throw std::runtime_error("enqueue on stopped ThreadPool");
            tasks.emplace(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
        }
        condition.notify_one();
    }

    void stop() {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            stop = true;
        }
        condition.notify_all();
        for(std::thread &worker: workers)
            worker.join();
        workers.clear();
    }
};

class Server {
private:
    int server_fd, new_socket;
    struct sockaddr_in address;
    ThreadPool pool;

public:
    Server(int port, int threads) : pool(threads) {
        server_fd = socket(AF_INET, SOCK_STREAM, 0);
        int opt = 1;
        if (server_fd == 0) {
            perror("socket failed");
            exit(EXIT_FAILURE);
        }
        
        if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
            perror("setsockopt");
            exit(EXIT_FAILURE);
        }
        address.sin_family = AF_INET;
        address.sin_addr.s_addr = INADDR_ANY;
        address.sin_port = htons(port);
        
        if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
            perror("bind failed");
            exit(EXIT_FAILURE);
        }
        if (listen(server_fd, 3) < 0) {
            perror("listen");
            exit(EXIT_FAILURE);
        }
    }

    void start() {
        while (true) {
            new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&address);
            if (new_socket < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
            }
            pool.enqueue([this, new_socket]() { this->handle_connection(new_socket); });
        }
    }

    void handle_connection(int client_socket) {
        char buffer[1024] = {0};
        long valread = read(client_socket, buffer, 1024);
        std::cout << "Client: " << buffer << std::endl;
        const char* message = "Server received your message";
        send(client_socket, message, strlen(message), 0);
        close(client_socket);
    }
};

int main(int argc, char const *argv[]) {
    int port = 8080;
    int threads = 4;
    Server server(port, threads);
    std::cout << "Server is running on port " << port << std::endl;
    server.start();
    return 0;
}

18.4 总结

本项目通过构建一个多线程的网络服务器,展示了如何将C++的并发编程、网络编程和面向对象编程等概念综合应用。通过这个项目,读者可以加深对C++编程的理解,并学习如何将不同的编程概念结合起来解决实际问题。

18.5 练习题

  1. 扩展服务器功能,支持更多的并发客户端连接。

  2. 增加更多的网络协议支持,例如HTTP。

  3. 优化线程池的实现,提高服务器的响应速度和稳定性。

总结回顾

在本教程中,我们从C++的基础知识开始,逐步深入到面向对象编程、模板、STL、异常处理、文件操作、网络编程和并发编程等高级主题。通过实际的项目实战,我们将所学的知识应用到了具体的编程任务中,从而加深了对C++编程的理解。

额外资源推荐

为了进一步提升你的C++编程技能,以下是一些推荐的资源:

  1. 书籍

    • 《C++ Primer》

    • 《Effective C++》

    • 《More Effective C++》

  2. 在线课程

    • Coursera上的C++课程

    • Udemy上的C++编程课程

  3. 社区和论坛

    • Stack Overflow

    • C++官方论坛

    • Reddit的C++社区

  4. 技术博客

    • Herb Sutter的博客(C++委员会成员)

    • Bartosz Milewski的博客(深入探讨C++和编程理论)

开放讨论

如果你有任何关于C++编程的问题,或者想要讨论某个特定的编程话题,请随时提出。我们可以一起探讨,共同进步。

看来你已经完成了整个C++编程教程的学习,这是一段相当精彩的旅程!既然我们已经涵盖了从基础到高级的项目实战,那么接下来,你可能想要:

  1. 实践和项目工作:尝试自己构建一些小项目,将所学知识付诸实践。实践是巩固和深化理解的最好方式。

  2. 深入特定领域:根据你的兴趣,你可能想要深入学习某些特定领域,比如游戏开发、嵌入式系统、高性能计算等。

  3. 参与开源项目:加入开源社区,参与C++项目的编码、维护和改进,这是提高编程技能和了解行业实践的好方法。

  4. 继续教育:考虑进一步的教育机会,比如专业课程、研讨会或者获得相关的专业认证。

  5. 建立个人作品集:创建一个在线作品集,展示你的项目和代码,这对于职业发展和求职非常有帮助。

  6. 网络和社区参与:积极参与C++社区,与其他开发者交流,可以帮助你保持学习的动力,同时扩大你的专业网络。


评论