Re:从零开始的C++世界——(一)入门基础

文章目录

  • C++发展历史
  • 1.命名空间
    • 1.1 namespace的价值
    • 1.2 namespace的定义
    • 1.3 命名空间使⽤
  • 2.C++输⼊&输出
  • 3.缺省参数
    • 3.1 缺省参数的概念
    • 3.2 缺省参数的分类
  • 4.函数重载
  • 5.引⽤
    • 5.1引⽤的概念和定义
    • 5.2 引⽤的特性
    • 5.3 const引⽤
    • 5.4 使用场景
    • 5.5 指针和引⽤的关系
  • 6.内联函数
    • 6.1内联函数概念
    • 6.2 内敛函数的特性
  • 7.指针空值nullptr
    • 7.1 C++98中的指针空值
    • 7.2 C++11中的指针空值
  • 8 **总结**

C++发展历史

C++的起源可以追溯到1979年,当时Bjarne Stroustrup(本贾尼·斯特劳斯特卢普,这个翻译的名字不同的地⽅可能有差异)在⻉尔实验室从事计算机科学和软件⼯程的研究⼯作。⾯对项⽬中复杂的软件开发任务,特别是模拟和操作系统的开发⼯作,他感受到了现有语⾔(如C语⾔)在表达能⼒、可维护性和可扩展性⽅⾯的不⾜。

1983年,Bjarne Stroustrup在C语⾔的基础上添加了⾯向对象编程的特性,设计出了C++语⾔的雏形,此时的C++已经有了类、封装、继承等核⼼概念,为后来的⾯向对象编程奠定了基础。这⼀年该语⾔被正式命名为C++。

在这里插入图片描述

语言的发展是一个初步递进、由浅入深的过程。
在这里插入图片描述

在这里插入图片描述
目前,C++还在不断向后发展中。

1.命名空间

1.1 namespace的价值

在C/C++中,变量、函数和后⾯要学到的类都是⼤量存在的,这些变量、函数和类的名称将都存在于全局作⽤域中,可能会导致很多冲突。使⽤命名空间的⽬的是对标识符的名称进⾏本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

c语⾔项⽬类似下⾯程序这样的命名冲突是普遍存在的问题,C++引⼊namespace就是为了更好的解决这样的问题。

#include <stdio.h>
#include <stdlib.h>

int rand = 10;
int main()
{
	// 编译报错:error C2365: “rand”: 重定义;以前的定义是“函数”
	printf("%d\n", rand);
	return 0;
}

1.2 namespace的定义

• 定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。

 // 普通的命名空间
namespace N1 // N1为命名空间的名称
{
	//  命名空间中的内容,既可以定义变量,也可以定义函数
	int a;
	int Add(int x, int y) 
	{
		return x + y;
	}
}

• namespace只能定义在全局,当然他还可以嵌套定义。

// 命名空间可以嵌套
namespace N1 // 定义一个名为N1的命名空间
{
	int a;
	int b;
	namespace N2 // 嵌套定义另一个名为N2的命名空间
	{
		int c;
		int d;
	}
}

•项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace,不会冲突。

// 定义一个N1
namespace N1
{
	int a;
	int Add(int x, int y) {
		return x + y;
	}
}

// 再定义一个N1
namespace N1
{
	int Mul(int left, int right)
	{
		return left * right;
	}
}

其它特征:

• namespace本质是定义出⼀个域,这个域跟全局域各⾃独⽴,不同的域可以定义同名变量,所以下
⾯的rand不在冲突了。
• C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/
类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响
编译查找逻辑,还会影响变量的⽣命周期,命名空间域和类域不影响变量⽣命周期。
• C++标准库都放在⼀个叫std(standard)的命名空间中。

1.3 命名空间使⽤

编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间⾥⾯去查找。所以下⾯程序会编译报错。

#include<stdio.h>
namespace bit
{
	int a = 0;
	int b = 1;
} 
int main()
{
	// 编译报错:error C2065: “a”: 未声明的标识符
	printf("%d\n", a);
	return 0;
}

所以我们要使⽤命名空间中定义的变量/函数,有三种⽅式:

(1)加命名空间名称及作用域限定符,项⽬中推荐这种⽅式。

符号 :: 在 C++中叫做作用域限定符。

我们通过 命名空间名称 :: 命名空间成员 便可以访问到命名空间中相应的成员。

#include <stdio.h>

// 加命名空间名称及作用域限定符
namespace N
{
	int a;
	float b;
}

int main()
{
	N::a = 10; // 将命名空间中的成员a赋值为10
	N::b = 5.55; // 将成员b赋值为5.55

	printf("%d\n", N::a); // 打印a
	printf("%.2f\n", N::b); // 打印b

	return 0;
}

(2)使用 using 将命名空间中成员引入

我们还可以通过 using 命名空间名称::命名空间成员 的方式将命名空间中指定的成员引入。

这样语句之后的代码中就可以直接使用引入的成员变量了。项⽬中经常访问的不存在冲突的成员推荐这种⽅式。

#include <stdio.h>

// 使用using将命名空间中的成员引入
namespace N
{
	int a;
	float b;
}

using N::a; // 将命名空间中的成员a引入
using N::b; // 再将b引入

int main()
{
	a = 10; // 将命名空间中的成员a赋值为10
	b = 5.55; // 将b赋值为5.55

	printf("%d\n", a); // 打印成员a
	printf("%.2f\n", b); // 打印成员b

	return 0;
}

(3) 使用 using namespace 命名空间名称引入

最后一种方式就是通 using namespace 命名空间名称 将命名空间中的全部成员引入。

这样语句之后的代码中就可以直接使用该命名空间内的全部成员了,项⽬不推荐,冲突⻛险很⼤,⽇常⼩练习程序为了⽅便推荐使⽤。

#include <stdio.h>

// 使用 using namespace 命名空间名称引入
namespace N
{
	int a;
	float b;
}

using namespace N; // 将命名空间N的所有成员引入

int main()
{
	a = 10; // 将命名空间中的成员a赋值为10

	printf("%d\n", a); // 打印命名空间中的成员a
	return 0;
}

2.C++输⼊&输出

在学习任何语言的时候,我们首先会向 世界问好!也就是会在屏幕上打印 hello world!
那么用 C++ 如何打印呢?很简单。

#include <iostream>
using namespace std;

int main()
{
	cout << "hello world!" << endl;

	return 0;
}

运行结果:

在这里插入图片描述

代码解释:

• 是 Input Output Stream 的缩写,是标准的输⼊、输出流库,定义了标准的输⼊、输
出对象。

• cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要通过命名空间的使⽤⽅式去⽤他们。

• ⼀般⽇常练习中我们可以using namespace std,实际项⽬开发中不建议using namespace std。

• std::cin 是 istream 类的对象,它主要⾯向窄字符(narrow characters (of type char))的标准输
⼊流。

• std::cout 是 ostream 类的对象,它主要⾯向窄字符的标准输出流。

• std::endl 是⼀个函数,流插⼊输出时,相当于插⼊⼀个换⾏字符加刷新缓冲区。

• <<是流插⼊运算符,>>是流提取运算符。(C语⾔还⽤这两个运算符做位运算左移/右移)

• 使⽤C++输⼊输出更⽅便,不需要像printf/scanf输⼊输出时那样,需要⼿动指定格式,C++的输⼊输出可以⾃动识别变量类型,其实最重要的是C++的流能更好的⽀持⾃定义类型对象的输⼊输出。

• 这⾥我们没有包含<stdio.h>,也可以使⽤printf和scanf,在包含间接包含了。vs系列
编译器是这样的,其他编译器可能会报错。

注意:在io需求⽐较⾼的地⽅,如部分⼤量输⼊的竞赛题中,加上以下3⾏代码,可以提⾼C++ IO效率:

int main()
{
	// 在io需求⽐较⾼的地⽅,如部分⼤量输⼊的竞赛题中,加上以下3⾏代码
	// 可以提⾼C++IO效率
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	
	return 0;
}

3.缺省参数

在C语言中,函数没有指定参数列表,默认可以接收任意多个参数,但在 C++ 中,因为严格的参数类型检测,没有参数列表的函数,默认为 void,不接收任何参数。

3.1 缺省参数的概念

缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调⽤该函数时,如果没有指定实参则采⽤该形参的缺省值,否则使⽤指定的实参,缺省参数分为全缺省和半缺省参数。(有些地⽅把缺省参数也叫默认参数)。

#include <iostream>
#include <assert.h>
using namespace std;

void Func(int a = 0)
{
	cout << a << endl;
} 

int main()
{
	Func(); // 没有传参时,使⽤参数的默认值
	Func(10); // 传参时,使⽤指定的实参
	return 0;
}

运行结果:
在这里插入图片描述

3.2 缺省参数的分类

缺省参数分为两类:一类是全缺省参数,另一类是半缺省参数。

(1)全缺省参数

•全缺省参数所有参数都有默认值,如果没有手动传参,那么编译器会使用默认参数列表中的参数。
•但是这里值得注意的是,如果传参的时候只传了部分参数,那么该值会被 从左至右 匹配.

#include <iostream>
using namespace std;

void Test(int a = 1, int b = 2, int c = 3)
{
    cout << a << " " << b << " " << c << endl;
}

int main()
{
    Test();
    Test(10);
    Test(10, 20);
    Test(10, 20, 30);

    return 0;
}

在这里插入图片描述

(2)半缺省参数

半缺省参数,即函数的参数不全是缺省参数。

void Test1(int a ,int b = 2, int c = 3)
{
    cout << a << " " << b << " " << c << endl;
}

void Test2(int a, int b, int c = 3)
{
    cout << a << " " << b << " " << c << endl;
}

其中 Test1 函数至少传一个参数,Test 2函数至少传两个参数,函数才可以正常运行。

注意事项

(1)半缺省参数必须从右往左依次来缺省,不能间隔着给。

// 错误示例
void Test(int a, int b = 20, int c)
{
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
}

// 正确示例
void Test(int a, int b = 20, int c = 30)
{
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
}

(2)函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。

错误示例:
// Test.h(函数声明)
void Test(int a, int b, int c = 30);

// Test.c(函数定义)
void TestFunc(int a, int b, int c = 30) {
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
}

//-------------------------------------------

正确示例:
// Test.h(函数声明)
void Test(int a, int b, int c = 30);

// Test.c(函数定义)
void TestFunc(int a, int b, int c) {
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
}

(3)缺省值必须是常量或全局变量

// 正确示例

int x = 30; //全局变量
void Test(int a, int b = 20, int c = x)
{
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
}

4.函数重载

C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同或者参数顺序不同。这样C++函数调⽤就表现出了多态⾏为,使⽤更灵活。C语⾔是不⽀持同⼀作⽤域中出现同名函数的。

#include <iostream>
using namespace std;

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

double Test(double a, double b) {
	return a + b;
}

double Test(int a, double b) {
	return a + b;
}

int main()
{
	cout << Test(10, 20) << endl;
	cout << Test(5.5, 5.5) << endl;
	cout << Test(10, 5.5) << endl;

	return 0;
}

运行结果:
在这里插入图片描述

注意: 返回值不同不能作为重载条件,因为调⽤时也⽆法区分

 
//void fxx()
//{
// return 0;
//}
//
//int fxx()
//{
// return 0;
//}

5.引⽤

5.1引⽤的概念和定义

引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名,编译器不会为引⽤变量开辟内存空间,它和它引⽤的变量共⽤同⼀块内存空间。
⽐如:⽔壶传中李逵,宋江叫"铁⽜",江湖上⼈称"⿊旋⻛";林冲,外号豹⼦头;

使用的基本形式为:类型& 引⽤别名 = 引⽤对象;

#include<iostream>
using namespace std;

int main()
{
	int a = 0;
	// 引⽤:b和c是a的别名
	int& b = a;
	int& c = a;
	// 也可以给别名b取别名,d相当于还是a的别名
	int& d = b;
	++d;
	// 这⾥取地址我们看到是⼀样的
	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	cout << &d << endl;
	return 0;
}

在这里插入图片描述

5.2 引⽤的特性

(1)引⽤在定义时必须初始化

错误用法:

int a = 10;
int& b; // 定义b时,没有进行初始化
b = a;

正确用法:

int a = 10;
int& b = a; // 定义时必须初始化

(2)⼀个变量可以有多个引⽤

int a = 10;
int& b = a;
int& c = a;
int& d = a;

此时,b、c、d都是变量a的引用。

(3)引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体

创建一个 变量 a,再创建一个 变量 b,那么ba的引用。

int a = 10;
int& b = a;

那么我再创建一个变量 c,想让 b成为c的引用。

int a = 10;
int& b = a;

int c = 20;
b = c;

注意:此时,b已经是a的引用了,b不能再引用其他实体,它是意思是,将b引用的实体赋值为c,也就是将变量 a的内容改成了 20。

运行结果:
在这里插入图片描述

5.3 const引⽤

引用类型必须和引用实体是同种类型的。

但是仅仅是同种类型,还不能保证能够引用成功,我们若用一个普通引用类型去引用一个被 const 所修饰的类型,那么引用将不会成功。

我们对于引用取别名的原则是:对原引用变量,权限只能缩小,不能放大。

(1)权限变大
下面代码中,a 变量用 const 修饰,说明变量不能被修改,是只读的,那么我们定义别名的时候,也必须拿const 修饰:

int main()
{
	const int a = 10; //变量a是只读的

	//这里的b属于权限的放大,编译会报错
	int& b = a; //b是a的别名,但b是可读可写的

	const int& c = a; //c是a的别名,和a一样,c是只读的

	return 0;
}

可以看到,编译会报错:
在这里插入图片描述

(2)权限变小
下面代码中,a 变量的内容是 可读可写 的,也就是说此时权限是最大的,那么我们可以控制b的权限,让它变成只读:

int main()
{
	int a = 10; //可读可写

	const int& b = a; //只读权限

	//打印b(读权限)
	cout << b << endl;

	//这里如果再对b进行修改,会报错
	b = 20;
	return 0;
}

可以看到,编译会报错:
在这里插入图片描述
(3)临时变量

需要注意的是类似 int& rb = a*3; double d = 12.34; int& rd = d; 这样⼀些场景下a*3的和结果保存在⼀个临时对象中, int& rd = d 也是类似,在类型转换中会产⽣临时对象存储中间值,也就是,rb和rd引⽤的都是临时对象,⽽C++规定临时对象具有常性,所以这⾥就触发了权限放⼤,必须要⽤常引⽤才可以。

所谓临时对象就是编译器需要⼀个空间暂存表达式的求值结果时临时创建的⼀个未命名的对象,
C++中把这个未命名对象叫做临时对象。

int main()
{
	double d = 2.2;
	
	int& a = d; //编译不通过,会报错
	
	const int& b = d;

	return 0;
}

可以看到,编译会报错:
在这里插入图片描述
总结:
·const 引用的好处是保护实参,避免被误改,且它可以传普通对象也可以传 const 对象。
函数传参如果想减少拷贝使用引用传参,如果函数中不改变这个参数最好使用 const 引用传参.。

5.4 使用场景

引⽤在实践中主要是于引⽤传参和引⽤做返回值中减少拷⻉提⾼效率和改变引⽤对象时同时改变被引⽤对象。

(1)做参数

在 C 语言中,我们学习过 交换函数,当时深入剖析了 传值传址

现在我们学习了引用,可以不用 传址 了。

#include <iostream>
using namespace std;

void Swap1(int* p1, int* p2) {
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

void Swap2(int& rx, int& ry) {
	int temp = rx;
	rx = ry;
	ry = temp;
}

int main()
{
	int x = 3, y = 5;

	Swap1(&x, &y); // C传参
	Swap2(x, y); // C++传参

	return 0;
}

因为这里 rx 和 ry 是传入实参的引用,我们将x和y的值交换,就相当于将传入的两个实参交换了。

(2)做返回值

思考一下为什么需要使用 引用 来做返回值呢?

下面这段代码中,我在 Cout 函数里面定义了一个静态变量,那么出了作用域以后,n不会被销毁,如果我们使用传值返回的话,会产生一个临时变量,意味着会有一个临时拷贝,那么程序的效率也就降低了。

int Cout() {
	static int n = 0;
	n++;
	return n;
}

int main()
{
	int ret = Cout();
	cout << ret << endl;

	ret = Cout();
	cout << ret << endl;
	return 0;
}

所以我们可以给 Cout 函数的返回值加上一个引用,那么当我们返回n时,主函数里面使用 ret 来接收,那么这个ret 就是n的别名,也就是说,传引用返回以后,就没有生成一个临时拷贝了,函数返回的直接就是返回变量的别名。

代码如下:

int& Cout() {
	static int n = 0;
	n++;
	return n;
}

int main()
{
	int ret = Cout();
	cout << ret << endl;

	ret = Cout();
	cout << ret << endl;
	return 0;
}

但是要特别注意,我们返回的数据不能是函数内部创建的普通局部变量,因为在函数内部定义的普通的局部变量会随着函数调用的结束而被销毁。

我们返回的数据必须是被 static 修饰,或者是 动态开辟 的,再或者是 全局变量 等一些不会随着函数调用的结束而被销毁的数据。

总结:

如果函数返回时,出了函数作用域,返回对象还未还给系统,则可以使用引用返回;

如果已经还给系统了,则必须使用传值返回。

5.5 指针和引⽤的关系

C++中指针和引⽤就像两个性格迥异的亲兄弟,指针是哥哥,引⽤是弟弟,在实践中他们相辅相成,功能有重叠性,但是各有⾃⼰的特点,互相不可替代。

• 语法概念上引⽤是⼀个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间。

• 引⽤在定义时必须初始化,指针建议初始化,但是语法上不是必须的。

• 引⽤在初始化时引⽤⼀个对象后,就不能再引⽤其他对象;⽽指针可以在不断地改变指向对象。

• 引⽤可以直接访问指向对象,指针需要解引⽤才是访问指向对象。

• sizeof中含义不同,引⽤结果为引⽤类型的⼤⼩,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8byte)

• 指针很容易出现空指针和野指针的问题,引⽤很少出现,引⽤使⽤起来相对更安全⼀些。

6.内联函数

6.1内联函数概念

⽤inline修饰的函数叫做内联函数,编译时C++编译器会在调⽤的地⽅展开内联函数,这样调⽤内联函数就不需要建⽴栈帧了,就可以提⾼效率。

代码示例:

#include <iostream>
using namespace std;

int Add(int x, int y)
{
	return x + y;
}

int main()
{
	int ret = 0;
	ret = Add(1, 2);
	return 0;
}

这就是一个简单的 加法 函数,我们可以转到 反汇编,然后能看到调用栈帧的过程(call 指令用于调用其他函数)

在这里插入图片描述

如果在上述函数前增加 inline 关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。

#include <iostream>
using namespace std;

inline int Add(int x, int y)
{
	return x + y;
}

int main()
{
	int ret = 0;
	ret = Add(1, 2);
	return 0;
}

在这里插入图片描述
从汇编代码中可以看出,内联函数调用时并没有调用函数这个过程的汇编指令。

6.2 内敛函数的特性

(1)inline 是一种以空间换时间的做法,省去调用函数额开销。所以 代码很长 或者 有循环 或者 有递归 的函数不适宜使用作为内联函数。

(2)inline 对于编译器而言只是一个建议,编译器会自动优化,如果定义为 inline 的函数体内 有循环 或者有递归 等等,编译器优化时会忽略掉内联。

(3)inline 不建议声明和定义分离,分离会导致链接错误。因为 inline 被展开,就没有函数地址了,链接就会找不到。

// F.h
#include <iostream>
using namespace std;
inline void f(int i);

// F.cpp
#include "F.h"
void f(int i)
{
 cout << i << endl;
}

// Test.cpp
#include "F.h"
int main()
{
 f(10);
 return 0;
}

可以看到,编译时会报错:

在这里插入图片描述

7.指针空值nullptr

这也是C++11中的特性

7.1 C++98中的指针空值

在良好的 C/C++ 编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现不可预料错误,比如未初始化的指针。

如果一个指针没有合法的指向,我们基本都是按照如下方式对其进行初始化。

void TestPtr() 
{
 	int* p1 = NULL;
 	int* p2 = 0;
}

NULL实际是⼀个宏,在传统的C头⽂件(stddef.h)中,可以看到如下代码:

/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else  /* __cplusplus */
#define NULL    ((void *)0)
#endif  /* __cplusplus */
#endif  /* NULL */

可以看到,NULL可能被定义为字⾯常量0,或者C中被定义为⽆类型指针(void*)的常量。不论采取何种定义,在使⽤空值的指针时,都不可避免的会遇到⼀些⿇烦。

比如:本想通过f(NULL)调⽤指针版本的f(int*)函数,但是由于NULL被定义成0,调⽤了f(int x),因此与程序的初衷相悖。f((void*)NULL);调⽤会报错。

#include <iostream>
using namespace std;

void f(int) 
{
	cout << "f(int)" << endl;
}

void f(int*) 
{
	cout << "f(int*)" << endl;
}

int main()
{
	f(0); //调用f(int)
	f(NULL); //也是调用f(int)

	return 0;
}

程序本意是想通过 f(NULL)调用指针版本的 f(int*)函数,但是由于 NULL 被定义成0,所以 f(NULL)最终调用的是 f(int)函数。

注意:

•·在 C++98 中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量。

•但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0 。

7.2 C++11中的指针空值

对于 C++98 存在的问题,C++11 引入了关键字 nullptr

但是,还得注意:

(1)在使用 nullptr 表示指针空值时,不需要包含头文件,因为 nullptrC++11 作为新关键字引入的。

(2)在C++11中,**sizeof(nullptr)**与 *sizeof((void)0)**所占的字节数相同。

(3)为了提高代码的健壮性,在后续表示指针空值时建议最好使用 nullptr

8 总结

这是 C++ 入门的第一篇,学习 C++ 语言就像学一门活跃使用中的外语,你不要期望能够掌握所有的单词和语法规则一那对于世界上 99.999999% 的人来说是不可能的。但语言是服务于人的,语法规则也是服务于人的,是为了让人们能够更好地沟通和表达。

虽然C++的每一个新标准都是让语言从定义和规则的角度变得更复杂,但从用法上来说,新标准允许人们能够更简单地表达自己的计算意图。跟学外语一样,我们需要的是多看多写,掌握合适的“语感”,而不是记住所有的规则。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/797508.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux_进程周边知识——理解冯诺依曼体系结构

前言&#xff1a; 本篇内容是为了让友友们较好地理解进程的概念&#xff0c; 而在真正了解进行概念之前&#xff0c; 要先了解一下冯诺依曼体系结构。 所以博主会先对冯诺伊曼体系结构进行解释&#xff0c; 然后再讲解进程的概念。 ps&#xff1a; 本篇内容适合了解一些linux指…

【redis操作语句】

1.数据库操作 redis默认有16个数据库&#xff0c;编号为0~15&#xff0c;且默认访问0号数据库 获取当前键值对数量:先set创建一个键值对,再用dbsize获取&#xff0c;flushdb清空再获取。 127.0.0.1:6379> set k1 v1 OK 127.0.0.1:6379> dbsize (integer) 1 127.0.0.1:…

opencv 中如何通过欧式距离估算实际距离(厘米)

1&#xff1a;这个方法个人测试觉得是正确的&#xff0c;误差较小&#xff0c;目前满足我当前的需求&#xff0c;如果方法不对&#xff0c;请大家评论&#xff0c;完善。 2&#xff1a;确保拍摄的参照物是垂直的&#xff0c;如果不垂直&#xff0c;就会有误差&#xff0c;不垂…

基于SpringBoot+Hadoop+python的物品租赁系统(带1w+文档)

基于SpringBootHadooppython的物品租赁系统(带1w文档) 基于SpringBootHadooppython的物品租赁系统(带1w文档) 物品租赁系统是电子、信息技术相结合&#xff0c;是一种必然的发展趋势。以互联网为基础&#xff0c;以服务于广大用户为目的&#xff0c;发展整体优势&#xff0c;扩…

Flutter实现局部刷新的几种方式

目录 前言 1.局部刷新的重要性 1.概念 2.重要性 2.局部刷新实现的几种方式 1.使用setState方法进行局部刷新 2.使用StatefulWidget和InheritedWidget局部刷新UI 3.ValueNotifier和ValueListenableBuilder 4.StreamBuilder 5.Provider 6.GetX 7.使用GlobalKey 前言 …

游戏三倍补帧工具 Lossless Scaling v2.9.0

运行时请将游戏窗口化或全屏 比如你的显示器是144hz 把游戏限制帧率到48帧后开启三倍补帧 允许撕裂和垂直同步一起来延迟更低 72,48,36&#xff0c;分别对应1/2&#xff0c;1/3&#xff0c;1/4&#xff0c;性能够的话&#xff08;补帧后满144fps&#xff09;就优先锁72fps&a…

自动驾驶中的人机互相接管问题讨论

一、背景 人机接管&#xff08;human takeover&#xff09;是指在自动驾驶过程中&#xff0c;当系统遇到超出其处理能力或预设安全阈值的情况时&#xff0c;将控制权交还给驾驶员的过程。这一环节的设计直接关系到自动驾驶技术的实用性与安全性&#xff0c;是目前研究和实践中…

深入解析双向链表与单向链表的区别:示例详解

文章目录 一、单向链表与双向链表的定义及结构二、单向链表与双向链表的区别示例插入操作删除操作 三、完整示例四、总结 链表是一种灵活的数据结构&#xff0c;它通过指针连接一系列节点&#xff0c;实现了动态数组的特性。在众多链表类型中&#xff0c;单向链表和双向链表是最…

vue2学习笔记2-老规矩,从Hello World开始,了解Vue实例和模板

想要实现的效果&#xff1a;在页面上展示“Hello&#xff0c;World”字符串 1、准备一个【容器】div 想要把“Hello&#xff0c;World”放置在页面上&#xff0c;首先需要准备一个HTML的块级元素div&#xff0c;来承接内容。所以&#xff0c;我们先在<body>中定义<di…

Android12 MultiMedia框架之GenericSource extractor

前面两节学习到了各种Source的创建和extractor service的启动&#xff0c;本节将以本地播放为例记录下GenericSource是如何创建一个extractor的。extractor是在PrepareAsync()方法中被创建出来的&#xff0c;为了不过多赘述&#xff0c;我们直接从GenericSource的onPrepareAsyn…

《昇思25天学习打卡营第17天|K近邻算法实现红酒聚类》

K近邻算法原理介绍 K近邻算法&#xff08;K-Nearest-Neighbor, KNN&#xff09;是一种用于分类和回归的非参数统计方法&#xff0c;最初由 Cover和Hart于1968年提出是机器学习最基础的算法之一。它正是基于以上思想&#xff1a;要确定一个样本的类别&#xff0c;可以计算它与所…

springboot在线教育平台-计算机毕业设计源码68562

摘要 在数字化时代&#xff0c;随着信息技术的飞速发展&#xff0c;在线教育已成为教育领域的重要趋势。为了满足广大学习者对于灵活、高效学习方式的需求&#xff0c;基于Spring Boot的在线教育平台应运而生。Spring Boot以其快速开发、简便部署以及良好的可扩展性&#xff0c…

TypeError: Rule.__init__() got an unexpected keyword argument ‘method‘报错的解法

报错如图&#xff1a; 原代码&#xff1a; app.route(/query,method[get,post]) 解决办法很简单&#xff0c;method后加s​​​​​​​ app.route(/query,methods[get,post]) 重新执行代码&#xff0c;不报错了

C++ QT开发 学习笔记(1)

C QT开发 学习笔记(1) 考试系统 创建项目 新建Qt桌面应用程序&#xff0c;项目名&#xff1a;ExamSys。 类信息&#xff1a;类名LoginDialog继承自QDialog &#xff08;1&#xff09; ExamSys.pro 工程文件&#xff0c;包含当前工程的相关信息。 QDialog 是 Qt 框架中用…

大数据基础:Hadoop之MapReduce重点架构原理

文章目录 Hadoop之MapReduce重点架构原理 一、MapReduce概念 二、MapReduce 编程思想 2.1、Map阶段 2.2、Reduce阶段 三、MapReduce处理数据流程 四、MapReduce Shuffle 五、MapReduce注意点 六、MapReduce的三次排序 Hadoop之MapReduce重点架构原理 一、MapReduce概…

JavaScript中的面向对象编程

OPP在JavaScript的表现方式&#xff1a;原型 传统的OPP&#xff1a;类 ● 对象&#xff08;实例&#xff09;由类实例化&#xff0c;类的功能类似于蓝图&#xff0c;通过蓝图来实现建筑&#xff08;实例&#xff09; ● 行为&#xff08;方法&#xff09;从类复制到所有实例 …

【2-1:RPC设计】

RPC 1. 基础1.1 定义&特点1.2 具体实现框架1.3 应用场景2. RPC的关键技术点&一次调用rpc流程2.1 RPC流程流程两个网络模块如何连接的呢?其它特性RPC优势2.2 序列化技术序列化方式PRC如何选择序列化框架考虑因素2.3 应用层的通信协议-http2.3.1 基础概念大多数RPC大多自…

并查集——AcWing 239. 奇偶游戏

目录 并查集 定义 运用情况 注意事项 解题思路 AcWing 239. 奇偶游戏 题目描述 运行代码 代码思路 改进思路 并查集 定义 并查集&#xff08;Disjoint Set Union&#xff0c;简称DSU&#xff09;&#xff0c;是一种树形的数据结构&#xff0c;常用于处理一些不交集…

jvm 07 GC算法,内存池

01 垃圾判断算法 1.1引用计数算法 最简单的垃圾判断算法。在对象中添加一个属性用于标记对象被引用的次数&#xff0c;每多一个其他对象引用&#xff0c;计数1&#xff0c; 当引用失效时&#xff0c;计数-1&#xff0c;如果计数0&#xff0c;表示没有其他对象引用&#xff0c;…

一文详解DDL同步及其应用场景

目录 一、什么是DDL&#xff1f; 二、什么是DDL同步&#xff1f; 三、DDL同步的痛点 1、缺少自动DDL同步机制 2、缺少DDL变更监测预警 四、解决方案 五、应用场景及案例 案例一 案例二 案例三 在现代数据管理中&#xff0c;数据库的结构变更频繁且不可避免&#xff0c;特别是在…