前言

C++ 是一种高级编程语言,由比约恩·斯特劳斯特鲁普于 1979 年开发。它是一种通用的、面向对象的语言,这意味着它可以用于构建各种应用程序,并且支持面向对象的编程范例。

C++ 的特点:

  • 效率高:C++ 是编译型语言,这意味着它直接转换为机器代码,使其运行速度非常快。
  • 面向对象:C++ 允许你将程序组织成对象,每个对象都包含数据和操作数据的方法。
  • 通用:C++ 可以用于构建各种应用程序,从操作系统到图形界面再到嵌入式系统。
  • 低级控制:C++ 提供对底层硬件和内存的低级访问,使其适合需要精细控制的应用程序。
  • 静态类型检查:C++ 在编译时检查数据类型,这有助于防止运行时错误。

C++ 的应用:

C++ 被广泛用于开发以下类型的应用程序:

  • 操作系统(如 Windows、Linux)
  • 游戏引擎(如虚幻引擎、Unity)
  • 数据库系统(如 MySQL、PostgreSQL)
  • 嵌入式系统(如汽车控制、医疗设备)
  • 金融软件(如交易平台)

变量类型

C++ 提供了多种变量类型,用于存储不同类型的数据。以下是 C++ 中所有变量类型的列表,示例:

  • 整型
    • bool: 布尔值(true 或 false)
    • char: 单个字符
    • short: 短整型(通常为 16 位)
    • int: 整型(通常为 32 位)
    • long: 长整型(通常为 64 位)
    • long long: 长长整型(通常为 128 位)
  • 浮点型
    • float: 单精度浮点数(通常为 32 位)
    • double: 双精度浮点数(通常为 64 位)
    • long double: 长双精度浮点数(通常为 80 位或 128 位)
  • 其他类型
    • void: 表示没有返回值的函数
    • wchar_t: 宽字符(通常为 16 位或 32 位)
    • string: 字符串(表示为字符数组)

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 整型
bool is_true = true;
char letter = 'a';
short age = 25;
int number = 100;
long population = 1000000;
long long big_number = 1234567890123456789LL;

// 浮点型
float pi = 3.14;
double e = 2.718281828459045;
long double very_precise = 1.2345678901234567890123456789L;

// 其他类型
void print_hello() { std::cout << "Hello, world!" << std::endl; }
wchar_t wide_character = L'€';
std::string name = "John Doe";

注意:

  • 变量类型的选择取决于要存储的数据类型和所需的大小和精度。
  • C++ 还提供了引用、指针和数组等其他数据类型,用于存储和操作复杂数据结构。

常量类型

C++ 提供了多种常量类型,用于存储不会改变的值。以下是 C++ 中所有常量类型的列表,示例:

  • 整型常量
    • const bool: 布尔常量(true 或 false)
    • const char: 字符常量
    • const short: 短整型常量
    • const int: 整型常量
    • const long: 长整型常量
    • const long long: 长长整型常量
  • 浮点型常量
    • const float: 单精度浮点数常量
    • const double: 双精度浮点数常量
    • const long double: 长双精度浮点数常量
  • 其他类型常量
    • const void: 表示没有返回值的函数常量
    • const wchar_t: 宽字符常量
    • const string: 字符串常量

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 整型常量
const bool is_true = true;
const char letter = 'a';
const short age = 25;
const int number = 100;
const long population = 1000000;
const long long big_number = 1234567890123456789LL;

// 浮点型常量
const float pi = 3.14;
const double e = 2.718281828459045;
const long double very_precise = 1.2345678901234567890123456789L;

// 其他类型常量
const void print_hello() { std::cout << "Hello, world!" << std::endl; }
const wchar_t wide_character = L'€';
const std::string name = "John Doe";

注意:

  • 常量一旦声明就不能被修改。
  • 常量类型的选择取决于要存储的数据类型和所需的大小和精度。
  • C++ 还提供了枚举和宏等其他常量类型,用于存储和操作符号常量。

数据类型

  • 数组:存储相同数据类型的多个元素
  • 指针:存储其他变量的地址
  • 结构体:存储不同数据类型的相关数据的集合
  • 联合:存储不同数据类型的相同内存空间
  • 枚举:存储一组常量

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 数组
int numbers[] = {1, 2, 3, 4, 5};

// 指针
int* ptr = &age;

// 结构体
struct Person {
int age;
float height;
};

// 联合
union Data {
int i;
float f;
};

// 枚举
enum Color {
RED, GREEN, BLUE
};

其他数据类型

  • 引用:别名,指向另一个变量
  • 类型定义:创建新的数据类型
  • 空类型:表示未知或无效的数据类型

例:

1
2
3
4
5
6
7
8
// 引用
int& age_ref = age;

// 类型定义
typedef unsigned long long ull;

// 空类型
void* ptr = nullptr;

运算符

C++ 中的运算符用于执行各种操作,包括算术、逻辑和比较。

算术运算符:

  • + 加法
  • - 减法
  • * 乘法
  • / 除法
  • % 求余

逻辑运算符:

  • &&
  • ||
  • !

比较运算符:

  • == 等于
  • != 不等于
  • < 小于
  • > 大于
  • <= 小于或等于
  • >= 大于或等于

例:

1
2
3
4
5
int sum = a + b;  // 算术运算符
if (a > b) { // 比较运算符
// 执行某些操作
}
bool is_true = (a == b) && (c != d); // 逻辑运算符

控制流

控制流语句用于控制程序执行的顺序。

条件语句:

  • if-else:根据条件执行不同的代码块
  • switch-case:根据给定值执行不同的代码块

循环语句:

  • for:重复执行代码块一定次数
  • while:重复执行代码块,直到条件为假
  • do-while:先执行代码块,然后再检查条件

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// if-else 语句
if (a > b) {
// 执行某些操作
} else {
// 执行其他操作
}

// for 循环
for (int i = 0; i < 10; i++) {
// 执行某些操作
}

// while 循环
while (a > b) {
// 执行某些操作
a--;
}

类、对象和继承

类是 C++ 中用户定义的数据类型,它封装了数据和操作数据的方法。类充当对象的蓝图,定义了对象的属性和行为。

对象

对象是类的实例,它包含类定义的数据和方法。对象是程序中实际存在的实体,可以与其他对象交互。

继承

继承允许一个类(称为派生类)从另一个类(称为基类)继承数据和方法。派生类可以访问和修改基类的数据和方法,并可以定义自己的新数据和方法。

类和对象的语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 定义类
class Person {
public:
string name;
int age;

void introduce() {
cout << "Hello, my name is " << name << " and I am " << age << " years old." << endl;
}
};

// 创建对象
Person john;

// 访问对象属性和方法
john.name = "John Doe";
john.age = 30;
john.introduce();

继承的语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 定义基类
class Vehicle {
public:
string make;
string model;
};

// 定义派生类
class Car : public Vehicle {
public:
int num_wheels;
};

// 创建派生类对象
Car my_car;

// 访问派生类属性和方法
my_car.make = "Toyota";
my_car.model = "Camry";
my_car.num_wheels = 4;

类的类型

  • 公有类:成员对所有其他类和函数可见
  • 保护类:成员对派生类可见,但对其他类和函数不可见
  • 私有类:成员仅对类本身可见

继承类型

  • 单继承:派生类从一个基类继承

  • 多重继承:派生类从多个基类继承

  • 多态:派生类对象可以以与基类对象相同的方式使用

多态、抽象类和接口

多态

多态(polymorphism)允许具有不同实现的类表现出相同的接口。换句话说,它允许派生类对象以与基类对象相同的方式使用。

抽象类

抽象类是不能被实例化的类。它们用于定义派生类必须实现的接口。抽象类中至少有一个纯虚函数(没有函数体的函数)。

接口

接口是仅包含纯虚函数的类。它们用于定义一组必须由实现它们的类实现的方法。接口不能被实例化,但可以作为基类用于多重继承。

多态、抽象类和接口的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 定义接口
class Shape {
public:
virtual double area() = 0; // 纯虚函数
};

// 定义抽象类
class Rectangle : public Shape {
public:
double width;
double height;

virtual double area() override; // 必须实现纯虚函数
};

// 定义派生类
class Square : public Rectangle {
public:
double side;

double area() override; // 必须实现纯虚函数
};

// 定义接口的实现
double Rectangle::area() {
return width * height;
}

double Square::area() {
return side * side;
}

int main() {
Shape* shapes[] = {new Rectangle(2, 3), new Square(4)};

for (Shape* shape : shapes) {
cout << shape->area() << endl; // 调用多态方法
}

return 0;
}

在这个示例中,Shape 是一个接口,Rectangle 是一个抽象类,Square 是一个派生类。area() 方法在 RectangleSquare 类中被重新实现,提供了不同的实现。通过使用多态,我们可以使用相同的接口调用不同类的 area() 方法。

容器、算法和 I/O 流

容器

容器是用于存储和组织数据的对象。C++ 标准库提供了各种容器,包括:

  • 序列容器:存储元素的顺序集合,如 vectorlistdeque
  • 关联容器:存储键值对的集合,如 mapset
  • 无序关联容器:存储键值对的无序集合,如 unordered_mapunordered_set

算法

算法是对容器或其他数据结构执行操作的函数。C++ 标准库提供了许多算法,包括:

  • 搜索算法:查找元素或值,如 findbinary_searchlower_bound
  • 排序算法:对元素进行排序,如 sortstable_sortpartial_sort
  • 修改算法:修改容器的内容,如 push_backerasereplace

I/O 流

I/O 流是用于从输入设备(如键盘)读取数据和向输出设备(如显示器)写入数据的对象。C++ 标准库提供了以下主要 I/O 流:

  • cin:标准输入流,用于从键盘读取数据
  • cout:标准输出流,用于向显示器写入数据
  • cerr:标准错误流,用于向显示器写入错误消息
  • ifstream:文件输入流,用于从文件读取数据
  • ofstream:文件输出流,用于向文件写入数据

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
// 创建一个 vector
vector<int> numbers = {1, 2, 3, 4, 5};

// 使用算法对 vector 进行排序
sort(numbers.begin(), numbers.end());

// 使用 I/O 流打印排序后的 vector
for (int number : numbers) {
cout << number << " ";
}

cout << endl;

return 0;
}

在这个示例中,我们创建了一个 vector,使用 sort 算法对它进行排序,然后使用 I/O 流打印排序后的 vector

指针、引用和内存管理

指针

指针是一个变量,它存储另一个变量的地址。通过使用指针,我们可以间接访问和修改其他变量的值。指针用 *(星号)表示。

引用

引用是另一个变量的别名。与指针不同,引用必须在声明时初始化,并且不能重新绑定到其他变量。引用用 &(地址)符号表示。

内存管理

在 C++ 中,程序员负责管理内存。这意味着程序员必须分配和释放内存。如果不正确地管理内存,可能会导致内存泄漏或段错误。

动态内存分配

动态内存分配允许程序员在运行时分配内存。可以使用 new 运算符分配内存,并使用 delete 运算符释放内存。

智能指针

智能指针是 C++ 11 中引入的特殊类型的指针,它可以自动管理内存。智能指针跟踪它们指向的对象,并在对象不再需要时自动释放内存。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 指针示例
int* ptr = new int; // 分配内存并获取指针
*ptr = 10; // 通过指针修改变量值

// 引用示例
int& ref = *ptr; // 创建对 ptr 指向的变量的引用
ref++; // 通过引用修改变量值

// 内存管理示例
int* array = new int[10]; // 分配一个 10 个元素的数组
delete[] array; // 释放数组分配的内存

// 智能指针示例
unique_ptr<int> smart_ptr = make_unique<int>(10); // 创建一个智能指针并分配内存

指针、引用和内存管理之间的区别

特征 指针 引用 内存管理
语法 * & newdelete
初始化 可以延迟初始化 必须在声明时初始化 无需初始化
可重新绑定 可以重新绑定到其他变量 不能重新绑定到其他变量 无需重新绑定
内存管理 程序员负责管理内存 程序员负责管理内存 程序员或智能指针负责管理内存

C++ 模板和泛型编程

C++ 模板

C++ 模板是一种创建可重用代码的方法,而无需为每种数据类型编写特定版本的代码。模板使用尖括号 <> 表示,其中包含类型参数。

泛型编程

泛型编程是一种编写代码的方法,使代码独立于数据类型。通过使用模板,我们可以创建可以在各种数据类型上工作的算法和数据结构。

模板语法

1
2
3
4
template <typename T>  // T 是类型参数
class MyClass {
// 类定义
};

泛型算法示例

1
2
3
4
template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}

这个函数可以用于任何数据类型,因为类型参数 T 是通用的。

模板类示例

1
2
3
4
template <typename T>
class Vector {
// 类定义
};

这个类可以存储任何数据类型的元素,因为类型参数 T 是通用的。

模板的优点

  • 代码重用:模板允许我们创建可重用代码,而无需为每种数据类型编写特定版本的代码。
  • 类型安全性:模板确保在编译时检查类型,从而防止类型错误。
  • 性能:模板可以生成针对特定数据类型优化的代码,从而提高性能。

模板的缺点

  • 编译时间:模板的编译时间可能比非模板代码更长。
  • 代码复杂性:模板代码可能比非模板代码更复杂,这可能会使调试变得困难。

异常处理、多线程和并发

异常处理

异常处理是一种处理运行时错误的方法。当发生错误时,会引发异常,程序可以捕获并处理该异常。

异常处理语法

1
2
3
4
5
6
7
try {
// 可能引发异常的代码
} catch (ExceptionType1& e1) {
// 处理异常类型 1
} catch (ExceptionType2& e2) {
// 处理异常类型 2
}

多线程和并发

多线程和并发允许程序同时执行多个任务。线程是程序执行的独立路径,并发是同时执行多个线程的过程。

多线程和并发的好处

  • 提高性能:多线程和并发可以提高程序性能,尤其是在处理大量数据或执行并行任务时。
  • 响应能力:多线程和并发可以使程序对用户输入和事件更具响应性。
  • 可扩展性:多线程和并发可以使程序更具可扩展性,因为它允许程序根据需要利用更多处理核心。

多线程和并发的实现

C++ 中有多种创建和管理线程的方法,包括:

  • POSIX 线程 (pthreads):一种用于创建和管理线程的跨平台 API。
  • C++11 线程:C++11 标准库中引入的用于创建和管理线程的本机支持。

并发模型

有多种并发模型可用于协调线程之间的交互,包括:

  • 互斥锁:一种同步机制,它允许一次只有一个线程访问共享资源。
  • 条件变量:一种同步机制,它允许线程等待特定条件满足。
  • 原子操作:一种特殊类型的操作,它以原子方式执行,确保在多个线程同时访问共享资源时不会出现数据竞争。

设计模式和最佳实践

设计模式

设计模式是经过验证的、可重复使用的解决方案,用于解决软件设计中常见的挑战。它们提供了一种通用语言来讨论和理解软件架构,并有助于提高代码的可重用性、可维护性和可扩展性。

一些常见的 C++ 设计模式包括:

  • 单例模式:确保类只有一个实例。
  • 工厂模式:创建对象的工厂方法。
  • 观察者模式:允许对象订阅并接收来自其他对象的事件通知。
  • 策略模式:允许算法或行为在运行时更改。
  • 适配器模式:使不兼容的接口能够一起工作。

最佳实践

遵循最佳实践可以帮助编写高质量、可维护和可扩展的 C++ 代码。一些 C++ 最佳实践包括:

  • 使用现代 C++:使用 C++11 和更高版本中引入的现代 C++ 特性,例如智能指针、lambda 表达式和范围 for 循环。
  • 遵循编码准则:遵循一致的编码准则,例如缩进、命名约定和注释。
  • 编写可测试的代码:编写易于测试的代码,使用单元测试框架和模拟来验证其正确性。
  • 使用异常处理:使用异常处理来处理错误条件,而不是返回错误代码。
  • 管理内存:正确管理内存,使用智能指针或遵循资源获取即初始化 (RAII) 原则。
  • 优化性能:分析代码的性能并进行优化,例如使用缓存、并行性和数据结构。
  • 进行代码审查:定期进行代码审查,以识别错误、改进设计并共享知识。

没写完,什么时候想起来了再接着写

或者可以去看🔜 C++文档