1.C和C++的区别还有关系
C和C++之间的关系是紧密且复杂的。C++最初是作为C语言的一个扩展开发的,目的是在不放弃C的强大 功能和效率的同时,增加对象导向编程、泛型编程和其他一些特性。下面是C和C++之间主要的关系和区 别:
- 1. 兼容性:C++在很大程度上是与C兼容的。这意味着许多C程序可以在C++编译器中编译并运行,尽 管可能需要一些小的修改。
- 2. 面向对象编程(OOP):C++引入了面向对象编程。它允许使用类和对象,而C是一个过程性语 言,不支持这些概念,或者说支持的不好,麻烦。
- 3. 模板:C++支持模板,这是一种允许程序员编写与数据类型无关的代码的功能。C没有这个功能。
- 4. 标准库:C++有一个更丰富的标准库,包括STL(标准模板库),这为数据结构和算法提供了广泛的 支持。而C的标准库相对较小。
- 5. 类型检查:C++比C提供更严格的类型检查。这意味着某些在C中可行但可能导致错误的代码在 C++中可能无法编译。
- 6. 异常处理:C++支持异常处理,这是一种处理程序运行时错误的机制。C没有内置的异常处理机制。
- 7. 命名空间:C++引入了命名空间,这有助于防止名称冲突。C没有这个概念。
2.命名空间
2.1命名空间作用
- 创建自己的命名空间是 C++ 中组织代码的一种好方法,特别是在开发大型项目或库时。
- 命名空间可以帮助你避免名称冲突,并且清晰地组织代码。
- std 是 C++ 标准库的命名空间。它是一个定义在 C++ 标准库中的所有类、函数和变量的命名空间。
- 我们新建一个QTCreator的C++工程,默认生成的代码
#include <iostream>
using namespace std;
int main()
{
cout << "Hello World!" << endl;
return 0;
}
在 C++ 中,如果你想使用标准库中的任何类、函数或对象,你通常有两种选择:
1.使用 std:: 前缀:这是最常见的方式,它明确指定了你正在使用的是位于 std 命名空间中的元素。
std::cout << "Hello, world!" << std::endl;
2. 使用 using namespace std; :这允许你在不显式指定 std:: 的情况下使用 std 命名空间中的所有元素。
using namespace std;
cout << "Hello, world!" << endl;//打印 Hello, world!
std包含的内容
std 命名空间包含了许多类、函数和对象,例如:
- 输入输出库(如 std::cout , std::cin , std::endl )
- 容器类(如 std::vector , std::map , std::set )
- 字符串类( std::string )
- 异常类( std::exception 和相关子类)
- 算法(如 std::sort , std::find )
- 实用工具(如 std::pair , std::tuple )
- 其他许多功能
使用建议
- 对于小型代码或示例代码,使用 using namespace std; 通常是安全的。
- 对于大型项目或库,建议显式地使用 std:: 前缀,以避免潜在的名称冲突,并提高代码的可读性和可维护性。
std 命名空间是 C++ 编程的基础部分,理解和正确使用它对于编写健壮和高效的 C++ 代码至关重要。
2.2 自定义命名空间
定义命名空间
假设我们要创建一个命名空间来包含与圆形相关的功能。我们可以命名这个命名空间为 Cir
:
#ifndef CIR_H
#define CIR_H
namespace cir { //命名空间为cir
double PI = 3.141592653; //定义一个浮点数变量
//获取圆形周长的函数
double getLenhOfCircle(double radius){
return 2*PI*radius;
}
//获取圆形面积的函数
double getAifCircle(double radius){
return PI*radius*radius;
}
}
#endif // CIR_H
在这个头文件
中,我们定义了一个名为 Cir 的命名空间,其中包含了计算圆的面积和周长的函数,以及圆周率常量 PI
。
命名空间的使用
不在cpp源文件里定义Cir命名空间的使用方法
#include <iostream>
#include <stdio.h>
#include "cir.h"//包含cir的头文件
using namespace std;//std命名空间
int main()
{
double myRadius = 5;//定义一个double类型的变量来存储计算的值
cout << "Hello World!" << endl;//打印hello word
printf("lenth:%lf,are:%lf\n",cir::getLenhOfCircle(myRadius),//cir::getLenhOfCircle(myRadius) cir是命名空间,里面存了两个函数。现在用的是获取圆形周长的函数,将 myRadius的数值传进去
cir::getAifCircle(myRadius));//获取圆形面积的函数,将 myRadius的数值传进去
return 0;
}
在源文件中,我们包含了cir命名空间的头文件,我们可以用cir::
前缀来访问cir命名空间的函数和常量。
在cpp源文件中定义Cir命名空间的使用方法
#include <iostream>
#include <stdio.h>
#include "cir.h"
using namespace std;
using namespace cir; //直接定义命名空间,就不用写cir::,直接用命名空间里的函数或常量
int main()
{
double myRadius = 5;//定义一个double类型的变量来存储计算的值
cout << "Hello World!" << endl;//打印Hello World!
printf("lenth:%lf,are:%lf\n",getLenhOfCircle(myRadius),getAifCircle(myRadius));// cir命名空间里面存了两个函数,和上面的一样,就是没有加cir::前缀而已
return 0;
}
3.C++入门
3.1 输入输出
C++ 中的输入和输出(I/O)主要是通过标准库中的输入输出流来实现的。最常用的是 iostream 库,它提供了用于输入和输出的基本流类,包括 cin
、 cout
、 cerr
和 clog
。
标准输出流 ( cout
)
cout
代表标准输出流,通常用于向屏幕输出数据。- 使用操作符
<<
(插入操作符)向 cout 发送数据。 - 例如,
std::cout << "Hello, world!" << std::endl;
会在屏幕上打印 “Hello, world!” 并换行。
标准输入流 ( cin
)
cin
代表标准输入流,用于从键盘接收数据。- 使用操作符
>>
(提取操作符)从 cin 提取数据。 - 例如,
int x; std::cin >> x;
会从用户那里读取一个整数并存储在变量x
中。
标准错误流 ( cerr
) 和标准日志流 ( clog
)
cerr
用于输出错误消息。与cout
不同,cerr
不是缓冲的,这意味着它会立即输出。clog
类似于cerr
,但它是缓冲的。它通常用于记录错误和日志信息
示例代码:注意<< >> 方向
#include <iostream>
using namespace std;
int main()
{
int a = 0;
int b = 0;
cout << "Hello World!" << endl;//cout输出,endl相当于换行
cin >> a;//cin输入,输入内容给变量a
cin >> b;
cout << a << "," << b << endl;//打印
cout << a << "+" << b << "=" << a+b << endl;//比较C语言,这个使用拼接的方式来写 a+b=*
return 0;
}
3.2 基本变量类型
C++ 基本数据类型整理成表格。以下是一个表格,展示了不同的基本数据类型及其一般用途和大小范围:
数据类型 | 描述 | 大小(通常情况下) | 用途 |
int | 整型 | 至少 16 位 | 存储整数 |
short int | 短整型 | 至少 16 位 | 存储较小的整数 |
long int | 长整型 | 至少 32 位 | 存储较大的整数 |
long long int | 更长的整型 | 至少 64 位 | 存储非常大的整数 |
unsigned int | 无符号整型 | 同 int | 存储非负整数 |
float | 单精度浮点类型 | 32 位 | 存储小数,精度约为 6-7 位小数 |
double | 双精度浮点类型 | 64 位 | 存储小数,精度约为 15-16 位小数 |
long double | 扩展精度浮点类型 | 80 位或更多 | 存储小数,提供比double 更高的精度 |
char | 字符型 | 8 位 | 存储单个字符或小整数 |
unsigned char | 无符号字符型 | 8 位 | 存储较大的字符或作为字节使用 |
signed char | 有符号字符型 | 8 位 | 明确作为带符号的字符或小整数使用 |
bool | 布尔型 | 通常为 8 位 | 存储真值 true 或假值 false C语言 C99以上支持 |
wchar_t | 宽字符类型 | 通过为16位或32位 | 存储中文或者unicode |
3.3 流程控制
在 C++ 中,流程控制语句用于根据不同条件控制程序的执行流程。它们是编程中的基本构建块,允许程
序根据条件执行不同的代码段,重复执行某些操作,或者根据特定情况跳过某些代码段。下面是 C++ 中
最常见的流程控制语句:
3.3.1 条件语句
1. if 语句:基于条件的基本控制结构。如果条件为真,则执行代码块
if (condition) {
// 条件为真时执行的代码
}
2. else 语句:与 if 语句配合使用,当 if 的条件为假时执行。
if (condition) {
// 条件为真时执行的代码
} else {
// 条件为假时执行的代码
}
3. else if 语句:用于测试多个条件。
if (condition1) {
// 第一个条件为真时执行的代码
} else if (condition2) {
// 第二个条件为真时执行的代码
} else {
// 所有条件为假时执行的代码
}
4. switch 语句:基于变量的值选择执行不同代码块的方法
switch (expression) {
case value1:
// expression 等于 value1 时执行的代码
break;
case value2:
// expression 等于 value2 时执行的代码
break;
default:
// 没有匹配的 case 时执行的代码
}
3.3.2 循环语句
1.for 循环:当知道循环应该执行的次数时使用。
for (initialization; condition; increment) {
// 循环体
}
2. while 循环:当条件为真时,重复执行代码块。
while (condition) {
// 循环体
}
3. do-while 循环:至少执行一次循环体,然后再检查条件。
do {
// 循环体
} while (condition);
3.3.3 跳转语句
1. break 语句:用于立即跳出最近的 switch 或循环( for 、 while 、 do-while )。
2. continue 语句:跳过循环的当前迭代,并继续下一次迭代。
3. goto 语句:直接跳转到程序中的另一个点。使用 goto 通常不推荐,因为它可以使代码难以阅读和维护。
流程控制语句是编程中非常重要的部分,允许开发者编写可以根据不同情况改变行为的灵活且强大的程序。在使用这些语句时,应该确保逻辑清晰,以便代码易于理解和维护。
3.4 函数
在 C++ 中,函数是一段执行特定任务的代码块,它可以带有参数,并且可能返回一个值。函数的使用使得代码更加模块化和可重用,有助于降低代码的复杂性,并提高可维护性。
函数的基本结构
C++ 函数的基本结构包括返回类型、函数名、参数列表和函数体:
返回类型 函数名(参数列表) {
// 函数体
// 返回语句(如果有返回值的话)
}
示例
#include <iostream>//包含头文件
using namespace std;//定义命名空间
// 函数声明
int add(int x, int y);
int main() {
int result = add(5, 3);1 //脚注
cout << "Result: " << result << endl;//打印
return 0;
}
// 函数定义
int add(int x, int y) {//1
return x + y; //2
}
add(5 ,3)
–>意思就是将 5,3分别代入函数定义里计算,可以得出 x=5,y=3
所以第2行x+y
得出 5+3=8,然后return
将8这个值返回给函数add
。
由此add(5,3)
等于 8 传给result
变量。 ↩︎
结果
在这个示例中, add 函数接收两个整数参数,并返回它们的和。
函数的组成部分
- 返回类型:指定函数返回的数据类型。如果函数不返回任何值,则使用 void 。
- 函数名:函数的标识符,用于调用函数。
- 参数列表:括号内的变量列表,用于从函数的调用者那里接收值。如果函数不接收任何参数,则此列表为空。
- 函数体:大括号 {} 内的一系列语句,定义了函数的执行操作。
4. Lambda 匿名函数
Lambda 表达式是 C++11 引入的一种匿名函数的方式,它允许你在需要函数的地方内联地定义函数,而无需单独命名函数
Lambda 表达式的基本语法如下:
[capture clause](parameters) -> return_type {
// 函数体
// 可以使用捕获列表中的变量
return expression; // 可选的返回语句
}
Lambda 表达式由以下部分组成:
- 捕获列表(Capture clause):用于捕获外部变量,在 Lambda 表达式中可以访问这些变量。捕获列表可以为空,也可以包含变量列表 [var1, var2, …] 。
- 参数列表(Parameters):与普通函数的参数列表类似,可以为空或包含参数列表 (param1,param2, …) 。
- 返回类型(Return type):Lambda 表达式可以自动推断返回类型auto,也可以显式指定返回类型 -> return_type 。如果函数体只有一条返回语句,可以省略返回类型。
- 函数体(Body):Lambda 表达式的函数体,包含需要执行的代码
Lambda 表达式最简单的案例是在需要一个小型函数或临时函数时直接使用它。以下是一个非常简单的例子,其中使用 Lambda 表达式来定义一个加法操作,并立即使用它来计算两个数的和。
普通函数
#include <iostream>
using namespace std;//定义命名空间
int add(int a, int b)//自写函数
{
return a+b;
}
int main()
{
int x = 10;
int y = 30;
int ret = add(x,y);//调用自写函数,将x,y的值传给自写函数计算
cout << ret;//打印
return 0;
}
Lambda函数 –> 不使用调用 add只能用auto,不能用其他类型代替
#include <iostream>
using namespace std;//定义命名空间
int main()
{
int x = 10;
int y = 40;
/*
*[capture clause](parameters) -> return_type {
// []函数体
// ()可以使用捕获列表中的变量
return expression; // 可选的指定返回语句类型
}
*
*/
auto add = [](int a, int b)->int{//auto自动推断返回类型,这个一般用在回调函数里的,现在没有用,所以加个类型给他
return a+b;
};
int ret = add(x,y);//调用自写函数,将x,y的值传给自写函数计算
cout << ret;//打印
return 0;
}
4.1 函数指针
4.1.1什么是函数指针?
函数指针是指向函数而非数据的指针变量。它存储的是函数的入口地址,通过这个指针可以间接调用函数。
// 函数声明
int add(int a, int b);
// 函数指针声明
int (*funcPtr)(int, int); // 指向返回int并接受两个int参数的函数
// 将函数地址赋给指针
funcPtr = add; // 或 funcPtr = &add;
// 通过指针调用函数
int result = funcPtr(3, 5); // 等同于 add(3, 5)
4.1.2函数指针的声明语法
返回类型 (*指针变量名)(参数类型列表);
示例:
// 指向无参数、无返回值的函数
void (*voidFuncPtr)();
// 指向返回double、接受两个float参数的函数
double (*mathFuncPtr)(float, float);
4.2 lambda回调函数使用
回调函数
#include <iostream>
using namespace std;
bool compare(int a, int b){ //判断a是否大于b, 大于 输出 true ,小于 输出 false
return a > b;
}
//回调函数,获得两数最大值
int getMax(int a, int b, bool(*pcompare)(int a, int b))//函数指针,bool(*pcompare)(int a, int b),指向返回bool、接受两个int参数的函数
{
if(pcompare(a,b)){ //判断是否满足,是输出a,否 输出b
return a;
}else {
return b;
}
}
int main()
{
int x =10;
int y = 20;
int max = getMax(x, y, compare);//调用getMax函数 ,compare调用
cout << max << endl;
return 0;
}
Lambda用回调函数实验,一般都是用这种
#include <iostream>
using namespace std;
//改为lambda表达式代替,不使用 compare函数
//bool compare(int a, int b){ //判断a是否大于b, 大于 输出 true ,小于 输出 false
// return a > b;
//}
//回调函数,获得两数最大值
int getMax(int a, int b, bool(*pcompare)(int a, int b))//函数指针,bool(*pcompare)(int a, int b),指向返回bool、接受两个int参数的函数
{
if(pcompare(a,b)){ //判断是否满足,是输出a,否 输出b
return a;
}else {
return b;
}
}
int main()
{
int x =90;
int y = 20;
int max = getMax(x, y, [](int a, int b)->bool{
return a > b;
});//调用getMax函数 ,将compare改为lambad表达式
cout << max << endl;
return 0;
}