C++ 教程(最新、最全、3.5万字总结),强烈建议收藏!!!
半笺寄怀 2024-06-25 15:35:04 阅读 88
一、前言
1、介绍
C++是一门历史悠久且广泛应用的编程语言,它在系统级编程、游戏开发、嵌入式系统、高性能计算和大规模软件开发等领域发挥着重要作用。C++起源于C语言,由Bjarne Stroustrup于1983年开发,最初是为了增强C语言的功能性而设计的。随着时间的推移,C++逐渐演变为一门多范式编程语言,结合了面向对象编程、泛型编程和低级操作的特性。
2、C++与其他编程语言的关系
C++与C语言有着紧密的关联性。事实上,C++可以看作是对C语言的扩展,提供了更多的功能和抽象层次。C++保留了C语言的核心特性,如高效性、直接内存访问和底层控制,同时引入了面向对象编程的概念,使得开发者能够更好地组织和管理代码。此外,C++还借鉴了其他编程语言的一些概念和特性,例如Java的垃圾回收机制和Python的动态类型。然而,与其他语言相比,C++在性能和底层操作方面具有独特的优势。
3、对比C++与其他语言的价值
对比C++与其他编程语言的差异对于有经验的开发者来说具有重要的价值。这样的对比可以帮助开发者更好地理解C++的设计哲学、优势和适用场景。以下是一些原因,解释为什么对比C++与其他语言对于有经验的开发者很有价值:
扩展技能和视野:通过学习和比较不同编程语言的差异,开发者可以拓宽自己的技能和视野。这样的对比可以让开发者更加灵活地选择适合特定任务的编程语言,从而提高开发效率和代码质量。
利用C++的独特特性:了解C++与其他语言的差异,可以帮助开发者更好地利用C++的独特特性。例如,通过对比Java和C++,开发者可以学习到C++的指针和引用的使用,以及对内存的直接控制,从而编写更高效的代码。
优化性能和资源利用:C++是一门注重性能和资源利用的语言。通过对比C++与其他
语言的差异,开发者可以了解C++的编译优化、内联函数、模板和低级操作等特性,从而编写更高效的代码,满足对性能和资源的苛刻要求。
二、C++与其他语言的基本语法和语义差异
C++与其他编程语言在基本语法和语义方面存在一些差异。在本节中,我们将比较C++与其他语言在变量声明、控制流、函数定义等方面的差异。这将帮助开发者更好地理解C++的语法和语义,并能够顺利地将已有的编程知识应用到C++中。
1. 变量声明
在C++中,变量的声明需要指定其类型,并且可以选择性地进行初始化。与其他动态类型语言相比,如Python和JavaScript,C++是一门静态类型语言,变量在声明时需要明确指定其类型。例如,以下是一个C++中整型变量的声明和初始化的示例:
int num = 10;
与之相比,一些动态类型语言允许在变量声明时省略类型,并根据赋值自动推断类型。
2. 控制流
C++的控制流语句与其他语言的差异在于语法和语义上的细微差别。例如,C++使用大括号 {}
来定义代码块,而其他语言可能使用缩进或关键字来表示代码块。此外,C++中的条件语句使用关键字 if
、else
和 switch
,循环语句使用关键字 for
、while
和 do-while
。虽然这些控制流语句的基本概念相似,但具体的语法和语义可能有所不同。
3. 函数定义
C++的函数定义与其他语言的函数定义也存在一些差异。C++使用函数头和函数体的组合来定义函数。函数头包括返回类型、函数名和参数列表,而函数体则包含实际的函数实现。
在C++中,函数可以被重载,这意味着可以定义具有相同名称但不同参数列表的多个函数。编译器根据调用时提供的参数数量和类型来确定要调用的具体函数。以下是一个函数重载的示例:
// 重载的函数 add
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
在上面的示例中,我们定义了两个名为 add
的函数,一个接收两个整型参数,另一个接收两个浮点型参数。根据调用时提供的参数类型,编译器会自动选择调用合适的函数。
此外,C++还支持默认参数,这意味着在函数定义中可以为某些参数提供默认值。如果调用函数时没有显式提供这些参数的值,将使用默认值。以下是一个具有默认参数的函数示例:
// 带有默认参数的函数
void printMessage(string message, int times = 1) {
for (int i = 0; i < times; i++) {
cout << message << endl;
}
}
在上述示例中,我们定义了一个名为 printMessage
的函数,它接收一个字符串参数 message
和一个整型参数 times
,times
参数有默认值为 1。这意味着如果在调用函数时省略了 times
参数,它将默认为 1。
当涉及C++与其他编程语言的基本语法和语义差异时,还有许多方面可以进行比较。以下是一些常见的差异和示例代码:
4. 数组和容器
C++与一些高级语言在数组和容器的表示和使用上存在差异。例如,与Python的动态列表相比,C++使用数组来存储和访问一组元素。以下是一个示例,展示了如何在C++中声明和使用数组:
int numbers[] = { 1, 2, 3, 4, 5};
int size = sizeof(numbers) / sizeof(numbers[0]);
for (int i = 0; i < size; i++) {
cout << numbers[i] << " ";
}
另一方面,C++还提供了丰富的容器类,如向量(vector)、链表(list)、映射(map)等。与其他语言相比,C++的容器类提供了更多的底层控制和性能优化。以下是一个使用C++向量的示例:
#include <vector>
using namespace std;
vector<int> numbers = { 1, 2, 3, 4, 5};
for (int i = 0; i < numbers.size(); i++) {
cout << numbers[i] << " ";
}
5. 内存管理
C++与许多高级语言在内存管理方面存在显著差异。在C++中,开发者需要显式地管理内存分配和释放。C++提供了操作符 new
和 delete
用于动态分配和释放内存。以下是一个使用 new
操作符动态分配内存的示例:
int* ptr = new int; // 动态分配一个整型变量的内存空间
*ptr = 10;
// 使用动态分配的内存
cout << *ptr << endl;
// 释放内存
delete ptr;
相比之下,一些高级语言如Java和C#提供了自动内存管理,通过垃圾回收机制自动释放不再使用的内存。
6. 异常处理
C++与其他一些语言在异常处理机制上存在差异。在C++中,异常处理使用 try
、catch
和 throw
来捕获和处理异常。以下是一个示例,展示了如何在C++中使用异常处理:
try {
// 可能引发异常的代码
throw runtime_error("Something went wrong."); // 抛出异常
}
catch (const exception& ex) {
// 捕获并处理异常
cout << "Exception: " << ex.what() << endl;
}
与之相比,其他一些语言可能使用不同的语法和机制来处理异常,如Java中的 try
、catch
、finally
块。
三、C++语法详解
1.1 基本数据类型
当谈到变量和数据类型时,C++提供了多种基本数据类型,其中包括整型、浮点型、字符型和布尔型。让我们逐个进行详细讲解,并为每个数据类型提供示例代码。
C++中的整型数据类型用于表示整数值。以下是C++中常用的整型数据类型:
1.1.1 整型数据类型
int
: 表示带符号的整数,通常为32位(取决于编译器)。short
: 表示短整数,通常为16位(取决于编译器)。long
: 表示长整数,通常为32位(取决于编译器)。long long
: 表示更长的整数,通常为64位(取决于编译器)。
以下是使用整型数据类型的示例代码:
int age = 25;
short weight = 150;
long population = 1000000;
long long bigNumber = 123456789012345;
1.1.2 浮点型数据类型
C++中的浮点型数据类型用于表示带有小数部分的数字。以下是C++中常用的浮点型数据类型:
float
: 表示单精度浮点数,通常为32位(取决于编译器)。double
: 表示双精度浮点数,通常为64位(取决于编译器)。
以下是使用浮点型数据类型的示例代码:
float pi = 3.14;
double gravity = 9.8;
1.1.3 字符型数据类型
C++中的字符型数据类型用于表示单个字符。以下是C++中常用的字符型数据类型:
char
: 表示单个字符。
以下是使用字符型数据类型的示例代码:
char grade = 'A';
1.1.4 布尔型数据类型
C++中的布尔型数据类型用于表示逻辑值,只有两个取值:true
和false
。以下是使用布尔型数据类型的示例代码:
bool isPassed = true;
bool isValid = false;
当谈到变量和数据类型时,数组是一种重要的数据结构,用于存储一系列相同类型的元素。C++提供了数组数据类型,允许你有效地组织和访问多个元素。让我们深入探讨数组的各个方面,并提供示例代码来帮助你理解。
1.2 数组
数组是由相同类型的元素组成的集合。每个元素在数组中都有一个唯一的索引,用于访问和操作元素。以下是使用数组的一些基本概念和操作:
1.2.1 一维数组
一维数组是最简单的数组形式,它由一系列按顺序排列的元素组成。你可以通过指定数组大小和类型来创建一维数组。以下是一维数组的示例代码:
int numbers[5]; // 创建一个可以存储5个整数的一维数组
// 初始化数组元素
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
numbers[3] = 40;
numbers[4] = 50;
你还可以使用循环来访问和操作一维数组的元素,以避免重复的代码。以下是使用循环遍历一维数组的示例代码:
for (int i = 0; i < 5; i++) {
cout << numbers[i] << " ";
}
1.2.2 多维数组
多维数组是由多个一维数组组成的数组。它们以类似于矩阵的方式进行排列。你可以通过指定数组的行数和列数来创建多维数组。以下是一个二维数组的示例代码:
int matrix[3][3]; // 创建一个3x3的二维数组
// 初始化数组元素
matrix[0][0] = 1;
matrix[0][1] = 2;
matrix[0][2] = 3;
matrix[1][0] = 4;
matrix[1][1] = 5;
matrix[1][2] = 6;
matrix[2][0] = 7;
matrix[2][1] = 8;
matrix[2][2] = 9;
你可以使用嵌套的循环来遍历和操作多维数组的元素。以下是使用嵌套循环遍历二维数组的示例代码:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}
多维数组也可以有更多的维度,如三维数组、四维数组等。你可以根据需要创建和操作任意维度的多维数组。
你可以更有效地组织和处理大量的数据。在接下来的章节中,我们将继续讲解字符串和指针等其他数据类型。
1.3 字符串
字符串是由一系列字符组成的序列。在C++中,你可以使用字符数组或标准库提供的string
类来处理字符串。
1.3.1 字符串的定义和初始化
你可以使用字符数组来定义和初始化字符串。以下是使用字符数组定义和初始化字符串的示例代码:
char str1[6] = { 'H', 'e', 'l', 'l', 'o', '\0'};
char str2[] = "World";
上述代码中,str1
是一个包含6个字符的字符数组,最后一个字符是表示字符串结束的空字符(\0
)。str2
是根据字符串常量进行初始化的字符数组。
你还可以使用string
类来定义和初始化字符串。以下是使用string
类定义和初始化字符串的示例代码:
#include <string>
using namespace std;
string str3 = "Hello";
string str4("World");
上述代码中,str3
和str4
都是使用string
类进行定义和初始化的字符串。
1.3.2 字符串的输入和输出
在C++中,你可以使用输入流对象(cin
)来接收用户输入的字符串,使用输出流对象(cout
)来输出字符串。以下是使用输入和输出流来处理字符串的示例代码:
#include <iostream>
#include <string>
using namespace std;
string name;
cout << "请输入你的名字:";
cin >> name;
cout << "你好," << name << "!" << endl;
上述代码中,用户可以输入他们的名字,然后程序将输出一条问候消息。
1.3.3 字符串的操作
C++提供了许多用于操作字符串的函数和方法。以下是一些常见的字符串操作:
字符串拼接:使用+
运算符可以将两个字符串进行拼接。
string str1 = "Hello";
string str2 = "World";
string result = str1 + " " + str2; // "Hello World"
字符串比较:可以使用比较运算符(如==
、!=
、<
、>
等)来比较两个字符串的大小。
string str1 = "Hello";
string str2 = "World";
if (str1 == str2) {
cout << "两个字符串相等" << endl;
} else {
cout << "两个字符串不相等" << endl;
}
字符串长度:使用length()
或size()
函数可以获取字符串的长度。
string str = "Hello";
int length = str.length();
cout << "字符串长度为:" << length << endl;
当谈到变量和数据类型时,指针是一种重要的概念,允许你直接访问内存地址和操作数据。C++中的指针提供了灵活的方式来处理内存和数据。让我们深入了解指针的概念、操作和常见用法,并提供示例代码来帮助你更好地理解。
1.4 指针
指针是存储内存地址的变量。它们可以指向其他变量或数据,允许你直接访问和操作内存中的值。
1.4.1 指针的定义和初始化
在C++中,你可以使用以下语法来定义和初始化指针:
dataType* pointerName;
其中,dataType
是指针所指向的数据类型,pointerName
是指针的名称。
以下是定义和初始化指针的示例代码:
int* ptr; // 定义一个指向整数的指针
int number = 10;
ptr = &number; // 将指针指向变量number的地址
上述代码中,ptr
是一个指向整数的指针,使用&
运算符获取变量number
的地址,并将该地址赋值给指针ptr
。
1.4.2 指针的操作
指针提供了一些重要的操作符和用法,用于访问和操作内存中的数据。
解引用操作符(*
):可以使用解引用操作符来访问指针所指向的内存中的值。
int value = *ptr; // 通过指针解引用获取内存中的值
指针运算:可以对指针进行算术运算,如加法、减法等。
int* nextPtr = ptr + 1; // 指针加1,移动到下一个内存位置
空指针:可以使用空指针来表示指针不指向任何有效的内存地址。
int* nullPtr = nullptr; // 定义一个空指针
动态内存分配:使用new
关键字可以在运行时动态分配内存空间。
int* dynamicPtr = new int; // 动态分配一个整数大小的内存空间
*dynamicPtr = 20; // 在动态分配的内存空间中存储值
delete dynamicPtr; // 释放动态分配的内存空间
以上是关于指针的基本概念、操作和常见用法的讲解,并提供了一些示例代码。通过使用指针,你可以更灵活地处理内存和数据。
1.5 输入输出流
输入输出流是C++中处理输入和输出的机制。它们提供了与外部设备(如键盘、屏幕、文件等)进行交互的能力。
1.5.1 标准输入输出流
C++中有三个标准的输入输出流对象:
cin
:用于从标准输入设备(通常是键盘)读取输入。cout
:用于向标准输出设备(通常是屏幕)输出数据。cerr
:用于向标准错误设备输出错误信息。
1.5.2 输入操作
你可以使用cin
对象从用户处接收输入数据。以下是使用cin
进行输入的示例代码:
#include <iostream>
using namespace std;
int number;
cout << "请输入一个整数:";
cin >> number;
上述代码中,用户可以输入一个整数,然后使用cin
将其存储在变量number
中。
1.5.3 输出操作
你可以使用cout
对象输出数据到标准输出设备。以下是使用cout
进行输出的示例代码:
#include <iostream>
using namespace std;
int number = 10;
cout << "数字是:" << number << endl;
上述代码中,程序将输出一条消息,其中包含变量number
的值。
1.5.4 文件输入输出流
除了标准输入输出流,C++还提供了文件输入输出流,允许你读写文件中的数据。
文件输入流(ifstream
):用于从文件中读取数据。文件输出流(ofstream
):用于向文件中写入数据。文件输入输出流(fstream
):既可以读取文件中的数据,也可以写入数据到文件中。
以下是文件输入输出流的基本用法示例代码:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream outFile("data.txt"); // 打开文件用于写入数据
if (outFile.is_open()) {
outFile << "Hello, World!"; // 写入数据到文件
outFile.close(); // 关闭文件
} else {
cout << "无法打开文件" << endl;
}
ifstream inFile("data.txt"); // 打开文件用于读取数据
if (inFile.is_open()) {
string line;
while (getline(inFile, line)) {
cout << line << endl; // 输出文件中的数据
}
inFile.close(); // 关闭文件
} else {
cout << "无法打开文件" << endl;
}
return 0;
}
上述代码中,程序首先使用文件输出流(ofstream
)将数据写入
到文件data.txt
中,然后使用文件输入流(ifstream
)从该文件中读取数据并输出到控制台。
以上是关于输入输出流的基本概念、操作和用法的讲解,并提供了一些示例代码。通过使用输入输出流,你可以与用户交互、处理文件数据等。
1.6 控制流语句
控制流语句用于决定程序的执行流程。它们根据特定条件决定是否执行特定的代码块、多次执行代码块或跳转到特定位置。
1.6.1 条件语句
条件语句用于根据条件的真假执行不同的代码块。
if
语句:用于执行单个代码块,当条件为真时执行。
if (condition) {
// 执行当条件为真时的代码块
}
if-else
语句:用于执行两个代码块中的一个,根据条件的真假执行。
if (condition) {
// 执行当条件为真时的代码块
} else {
// 执行当条件为假时的代码块
}
if-else if-else
语句:用于执行多个代码块中的一个,根据多个条件的真假执行。
if (condition1) {
// 执行当条件1为真时的代码块
} else if (condition2) {
// 执行当条件2为真时的代码块
} else {
// 执行当所有条件都为假时的代码块
}
以下是条件语句的示例代码:
#include <iostream>
using namespace std;
int main() {
int number;
cout << "请输入一个整数:";
cin >> number;
if (number > 0) {
cout << "输入的数字是正数" << endl;
} else if (number < 0) {
cout << "输入的数字是负数" << endl;
} else {
cout << "输入的数字是零" << endl;
}
return 0;
}
上述代码中,根据用户输入的数字,程序使用条件语句判断输入的数字是正数、负数还是零,并输出相应的消息。
1.6.2 循环语句
循环语句用于重复执行一段代码,直到满足特定条件为止。
while
循环:在条件为真时重复执行代码块。
while (condition) {
// 重复执行的代码块
}
do-while
循环:先执行代码块,然后检查条件是否为真,如果为真则继续重复执行。
do {
// 重复执行的代码块
} while (condition);
for
循环:在指定的循环次
数内重复执行代码块。
for (initialization; condition; update) {
// 重复执行的代码块
}
以下是循环语句的示例代码:
#include <iostream>
using namespace std;
int main() {
int i = 0;
while (i < 5) {
cout << i << " ";
i++;
}
cout << endl;
do {
cout << i << " ";
i--;
} while (i > 0);
cout << endl;
for (int j = 0; j < 5; j++) {
cout << j << " ";
}
cout << endl;
return 0;
}
上述代码中,程序使用while
循环、do-while
循环和for
循环分别输出数字从0到4、从4到1和从0到4的序列。
1.6.3 跳转语句
跳转语句用于在程序中进行跳转操作,改变程序的执行顺序。
break
语句:用于跳出循环或switch
语句。
while (condition) {
// ...
if (condition) {
break; // 跳出循环
}
// ...
}
continue
语句:用于跳过当前循环的剩余代码,进入下一次循环。
while (condition) {
// ...
if (condition) {
continue; // 跳过当前循环的剩余代码,进入下一次循环
}
// ...
}
return
语句:用于从函数中返回结果并结束函数的执行。
int add(int a, int b) {
return a + b; // 返回结果并结束函数的执行
}
以上是关于控制流语句的详细讲解,并提供了一些示例代码。通过使用条件语句、循环语句和跳转语句,你可以根据特定的条件控制程序的执行流程。
1.7 字符串操作
在C++中,字符串是由字符组成的序列,用于存储和操作文本数据。C++提供了许多字符串操作函数和类,使你可以进行字符串的连接、比较、查找、截取等操作。
以下是一些常用的字符串操作:
字符串连接:
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1 = "Hello";
string str2 = "World";
string result = str1 + " " + str2;
cout << result << endl; // 输出:Hello World
return 0;
}
上述代码中,使用+
运算符将两个字符串连接在一起,并将结果存储在result
变量中。
字符串长度:
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "Hello";
int length = str.length();
cout << "字符串长度为:" << length << endl; // 输出:字符串长度为:5
return 0;
}
上述代码中,使用length()
函数获取字符串的长度,并将结果输出。
字符串比较:
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1 = "Hello";
string str2 = "World";
if (str1 == str2) {
cout << "字符串相等" << endl;
} else {
cout << "字符串不相等" << endl; // 输出:字符串不相等
}
return 0;
}
上述代码中,使用==
运算符比较两个字符串是否相等。
以上是一些常见的字符串操作示例,C++还提供了更多字符串操作函数和类,如查找子字符串、截取子字符串等。你可以根据需要使用适当的函数进行字符串处理。
1.8 文件操作
在编程中,读写文件是一项常见的任务。C++提供了文件输入输出流,使你可以打开、读取和写入文件中的数据。
以下是文件操作的基本步骤:
打开文件:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream outFile("data.txt"); // 打开文件用于写入数据
if (outFile.is_open()) {
// 写入数据到文件
outFile << "Hello, World!";
outFile.close(); // 关闭文件
} else {
cout << "无法打开文件" << endl;
}
return 0;
}
上述代码中,使用ofstream
类创建文件输出流,并打开文件data.txt
用于写入数据。
写入文件:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream outFile("data.txt");
if (outFile.is_open()) {
outFile
<< "Hello, World!";
outFile.close();
} else {
cout << "无法打开文件" << endl;
}
return 0;
}
上述代码中,使用<<
运算符将数据写入文件。
读取文件:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
ifstream inFile("data.txt"); // 打开文件用于读取数据
if (inFile.is_open()) {
string line;
while (getline(inFile, line)) {
cout << line << endl; // 输出文件中的每一行
}
inFile.close(); // 关闭文件
} else {
cout << "无法打开文件" << endl;
}
return 0;
}
上述代码中,使用ifstream
类创建文件输入流,并打开文件data.txt
用于读取数据。使用getline()
函数逐行读取文件中的数据,并将其输出到控制台。
以上是关于字符串操作和文件操作的简要讲解,并提供了一些示例代码。通过使用字符串操作和文件操作,你可以处理文本数据、读写文件等常见任务。
2、函数
当谈到函数时,它是一种用于封装可重复使用的代码块的重要工具。函数可以接受参数,执行特定的任务,并返回一个值(或不返回任何值)。在C++中,函数具有以下组成部分:函数头、函数体和返回值。
函数的定义和调用
函数的定义由函数头和函数体组成。函数头指定了函数的名称、参数列表和返回类型。函数体包含了函数的实际代码。
下面是一个简单的函数示例:
// 函数定义
int add(int a, int b) {
int sum = a + b;
return sum;
}
int main() {
// 函数调用
int result = add(3, 4);
cout << "结果是:" << result << endl;
return 0;
}
在上面的示例中,add()
函数接受两个整数参数 a
和 b
,并返回它们的和。main()
函数中调用了 add()
函数,并将返回值存储在 result
变量中,然后将结果输出到控制台。
函数参数
函数可以接受零个或多个参数。参数是函数定义中用于接受传递给函数的值的变量。在函数调用时,实际的值将传递给这些参数。
函数参数有两种传递方式:传值(by value)和传引用(by reference)。
传值参数:将参数的值复制给函数中的对应变量,函数内部对参数的修改不会影响原始变量。
void increment(int x) {
x++;
}
int main() {
int num = 5;
increment(num);
cout << "num 的值是:" << num << endl; // 输出:num 的值是:5
return 0;
}
传引用参数:通过引用传递参数,函数内部对参数的修改将影响原始变量。
void increment(int& x) {
x++;
}
int main() {
int num = 5;
increment(num);
cout << "num 的值是:" << num << endl; // 输出:num 的值是:6
return 0;
}
在上述示例中,increment()
函数通过传值和传引用两种方式进行参数传递。当传值方式调用函数时,对参数的修改不会影响原始变量的值。而当传引用方式调用函数时,对参数的修改会直接影响原始变量。
函数的返回值
函数可以返回一个值,也可以不返回任何值。在函数定义中,使用返回类型来指定函数返回的数据类型。使用 return
关键字来指定函数的返回值。
以下是一个返回值的函数示例:
int add(int a, int b) {
int sum = a + b;
return sum;
}
int main() {
int result = add(3, 4);
cout << "结果是:" << result << endl; // 输出:结果是:7
return 0;
}
``
`
在上述示例中,`add()` 函数返回两个整数的和,并将结果作为函数的返回值。在 `main()` 函数中,我们将返回值存储在 `result` 变量中,并将其输出到控制台。
**递归函数**
递归函数是指可以在函数体内调用自身的函数。递归函数通常在解决可以被分解为相似子问题的问题时很有用。
以下是一个计算阶乘的递归函数示例:
```cpp
int factorial(int n) {
if (n == 0 || n == 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}
int main() {
int n = 5;
int result = factorial(n);
cout << n << " 的阶乘是:" << result << endl; // 输出:5 的阶乘是:120
return 0;
}
当谈到结构体和类时,它们是C++中用于创建自定义数据类型的重要工具。结构体和类都可以封装数据和函数,并且允许创建多个实例(对象)。
3、结构体
结构体是一种用户定义的数据类型,用于封装多个不同类型的变量。它可以将这些变量作为一个单一的实体进行操作。
以下是一个简单的结构体示例:
struct Person {
string name;
int age;
string occupation;
};
int main() {
Person person1;
person1.name = "Alice";
person1.age = 25;
person1.occupation = "Engineer";
cout << "姓名:" << person1.name << endl;
cout << "年龄:" << person1.age << endl;
cout << "职业:" << person1.occupation << endl;
return 0;
}
在上述示例中,我们定义了一个名为 Person
的结构体,它具有三个成员变量:name
、age
和 occupation
。在 main()
函数中,我们创建了一个 Person
类型的变量 person1
,并给其成员变量赋值。然后,我们使用 cout
将其成员变量的值输出到控制台。
4、类
类是一种更高级的数据类型,它可以封装数据和函数,并提供对数据和函数的访问控制。类是面向对象编程(Object-Oriented Programming,OOP)的核心概念之一。
以下是一个简单的类示例:
class Rectangle {
private:
double length;
double width;
public:
void setDimensions(double len, double wid) {
length = len;
width = wid;
}
double getArea() {
return length * width;
}
};
int main() {
Rectangle rectangle;
rectangle.setDimensions(5.0, 3.0);
double area = rectangle.getArea();
cout << "矩形的面积是:" << area << endl;
return 0;
}
在上述示例中,我们定义了一个名为 Rectangle
的类,它具有私有成员变量 length
和 width
,以及公有成员函数 setDimensions()
和 getArea()
。私有成员变量只能在类的内部访问,而公有成员函数可以从类的外部访问。
在 main()
函数中,我们创建了一个 Rectangle
类的对象 rectangle
,并使用 setDimensions()
设置其长度和宽度。然后,我们调用 getArea()
函数来计算矩形的面积,并将结果输出到控制台。
类还支持其他的特性,例如构造函数、析构函数、成员函数的重载和访问修饰符(public、private、protected)等。这些特性可以根据需要来使用,以满足程序的要求。
结构体和类是C++中重要的概念,它们提供了一种组织和管理数据的方式,使代码更加模块化和可扩展。
构造函数和析构函数
构造函数是一种特殊的成员函数,它在创建对象时被调用,并用于初始化对象的成员变量。析构函数是在对象被销毁时自动调用的函数,用于清理对象所占用的资源。
以下是一个示例,演示如何在类中定义构造函数和析构函数:
class Circle {
private:
double radius;
public:
Circle(double r) {
radius = r;
cout << "构造函数被调用" << endl;
}
~Circle() {
cout << "析构函数被调用" << endl;
}
double getArea() {
return 3.14159 * radius * radius;
}
};
int main() {
Circle circle(5.0);
double area = circle.getArea();
cout << "圆的面积是:" << area << endl;
return 0;
}
在上述示例中,我们在 Circle
类中定义了一个带有参数的构造函数和一个析构函数。在 main()
函数中,我们创建了一个 Circle
类的对象 circle
,并传递半径值给构造函数。然后,我们调用 getArea()
函数来计算圆的面积,并输出结果。
构造函数使用与类相同的名称,并在函数定义前加上类的名称。析构函数的名称与类的名称相同,但在函数名前加上波浪线(~
)。构造函数没有返回类型,而析构函数也不需要参数。
成员函数的重载
类中的成员函数可以进行重载,就像普通函数一样。重载的成员函数具有相同的名称,但参数列表不同。通过重载成员函数,我们可以为类提供多个具有相似功能但参数不同的函数。
以下是一个示例,展示了如何在类中重载成员函数:
class MathOperations {
public:
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
};
int main() {
MathOperations math;
int result1 = math.add(3, 4);
double result2 = math.add(2.5, 3.7);
cout << "整数相加的结果:" << result1 << endl; // 输出:整数相加的结果:7
cout << "浮点数相加的结果:" << result2 << endl; // 输出:浮点数相加的结果:6.2
return 0;
}
在上述示例中,我们在 MathOperations
类中定义了两个名为 add
的成员函数,一个接受两个整数参数,另一个接受两个浮点数参数。通过成员函数的重载,我们可以根据参数类型的不同来执行相应的操作。
通过构造函数、析构函数和成员函数的重载,我们可以根据需求为类提供不同的初始化方法、资源管理和功能实现。
访问修饰符
在结构体和类中,成员变量和成员函数可以使用不同的访问修饰符来控制对它们的访问权限。C++提供了三种访问修饰符:public、private和protected。
public
:公有访问修饰符表示成员在类的内部和外部均可访问。这意味着它们可以从类的外部代码访问。
private
:私有访问修饰符表示成员只能在类的内部访问。这意味着它们对于类的外部代码来说是不可见的。
protected
:受保护访问修饰符表示成员对于类的外部代码是不可见的,但对于该类的派生类是可见的。这将在后面的继承部分中进一步讨论。
以下是一个示例,演示了访问修饰符的使用:
class Rectangle {
public:
double length;
double width;
private:
double calculateArea() {
return length * width;
}
public:
double getArea() {
return calculateArea();
}
};
int main() {
Rectangle rectangle;
rectangle.length = 5.0;
rectangle.width = 3.0;
double area = rectangle.getArea();
cout << "矩形的面积是:" << area << endl;
// 以下代码将导致编译错误,因为 width 是私有成员
// rectangle.width = 4.0;
return 0;
}
在上述示例中,我们定义了一个 Rectangle
类,它具有公有成员变量 length
和 width
,以及私有成员函数 calculateArea()
和公有成员函数 getArea()
。我们可以在 main()
函数中访问公有成员变量和公有成员函数,但不能直接访问私有成员变量。
友元函数
友元函数是一种特殊类型的函数,它可以访问类的私有成员。友元函数可以在类的内部声明为友元函数,也可以在类的外部定义为友元函数。
以下是一个示例,展示了如何使用友元函数:
class Rectangle {
private:
double length;
double width;
public:
Rectangle(double len, double wid) {
length = len;
width = wid;
}
friend double calculateArea(Rectangle rect);
};
double calculateArea(Rectangle rect) {
return rect.length * rect.width;
}
int main() {
Rectangle rectangle(5.0, 3.0);
double area = calculateArea(rectangle);
cout << "矩形的面积是:" << area << endl;
return 0;
}
在上述示例中,我们将 calculateArea()
函数声明为 Rectangle
类的友元函数,并在函数定义中访问了
Rectangle
类的私有成员。在 main()
函数中,我们创建了一个 Rectangle
类的对象,并将其传递给 calculateArea()
函数来计算矩形的面积。
静态成员变量和静态成员函数
静态成员变量属于整个类而不是类的实例。它们在类的所有对象之间共享。静态成员变量在类的定义中声明,并在类的外部进行初始化。
静态成员函数是属于类而不是类的实例的函数。它们可以直接通过类名调用,无需创建类的实例。
以下是一个示例,演示了静态成员变量和静态成员函数的使用:
class Circle {
public:
double radius;
static int count;
Circle(double r) {
radius = r;
count++;
}
static int getCount() {
return count;
}
};
int Circle::count = 0; // 静态成员变量的初始化
int main() {
Circle circle1(5.0);
Circle circle2(3.0);
int count = Circle::getCount();
cout << "圆的数量:" << count << endl; // 输出:圆的数量:2
return 0;
}
在上述示例中,我们在 Circle
类中定义了一个静态成员变量 count
和一个静态成员函数 getCount()
。每当创建一个 Circle
类的对象时,静态成员变量 count
会增加,并且我们可以通过调用静态成员函数 getCount()
来获取圆的数量。
继承
继承是一种面向对象编程的重要概念,它允许一个类继承另一个类的属性和行为。通过继承,子类可以从父类继承成员变量和成员函数,并且可以在子类中添加额外的成员变量和成员函数。
在C++中,使用冒号(:)来指定一个类继承另一个类。以下是一个示例:
class Animal {
protected:
string name;
public:
Animal(string n) {
name = n;
}
void speak() {
cout << "动物发出声音" << endl;
}
};
class Dog : public Animal {
public:
Dog(string n) : Animal(n) {
}
void speak() {
cout << "汪汪汪!" << endl;
}
};
int main() {
Dog dog("小狗");
dog.speak(); // 输出:汪汪汪!
return 0;
}
在上述示例中,我们定义了一个 Animal
类,它有一个受保护的成员变量 name
和一个 speak()
函数。然后,我们定义了一个 Dog
类,它从 Animal
类继承,并重写了 speak()
函数。
通过使用 public
访问修饰符,我们确保 Dog
类可以继承 Animal
类的成员变量和成员函数,并且可以在 Dog
类中访问和重写它们。
多态性
多态性是面向对象编程的另一个重要概念,它允许在不同的对象上执行相同的操作,但根据对象的实际类型而执行不同的行为。
在C++中,多态性通常通过虚函数和纯虚函数来实现。虚函数是在基类中声明的,它可以被派生类重写,并且通过基类指针或引用调用时,将根据对象的实际类型来调用相应的函数。
以下是一个示例,展示了多态性的使用:
class Shape {
public:
virtual double getArea() {
return 0.0;
}
};
class Rectangle : public Shape {
private:
double length;
double width;
public:
Rectangle(double len, double wid) {
length = len;
width = wid;
}
double getArea() {
return length * width;
}
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) {
radius = r;
}
double getArea() {
return 3.14159 * radius * radius;
}
};
int main() {
Rectangle rectangle(5.0, 3.0);
Circle circle(2.5);
Shape* shape1 = &rectangle;
Shape* shape2 = &circle;
double area1 = shape1->getArea();
double area2 = shape2->get
Area();
cout << "矩形的面积:" << area1 << endl; // 输出:矩形的面积:15
cout << "圆的面积:" << area2 << endl; // 输出:圆的面积:19.6349
return 0;
}
在上述示例中,我们定义了一个基类 Shape
,它具有一个虚函数 getArea()
。然后,我们定义了两个派生类 Rectangle
和 Circle
,它们分别重写了 getArea()
函数。
通过创建基类指针 Shape*
,我们可以将派生类对象的地址赋给这些指针,并通过它们调用 getArea()
函数。根据对象的实际类型,将调用相应的派生类函数,实现了多态性。
静态成员
C++中的静态成员是属于类而不是类的实例的成员。它们与类本身相关联,而不是与类的实例相关联。可以通过使用关键字 static
来声明静态成员变量和静态成员函数。
静态成员变量被所有类的实例共享,它们在内存中只有一个副本。静态成员函数可以直接访问静态成员变量,而不需要通过类的实例。
以下是一个示例:
class Circle {
private:
double radius;
static int count;
public:
Circle(double r) {
radius = r;
count++;
}
static int getCount() {
return count;
}
};
int Circle::count = 0;
int main() {
Circle c1(5.0);
Circle c2(3.0);
cout << "圆的个数:" << Circle::getCount() << endl; // 输出:圆的个数:2
return 0;
}
在上述示例中,我们定义了一个 Circle
类,其中包含一个静态成员变量 count
和一个静态成员函数 getCount()
。通过在类外部初始化静态成员变量,并在构造函数中对其进行递增操作,我们可以统计创建的圆的个数。
在 main()
函数中,我们创建了两个 Circle
对象,并通过调用静态成员函数 getCount()
输出圆的个数。
四、STL 标准模板库
C++的STL(标准模板库),C++标准库的重要组成部分,提供了一系列通用的数据结构和算法,使得C++开发更加高效和方便。STL包含三个主要组件:容器(Containers)、算法(Algorithms)和迭代器(Iterators)。
容器(Containers)
容器是STL的核心组件之一,提供了各种数据结构,如向量、列表、集合、映射等。这些容器提供了不同的操作和特性,可以根据需要选择合适的容器。
以下是一些常用的STL容器:
vector
:动态数组,提供快速的随机访问。list
:双向链表,支持快速插入和删除操作。set
:有序集合,存储唯一的元素。map
:有序映射,存储键值对。stack
:堆栈,先进后出(LIFO)的数据结构。queue
:队列,先进先出(FIFO)的数据结构。
每种容器都有自己的特点和适用场景,可以根据具体需求选择合适的容器。
算法(Algorithms)
STL提供了丰富的算法库,包括排序、搜索、复制、替换、合并等各种常用算法。这些算法可以用于不同类型的容器,使得对数据进行各种操作变得简单高效。
以下是一些常用的STL算法:
sort
:对容器进行排序。find
:在容器中查找指定元素。copy
:将容器中的元素复制到另一个容器。replace
:替换容器中的元素。merge
:合并两个有序容器。reverse
:反转容器中的元素顺序。
STL算法库的设计使得可以在不同容器之间共享相同的算法实现,提高了代码的重用性和可读性。
迭代器(Iterators)
迭代器是STL提供的一种通用访问容器元素的方式。迭代器类似于指针,可以用于遍历容器中的元素,提供了统一的访问接口。
迭代器分为输入迭代器(Input Iterator)、输出迭代器(Output Iterator)、前向迭代器(Forward Iterator)、双向迭代器(Bidirectional Iterator)和随机访问迭代器(Random Access Iterator)等几种类型,不同类型的迭代器支持不同的操作。
使用迭代器可以方便地遍历容器中的元素,执行各种操作,例如查找、排序、复制等。
明白了,你希望对每种容器进行详细的介绍,类似于官方文档的形式。下面是一个示例,展示了如何详细介绍一个容器(以vector
为例):
vector(动态数组)
概述
vector
是一个动态数组,提供了连续的内存空间用于存储元素。它是最常用的容器之一,支持快速随机访问和动态调整大小。
头文件
#include <vector>
创建容器对象
std::vector<T> vec; // 创建一个空的 vector,元素类型为 T
std::vector<T> vec(n); // 创建包含 n 个默认初始化的元素的 vector
std::vector<T> vec(n, value); // 创建包含 n 个初始化为 value 的元素的 vector
std::vector<T> vec(begin, end); // 创建包含范围 [begin, end) 内的元素的 vector
std::vector<T> vec(other); // 创建另一个 vector 的副本
常用成员函数
size()
:返回 vector 中的元素数量。empty()
:检查 vector 是否为空。push_back(value)
:在 vector 的末尾添加一个元素。pop_back()
:删除 vector 的最后一个元素。front()
:访问 vector 的第一个元素。back()
:访问 vector 的最后一个元素。clear()
:清空 vector 中的所有元素。insert(position, value)
:在指定位置插入一个元素。erase(position)
:删除指定位置的元素。erase(begin, end)
:删除指定范围内的元素。
示例代码
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec; // 创建一个空的 vector
vec.push_back(1); // 添加元素到末尾
vec.push_back(2);
vec.push_back(3);
std::cout << "Vector size: " << vec.size() << std::endl; // 输出元素数量
std::cout << "Vector elements: ";
for (int num : vec) {
std::cout << num << " "; // 遍历并输出元素
}
std::cout << std::endl;
vec.pop_back(); // 删除最后一个元素
std::cout << "Vector size after pop_back(): " << vec.size() << std::endl;
std::cout << "New vector elements: ";
for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
总结
vector
提供了动态数组的功能,可以方便地添加、删除和访问元素。它在需要高效随机访问的场景中非常有用。
下面是针对list
和map
容器的示例:
list(双向链表)
概述
list
是一个双向链表,它支持高效的插入和删除操作,但不支持随机访问。它可以在任意位置进行元素的插入和删除,适用于需要频繁插入和删除操作的场景。
头文件
#include <list>
创建容器对象
std::list<T> lst; // 创建一个空的 list,元素类型为 T
std::list<T> lst(n); // 创建包含 n 个默认初始化的元素的 list
std::list<T> lst(n, value); // 创建包含 n 个初始化为 value 的元素的 list
std::list<T> lst(begin, end); // 创建包含范围 [begin, end) 内的元素的 list
std::list<T> lst(other); // 创建另一个 list 的副本
常用成员函数
size()
:返回 list 中的元素数量。empty()
:检查 list 是否为空。push_back(value)
:在 list 的末尾添加一个元素。push_front(value)
:在 list 的开头添加一个元素。pop_back()
:删除 list 的最后一个元素。pop_front()
:删除 list 的第一个元素。front()
:访问 list 的第一个元素。back()
:访问 list 的最后一个元素。clear()
:清空 list 中的所有元素。insert(position, value)
:在指定位置插入一个元素。erase(position)
:删除指定位置的元素。erase(begin, end)
:删除指定范围内的元素。
示例代码
#include <iostream>
#include <list>
int main() {
std::list<int> lst; // 创建一个空的 list
lst.push_back(1); // 在末尾添加元素
lst.push_back(2);
lst.push_front(0); // 在开头添加元素
std::cout << "List size: " << lst.size() << std::endl; // 输出元素数量
std::cout << "List elements: ";
for (int num : lst) {
std::cout << num << " "; // 遍历并输出元素
}
std::cout << std::endl;
lst.pop_back(); // 删除最后一个元素
std::cout << "List size after pop_back(): " << lst.size() << std::endl;
std::cout << "New list elements: ";
for (int num : lst) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
map(关联容器)
概述
map
是一个关联容器,它提供了一对一的键值对存储和访问功能。它基于红黑树
实现,具有自动排序的特性,键值对按键进行排序,并且可以快速地进行插入、删除和查找操作。
头文件
#include <map>
创建容器对象
std::map<Key, T> mp; // 创建一个空的 map,键类型为 Key,值类型为 T
std::map<Key, T> mp(other); // 创建另一个 map 的副本
常用成员函数
size()
:返回 map 中的键值对数量。empty()
:检查 map 是否为空。insert({key, value})
:插入一个键值对到 map 中。erase(key)
:删除指定键的键值对。clear()
:清空 map 中的所有键值对。find(key)
:查找指定键对应的迭代器。begin()
:返回指向第一个键值对的迭代器。end()
:返回指向最后一个键值对之后的迭代器。
示例代码
#include <iostream>
#include <map>
int main() {
std::map<std::string, int> mp; // 创建一个空的 map
mp.insert({ "Alice", 25}); // 插入键值对
mp.insert({ "Bob", 30});
mp["Charlie"] = 35; // 也可以使用索引操作符插入键值对
std::cout << "Map size: " << mp.size() << std::endl; // 输出键值对数量
std::cout << "Map elements:" << std::endl;
for (const auto& pair : mp) {
std::cout << pair.first << ": " << pair.second << std::endl; // 遍历并输出键值对
}
mp.erase("Bob"); // 删除指定键的键值对
std::cout << "Map size after erase(): " << mp.size() << std::endl;
std::cout << "New map elements:" << std::endl;
for (const auto& pair : mp) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
return 0;
}
set(关联容器)
概述
set
是一个关联容器,它存储唯一的元素,且自动按照键进行排序。set
的底层实现基于红黑树,具有快速的插入、删除和查找操作。
头文件
#include <set>
创建容器对象
std::set<T> st; // 创建一个空的 set,元素类型为 T
std::set<T> st(other); // 创建另一个 set 的副本
常用成员函数
size()
:返回 set 中的元素数量。empty()
:检查 set 是否为空。insert(value)
:向 set 中插入一个元素。erase(value)
:删除 set 中指定的元素。clear()
:清空 set 中的所有元素。find(value)
:查找 set 中是否存在指定的元素。begin()
:返回指向第一个元素的迭代器。end()
:返回指向最后一个元素之后的迭代器。
示例代码
#include <iostream>
#include <set>
int main() {
std::set<int> st; // 创建一个空的 set
st.insert(10); // 插入元素
st.insert(20);
st.insert(30);
std::cout << "Set size: " << st.size() << std::endl; // 输出元素数量
std::cout << "Set elements: ";
for (int num : st) {
std::cout << num << " "; // 遍历并输出元素
}
std::cout << std::endl;
st.erase(20); // 删除指定元素
std::cout << "Set size after erase(): " << st.size() << std::endl;
std::cout << "New set elements: ";
for (int num : st) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
stack(适配器容器)
概述
stack
是一个适配器容器,它提供了栈(先进后出)的行为。stack
内部使用其他容器作为其底层实现,默认情况下使用 deque
作为底层容器。
头文件
#include <stack>
创建容器对象
std::stack<T> stk; // 创建一个空的 stack,元素类型为 T
常用成员函数
size()
:返回 stack 中的元素数量。empty()
:检查 stack 是否为空。push(value)
:将元素压入 stack。pop()
:弹出 stack 的顶部元素。top()
:返回 stack 的顶部元素的引用。
示例代码
#include <iostream>
#include <stack>
int main() {
std::stack<int> stk; // 创建一个空的 stack
stk.push(10); // 将元素压入 stack
stk.push(20);
stk.push(30);
std::cout << "Stack size: " << stk.size() << std::endl; // 输出元素数量
std::cout << "Stack top: " << stk.top() << std::endl; // 输出栈顶元素
stk.pop(); // 弹出栈顶元素
std::cout << "Stack size after pop(): " << stk.size() << std::endl;
std::cout << "New stack top: " << stk.top() << std::endl;
return 0;
}
queue(适配器容器)
概述
queue
是一个适配器容器,它提供了队列(先进先出)的行为。queue
内部使用其他容器作为其底层实现,默认情况下使用 deque
作为底层容器。
头文件
#include <queue>
创建容器对象
std::queue<T> que; // 创建一个空的 queue,元素类型为 T
常用成员函数
size()
:返回 queue 中的元素数量。empty()
:检查 queue 是否为空。push(value)
:将元素加入到 queue 的末尾。pop()
:移除 queue 的首个元素。front()
:返回 queue 的首个元素的引用。back()
:返回 queue 的末尾元素的引用。
示例代码
#include <iostream>
#include <queue>
int main() {
std::queue<int> que; // 创建一个空的 queue
que.push(10); // 将元素加入到 queue 的末尾
que.push(20);
que.push(30);
std::cout << "Queue size: " << que.size() << std::endl; // 输出元素数量
std::cout << "Queue front: " << que.front() << std::endl; // 输出队首元素
std::cout << "Queue back: " << que.back() << std::endl; // 输出队尾元素
que.pop(); // 移除队首元素
std::cout << "Queue size after pop(): " << que.size() << std::endl;
std::cout << "New queue front: " << que.front() << std::endl;
return 0;
}
STL 算法
STL(标准模板库)提供了丰富的算法,用于在容器上执行各种操作。这些算法大大简化了对数据集合的处理,包括搜索、排序、转换等操作。
以下是一些常用的 STL 算法:
std::find()
:在容器中查找指定的元素。std::sort()
:对容器中的元素进行排序。std::reverse()
:反转容器中的元素顺序。std::count()
:统计容器中某个值的出现次数。std::accumulate()
:计算容器中元素的累加和。std::transform()
:对容器中的元素应用一个操作,并将结果存储在另一个容器中。std::copy()
:将一个容器中的元素复制到另一个容器中。std::remove()
:从容器中删除指定的值。std::unique()
:删除容器中的重复元素。std::min_element()
:查找容器中的最小元素。std::max_element()
:查找容器中的最大元素。
这些算法都是通过包含 <algorithm>
头文件来使用的。它们适用于不同类型的容器,包括数组、向量、列表、集合等。
下面是一个示例代码,演示了如何使用 STL 算法:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> nums = { 4, 2, 7, 1, 5, 3};
// 查找元素 5
auto it = std::find(nums.begin(), nums.end(), 5);
if (it != nums.end()) {
std::cout << "Element 5 found at index: " << std::distance(nums.begin(), it) << std::endl;
} else {
std::cout << "Element 5 not found" << std::endl;
}
// 对容器进行排序
std::sort(nums.begin(), nums.end());
// 输出排序后的容器
std::cout << "Sorted container: ";
for (int num : nums) {
std::cout << num << " ";
}
std::cout << std::endl;
// 计算容器中的元素和
int sum = std::accumulate(nums.begin(), nums.end(), 0);
std::cout << "Sum of elements: " << sum << std::endl;
return 0;
}
std::reverse()
算法用于反转容器中的元素顺序。
template< class BidirIt >
void reverse( BidirIt first, BidirIt last );
first
和 last
:定义了容器中要进行反转的元素的范围。这个范围是一个双向迭代器(Bidirectional Iterator),可以在正向和反向方向上进行遍历。
下面是一个示例代码:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> nums = { 1, 2, 3, 4, 5};
std::reverse(nums.begin(), nums.end());
std::cout << "Reversed container: ";
for (int num : nums) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
输出结果为:
Reversed container: 5 4 3 2 1
在上面的示例中,我们使用 std::reverse()
将容器 nums
中的元素反转。反转后,容器中的元素顺序由 {1, 2, 3, 4, 5} 变为 {5, 4, 3, 2, 1}。
这就是 std::reverse()
算法的用法。它可以用于任何支持双向迭代器的容器,如向量、双向链表等。
std::replace()
std::replace()
算法用于将容器中的指定值替换为另一个值。
template< class ForwardIt, class T >
void replace( ForwardIt first, ForwardIt last, const T& old_value, const T& new_value );
first
和 last
:定义了容器中要进行替换的元素的范围。old_value
:要替换的旧值。new_value
:要替换成的新值。
下面是一个示例代码:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> nums = { 1, 2, 3, 4, 3, 5, 6, 3, 7};
std::replace(nums.begin(), nums.end(), 3, 9);
std::cout << "After replace: ";
for (int num : nums) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
输出结果为:
After replace: 1 2 9 4 9 5 6 9 7
std::transform()
算法用于对容器中的元素应用一个操作,并将结果存储到另一个容器中。
template< class InputIt, class OutputIt, class UnaryOperation >
OutputIt transform( InputIt first1, InputIt last1, OutputIt d_first, UnaryOperation unary_op );
first1
和 last1
:定义了输入容器中要应用操作的元素的范围。d_first
:定义了输出容器的起始位置,用于存储操作的结果。unary_op
:要应用的一元操作,可以是函数对象、函数指针或 Lambda 表达式。
下面是一个示例代码:
#include <iostream>
#include <algorithm>
#include <vector>
int square(int num) {
return num * num;
}
int main() {
std::vector<int> nums = { 1, 2, 3, 4, 5};
std::vector<int> squared_nums(nums.size());
std::transform(nums.begin(), nums.end(), squared_nums.begin(), square);
std::cout << "Original numbers: ";
for (int num : nums) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "Squared numbers: ";
for (int num : squared_nums) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
输出结果为:
Original numbers: 1 2 3 4 5
Squared numbers: 1 4 9 16 25
在上面的示例中,我们定义了一个函数 square()
,用于计算一个数的平方。然后使用 std::transform()
将函数 square()
应用到容器 nums
中的每个元素上,并将结果存储到容器 squared_nums
中。
std::transform()
还支持其他形式的操作,如二元操作和多元操作。你可以根据具体的需求选择合适的操作方式。
std::for_each()
template< class InputIt, class UnaryFunction >
UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );
first
和 last
:定义了容器中要应用操作的元素的范围。f
:要应用的操作,可以是函数对象、函数指针或 Lambda 表达式。
下面是一个示例代码:
#include <iostream>
#include <algorithm>
#include <vector>
void printSquare(int num) {
std::cout << num * num << " ";
}
int main() {
std::vector<int> nums = { 1, 2, 3, 4, 5};
std::for_each(nums.begin(), nums.end(), printSquare);
return 0;
}
输出结果为:
1 4 9 16 25
在上面的示例中,我们定义了一个函数 printSquare()
,用于打印每个元素的平方。然后使用 std::for_each()
将这个函数应用到容器 nums
中的每个元素上。
std::binary_search()
std::binary_search()
算法用于在已排序的容器中执行二分查找。
template< class ForwardIt, class T >
bool binary_search( ForwardIt first, ForwardIt last, const T& value );
first
和 last
:定义了容器中要进行查找的元素的范围。value
:要查找的值。
下面是一个示例代码:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::
vector<int> nums = { 1, 2, 3, 4, 5};
bool found = std::binary_search(nums.begin(), nums.end(), 3);
if (found) {
std::cout << "Element 3 found" << std::endl;
} else {
std::cout << "Element 3 not found" << std::endl;
}
return 0;
}
输出结果为:
Element 3 found
在上面的示例中,我们使用 std::binary_search()
在已排序的容器 nums
中查找值为 3 的元素。
std::copy()
算法用于将一个容器中的元素复制到另一个容器中。
template< class InputIt, class OutputIt >
OutputIt copy( InputIt first, InputIt last, OutputIt d_first );
first
和 last
:定义了要复制的元素的范围。d_first
:定义了目标容器的起始位置,用于存储复制的元素。
下面是一个示例代码:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> source = { 1, 2, 3, 4, 5};
std::vector<int> destination(source.size());
std::copy(source.begin(), source.end(), destination.begin());
std::cout << "Source container: ";
for (int num : source) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "Copied container: ";
for (int num : destination) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
输出结果为:
Source container: 1 2 3 4 5
Copied container: 1 2 3 4 5
在上面的示例中,我们使用 std::copy()
将容器 source
中的元素复制到容器 destination
中。注意,destination
容器的大小必须与 source
容器相同,以便能够存储所有复制的元素。
std::copy()
还可以用于将元素复制到输出流(如标准输出)中,或将元素复制到指定位置的迭代器中。
std::remove()
算法用于从容器中移除指定值的元素,但并不实际删除这些元素,而是将它们移到容器的末尾,并返回一个指向新的逻辑末尾的迭代器。
template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );
first
和 last
:定义了要移除元素的范围。value
:指定要移除的值。
下面是一个示例代码:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> nums = { 1, 2, 3, 2, 4, 5, 2};
auto newEnd = std::remove(nums.begin(), nums.end(), 2);
std::cout << "Original container: ";
for (int num : nums) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "Modified container: ";
for (auto it = nums.begin(); it != newEnd; ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
输出结果为:
Original container: 1 3 4 5 4 5 2
Modified container: 1 3 4 5 4 5
在上面的示例中,我们使用 std::remove()
将容器 nums
中的值为 2 的元素移动到容器末尾,并返回一个迭代器指向新的逻辑末尾位置。然后,我们使用迭代器循环遍历原容器,并输出移除后的容器。
请注意,虽然移除操作并不实际删除元素,但它可以结合其他算法(如 std::erase()
)来实现真正的删除操作。
std::unique()
算法用于移除容器中的连续重复元素,并返回一个指向新的逻辑末尾的迭代器。
template< class ForwardIt >
ForwardIt unique( ForwardIt first, ForwardIt last );
first
和 last
:定义了要移除重复元素的范围。
下面是一个示例代码:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> nums = { 1, 1, 2, 2, 3, 3, 4, 4, 5};
auto newEnd = std::unique(nums.begin(), nums.end());
std::cout << "Original container: ";
for (int num : nums) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "Modified container: ";
for (auto it = nums.begin(); it != newEnd; ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
输出结果为:
Original container: 1 1 2 2 3 3 4 4 5
Modified container: 1 2 3 4 5
在上面的示例中,我们使用 std::unique()
移除容器 nums
中的连续重复元素,并返回一个指向新的逻辑末尾位置的迭代器。然后,我们使用迭代器循环遍历原容器,并输出移除重复后的容器。
请注意,该算法只能移除相邻的重复元素,如果容器中的重复元素不相邻,需要先进行排序操作。
std::min_element()
算法用于在容器中找到最小元素,并返回指向该元素的迭代器。
template< class ForwardIt >
ForwardIt min_element( ForwardIt first, ForwardIt last );
first
和 last
:定义了要查找最小元素的范围。
下面是一个示例代码:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> nums = { 5, 2, 8, 4, 1};
auto minIt = std::min_element(nums.begin(), nums.end());
std::cout << "Container: ";
for (int num : nums) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "Minimum element: " << *minIt << std::endl;
return 0;
}
输出结果为:
Container: 5 2 8 4 1
Minimum element: 1
在上面的示例中,我们使用 std::min_element()
在容器 nums
中查找最小元素,并返回指向该元素的迭代器。然后,我们使用迭代器获取最小元素的值,并输出结果。
std::max_element()
算法用于在容器中找到最大元素,并返回指向该元素的迭代器。
template< class ForwardIt >
ForwardIt max_element( ForwardIt first, ForwardIt last );
first
和 last
:定义了要查找最大元素的范围。
下面是一个示例代码:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> nums = { 5, 2, 8, 4, 1};
auto maxIt = std::max_element(nums.begin(), nums.end());
std::cout << "Container: ";
for (int num : nums) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "Maximum element: " << *maxIt << std::endl;
return 0;
}
输出结果为:
Container: 5 2 8 4 1
Maximum element: 8
在上面的示例中,我们使用 std::max_element()
在容器 nums
中查找最大元素,并返回指向该元素的迭代器。然后,我们使用迭代器获取最大元素的值,并输出结果。
五、总结
如果你看到了这个位置,恭喜你已经对C++的知识,有了一个初步的了解。同时,你是适合学习C++, 因为能够静下心,看到最后,你已经超过了很多人,加油,学无止尽。
同时,本教程旨在为有其他编程语言经验的开发者提供一个详细的C++入门基础教程。我们从对比C++与其他语言的差异开始,重点介绍了C++的核心特性,深入讲解了C++的高级特性,并提供了注意语言细节和最佳实践的指导,以及引导进阶学习的建议。
在教程中,我们了解了C++的历史和用途,以及为什么对比C++与其他语言的差异对于有经验的开发者很有价值。我们强调了C++作为一门多范式编程语言的特点,既支持面向对象编程,又支持泛型编程和低级操作。
我们详细讲解了C++的语法和语义,包括变量和数据类型、运算符、控制流语句、函数和函数重载、结构体和类等。每个知识点都附带了具体的示例代码和解释,以帮助读者更好地理解。
我们还介绍了C++标准模板库(STL),包括各种容器(如向量、列表、集合、映射等)和常用算法(如排序、查找、变换等)。对于每个容器和算法,我们提供了详细的讲解和示例代码,帮助读者熟悉和应用STL。
最后,我们总结了整个教程的内容,强调了C++作为一门强大而灵活的编程语言的优点,并鼓励读者继续深入学习和探索C++的更多高级特性和应用领域。
希望本教程能够帮助你快速入门C++,并为你在C++开发中提供坚实的基础。祝你在C++编程的旅程中取得成功!
注释:如果本文中有描述错误,或者表述不恰当,理解偏差的地方。欢迎大家批评指正。
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。