C++的入门

news2024/11/25 22:25:02

C++的关键字

C++总计63个关键字,C语言32个关键字
在这里插入图片描述

命名空间

我们C++的就是建立在C语言之上,但是是高于C语言的,将C语言的不足都弥补上了,而命名空间就是为了弥补C语言的不足。

看一下这个例子。在C语言中会报错

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

int rand = 10;

int main()
{
	printf("%d ", rand);
	return 0;
}

在这里插入图片描述

原因就是在我们#include<stdlib.h>中,定义了rand ,但是我们自己也定义了一个全局变量rand,这样就重定义了,C语言无法解决这个问题。
所以我们这是C++,为了解决这个问题,就引用了命名空间的概念。

我们在C语言中,我们们接触的一共有两个,
一个是全局域,一个是局部域。他们的使用,和生命周期不一样。
而在这两个域中,我们可以声明同一个名字的变量,这是可以的。

但是我们想在局部作用域中,找命名相同的全局域的东西可以吗?
答案是可以的,这是就要用到我们的域作用符 ::,前面的空格就表示全局域。
看下面代码

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

int a = 10;

void f1()
{
	int a = 0;
	printf("%d\n", a);
	printf("%d\n", ::a);
}

int main()
{
	f1();
	return 0;
}

在这里插入图片描述

命名空间定义了什们?
命名空间域,只影响使用,不影响生命周期。
这时就需要一个关键字— namespace
命名空间怎么用?
当我们的命名存在冲突的时候,将各自的内容用 namespace定义的域包括起来(这时我们自己定义这个域名),当我们要找的时候就用就域操作符 ::,找到我们的域名,就可以找到我们的命名冲突的东西。请看下列例子。
namespace List
{
	struct Node
	{
		struct QNode* next;
		struct QNode* prev;
		int val;
	};
}

namespace Queue
{
	struct Node
	{
		struct QNode* next;
		int val;
	};

}

int main()
{
	//f1();
	struct Queue::Node node1;
	struct List::Node node2;
	return 0;
}

注意我们的命名空间,可以嵌套。

使用方法

1.指定命名空间访问。

每次使用的时候,我们都使用域作用符表明他的域

namespace Queue
{
	struct Node
	{
		struct QNode* next;
		int val;
	};
	struct QueueNode
	{
		struct Node* head;
		struct Node* tail;
	};

	void QueueInit(struct QueueNode* q)
	{

	}
	void QueuePush(struct QueueNode* q,int x)
	{

	}
}

int main()
{
	struct Queue::QueueNode q;
	Queue::QueueInit(&q);
	Queue::QueuePush(&q,1);
	Queue::QueuePush(&q,2);
}

2.全局展开(一般情况,不建议全局展开)

我们用一次展开一次,太繁琐了,我们怎样可以简单一点呢?

就是用全局展开,
代码为using namespace + 域名

namespace Queue
{
	struct Node
	{
		struct QNode* next;
		int val;
	};
	struct QueueNode
	{
		struct Node* head;
		struct Node* tail;
	};

	void QueueInit(struct QueueNode* q)
	{

	}
	void QueuePush(struct QueueNode* q,int x)
	{

	}
}

using namespace Queue;

int main()
{
	struct QueueNode q;
	QueueInit(&q);
	QueuePush(&q,1);
	QueuePush(&q,2);
}

所以我们写C++,代码的时候,
我们要加上一句using namespace std,将我们库文件的东西全局展开。
但是这种方法不太好,将我们好不容易建立的库,就有展开了,相当于没有命名空间了
所以我们以后进公司写项目,禁止这样写代码,但是我们在前期学习阶段,我们是可以这样的,因为这样很方便。

3.部分展开

就是将常用的展开。具体看下面的例子

#include<iostream>

//常用的展开
using std::cout;
using std::endl;

int main()
{
	cout << "1111" << endl;
	cout << "1111" << endl;
	cout << "1111" << endl;
	cout << "1111" << endl;
	
	int i = 0;
	std::cin >> i;
}

cin和cout的理解

其实就是流,输入流,和输出流。
我们可以简单的认为,
cout相当于printf
cin相当于scanf

他们的优势
自动识别类型。
不用想我们的 printfscanf需要指定类型, %d, %f,但是我这个就不用,他自动识别类型。
#include<iostream>
using namespace std;

int main()
{
	cout << "hello world" << endl;
	cout << "hello world" << '\n';

	int n;
	double* a = (double*)malloc(sizeof(double) * n);
	if (a == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
	}
	for (int i = 0; i < n; i++)
	{
		cout << a[i] << endl;
	}
}

在这里插入图片描述

缺省参数

也是为了弥补c语言的缺陷。

这是通过函数使用的,在c语言中,当我们的函数有参数的时候,我们在用这个函数的时候,我们必须传这个参数。
而缺省参数的作用,就是我们在函数传参的时候,可以不用传参数。在我们不传参数的时候,就会把我们的默认参数传上。

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

int main()
{
	Func(1);
	Func();
	return 0;
}

在这里插入图片描述

多个缺省参数

//全缺省
void Func(int a = 10, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;

	cout << endl;

}

int main()
{
	Func(1, 2, 3);
	Func(1, 2);
	Func(1);
	Func();
	return 0;
}

在这里插入图片描述

注意:不可以跳着传,使用缺省值,必须从右往左连续使用
下列用法不可以,这是规定没有为什们
Fun( ,2, );
Fun( , , 3);

半缺省

注意:必须从右往左连续缺省,不能跳跃缺省

//这样是可以的
void Func(int a, int b = 10, int c = 20) 
 {
     cout<<"a = "<<a<<endl;
     cout<<"b = "<<b<<endl;
     cout<<"c = "<<c<<endl; 
 }
int main()
{
	Func(1, 2, 3);
	Func(1, 2);
	Func(1);
	
	return 0;
}
//这样是错误的,完全不可以
void Func(int a = 10, int b , int c = 20) 
 {
     cout<<"a = "<<a<<endl;
     cout<<"b = "<<b<<endl;
     cout<<"c = "<<c<<endl; 
 }
注意
缺省参数不能在函数声明和定义中同时出现。
推荐在声明的时候给我们的缺省参数)
如果生命与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该 用那个缺省值。
	void Func(int a = 10); 
 	void Func(int a = 20) 
  	{}

函数重载

其实这也是为了解决c语言的缺陷,当一个函数同名的时候,我们就会重定义。

可能你会想,为什们要函数重载,函数本来就不能同名呀。
那你大错特错了,我们看完下面这个例子就知道了。

函数重载的定义
函数重载:是函数的一种特殊情况,C++允许在 同一作用域中声明几个功能类似的同名函数,这 些同名函数的形参列表( 参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。

函数返回值不同,不能构成函数重载。
是因为我们调用的时候可以不接受返回值,但是和没有返回值的函数无法区分,所以才不可以。

参数类型不同

// 1、参数类型不同
int Add(int left, int right)
{
	cout << "int Add(int left, int right)" << endl;
	
	return left + right;
}
double Add(double left, double right)
{
	cout << "double Add(double left, double right)" << endl;
	
	return left + right;
}
int main()
{
	Add(1, 2);
	Add(1.1, 2.2);
	return 0;
}

参数个数不同

// 2、参数个数不同 
void f()
{
	cout << "f()" << endl;
}
void f(int a) 
{
	cout << "f(int a)" << endl;
}

参数顺序不同

// 3、参数类型顺序不同 
void f(int a, char b)
{
	cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
	cout << "f(char b, int a)" << endl;
}

编译器怎么分辨这些相同名字的函数呢

  1. 实际项目通常是由多个头文件和多个源文件构成,我们知道,【当前a.cpp中调用了b.cpp中定义的Add函数时】,编译后链接前,a.o的目标
    文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。那么怎么办呢?
  2. 所以链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就会到b.o的符号表中找Add的地址,然后链接到一起。
  3. 那么链接时,面对Add函数,链接接器会使用哪个名字去找呢?这里每个编译器都有自己的 函数名修饰规则。
  4. 由于Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,下面我们看g++演示了这个修饰后的名字。
  5. 通过下面我们可以看出gcc的函数修饰后名字不变。而g++的函数修饰后变成【_Z+函数长度 +函数名+类型首字母】。

引用

什们是引用?(就是取别名)
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
比如:你有大名和小名,但那都是你,而引用就相当于这个。
引用怎么写?
就是类型后面加一个&。
要区别赋值和引用。
在这里插入图片描述

那我们用一下&,写一下我们的交换函数,就不用再传指针了。

//输出型参数
//形参的改变要影响实参。
void Swap(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int i = 10;
	int j = 20;
	Swap(i, j);
	printf("i=%d\n", i);
	printf("j=%d\n", j);
	return 0;
}

引用特征

  1. 引用必须在定义的时候初始化。
  2. 一个变量可以有多个引用

引用做返回值

我们先看一个场景,看完下面这个场景,我问一个问题,

在函数的返回值中我们是将函数中的n返回了吗?
答案是否定的,我们 n是一个局部变量,他的生命周期就是在函数中,一但出了函数,那么它就会被销毁。
那么有的同学就会想:他是怎么传出来的呢?
其实编译器会将我们的 n拷贝一个临时变量(临时变量具有常性),然后用这个临时变量将我们的 n传给我们的 ret

同时我们想优化一下他,我们也是不可以的,我们没有办法优化,但是我们看第二个例子

int  count()
{
	int n = 0;
	n++;
	return n;
}
int main()
{
	int ret = count();
	return 0;
}

第二个例子不太一样,我们的n存放在静态区,当函数被销毁的时候我们的n还在,但是这是有的同学会问,那么它传返回值是直接用n传吗?
答案并不是,编译器并不能分辨他们是哪一种,只会进行他的操作,跟上面一样还是产生一个n的临时拷贝,用的这个临时拷贝传个ret

怎么优化?
我们想要优化一下这个,怎么优化?我们学习了引用,就是产生一个别名,我们可以通过改变别名来改变这个东西。
因为我们这里的 n并不会被销毁,如果我们在返回的时候用引用。
这时我们还会像上面的操作一样产生一个临时变量,但是这个临时变量就不是我们的临时拷贝而是我们 n的一个别名,我们如果想改变 n,我们就可以通过改变返回值改变我们的 n
int  count()
{
	static int n = 0;
	n++;
	return n;
}
int main()
{
	int ret = count();
	return 0;
}

这就是引用返回。

int&  count()
{
	static int n = 0;
	n++;
	return n;
}
int main()
{
	int ret = count();
	return 0;
}

什们场景下可以使用引用返回?

: 大家可能想到的是我们的静态变量,全局变量。结构体。
其实这些东西用一句话来说就是出了函数作用域,不被销毁的变量就可以。

引用返回的作用

通过上面的介绍我们知道了什们是引用返回,但是我们有这个有什么作用?我们什们情况下会用到这个。
那就看看下面这个例子。

#include<assert.h>
#define N 10

typedef struct Array
{
	int a[N];
	int size;
}AY;

//因为这个结构体在我们函数销毁完,我们还在所以可以用引用返回
int& PosAY(AY& ay, int i)
{
	assert(i < N);
	return ay.a[i];
}
int main()
{
	AY ay;

	//修改返回值
	for (int i = 0; i < N; i++)
	{
		PosAY(ay, i) = i * 10;
	}
	//打印出来验证
	for (int i = 0; i < N; i++)
	{
		cout << PosAY(ay, i) << " ";
	}
	return 0;
}
作用一
减少拷贝。
我们如果不用引用返回,那么我们在返回的时候我们要创建一个临时变量,将我们需要传的数据拷贝给临时变量。而我们的引用返回,直接将这个临时变量当作他的别名。
作用二
调用者可以修改返回对象
既然临时变量已经是我们要传的数据的别名,那么我们就可以修改返回对象来修改我们的数据。

下面我们在看一个例子

int& Add(int a, int b)
{
	int c = a + b;
	return c;
}
int main()
{
	int& ret = Add(1, 2);
	Add(3, 4);
	cout << "Add(1, 2) is :" << ret << endl;
	cout << "Add(1, 2) is :" << ret << endl;
	return 0;
}

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

这是一个错误的程序,我们这个函数,在我们出去了这个函数,函数就会被销毁,而我们c是一个局部变量,也就说明c在出来函数也被销毁。
但是我们在传返回值的时候我们传的是引用返回,我们传的是别名,这时ret就是别名,但是已经销毁了,我们的别名就已经没有意义。

有的同学就问,那我们第一次是7呢,是因为在vs编译器下,函数销毁并没有清理空间,我们访问可以找到。但是第二次已经处理了,所以我们就是随机值了。

常引用

我们先看例子。

int main()
{
	int a = 1;
	int& b = a;

	const int c = 2;
	//错误
	//int& d = c;
}

我们的指针和引用,在进行赋值和初始化,权限可以缩小,但是权限不能放大。
就是我们上面对于c来说,cconst修饰,是一个不可修改的变量。
但是呢我们用d引用c,尽然可以让d修改,进而改变c,这显然是不合法的。这时我们就能理解为什们权限不能放大。但是权限可以平移。

解决方法,就是在引用的时候也变成被const修饰的引用,让他变得不可修改。const int& d = c;

因为临时变量具有常性,大家看一下下面这个例子

int count()
{
	static int n = 0;
	n++;
	return n;
}
int main()
{
	int& ret = count();
	return 0;
}

上面这个代码大家千万不要以为这样可以,我们通过上面的讲解,并不是直接将我们的n返回,而是将我们的n拷贝给我们的临时变量。将其引用给ret涉及到权限的放大,这时万万不行的,所以我们的可以将ret也设置为常性。const int& ret = count();这样就可以了。

我们再看一个代码。

int main()
{
	int i = 10;
	//错误
	//double& dd = i;
	const double& d = i;
	return 0;
}

为什们第一个不可以,但是第二个可以呢?
原因就是我们在进行类型转换的时候,我们会产生一个临时变量,(为什们会产生临时变量呢?我们再传的时候并不是将i直接传给d,并不能改变i,而是产生一个临时变量,将他改变,然后再赋值在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。给d。)又因为我们的临时变量具有常性,我们就必须用const修饰。

引用和指针的区别

语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

引用和指针的不同点:

  1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
  2. 引用在定义时必须初始化,指针没有要求
  3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体
  4. 没有NULL引用,但有NULL指针
  5. sizeof中含义不同引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32 位平台下占4个字节)
  6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  7. 有多级指针,但是没有多级引用
  8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  9. 引用比指针使用起来相对更安全

内联函数

C++用const和枚举替换宏常量
C++用inline去替代宏函数

宏缺点
1.不能调试
2.没有类型安全的检查
3.有些常见很复杂,很容易函数,不容易掌握。
宏优点
  1. 增强代码的复用性。
  2. 提高性能。

内联函数既包括了宏的优点,也几乎去除了宏的缺点。
看一个例子感受内联函数的使用。
其实就是还是正常写我们的函数,再其前面加上inline,在编译阶段,会用函数体替换函数调用。

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

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

内联函数的特型

1. inline是一种以空间换时间(空间指可执行程序)的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运 行效率。
2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建 议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。
3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

auto关键字

auto的作用
简化代码,自动识别类型。具体看下面代码
int main()
{
	int a = 0;

	auto b = a;
	auto c = &a;

	//typeid能看他是什们类型
	cout << typeid(b).name() << endl;
	cout << typeid(c).name() << endl;
}

在这里插入图片描述

	auto b = a;
	auto c = &a;
	//其实下面这个跟上面这个没有区别
	//就是将限定死d是指针

	auto* d = &a;
	auto& f = a;

auto在同一行定义多个变量

当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译 器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

void TestAuto() 
{
    auto a = 1, b = 2;
    auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同 
}

auto不能推导的场景

  1. auto不能作为函数的参数
    在这里插入图片描述
  2. auto不能直接用来声明数组
    在这里插入图片描述

范围for–语法糖

先看例子

int main()
{
	int a[] = { 1,2,3,4,5,5 };

	//我们平常遍历一边数组,我们用的就是for循环
	for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
	{
		cout << a[i] << " ";
	}
	cout << endl;

	//那我们用语法糖
	//其实就是自己自动依次取数组中数据赋值给n对象,自动判定结束
	//for(int n : a)
	for (auto n : a)
	{
		n *= 2;
		cout << n << " ";
	}
	cout << endl;
}

范围for只是自动依次取数组中数据赋值给n对象,自动判定结束
并不会改变数组的内容,他只是赋值。
如果想要改变数组的内容,我们就用引用,问题就可以很好的解决。

在这里插入代码片

指针空值nullptr

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

#ifndef NULL
#ifdef __cplusplus 
#define NULL    0 
#else
#define NULL    ((void *)0) 
#endif
#endif

可以看到,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何 种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦
比如下面的代码,
结果是这样的
在这里插入图片描述

void f(int) 
{
	cout<<"f(int)"<<endl; 
}
void f(int*) 
{
	cout<<"f(int*)"<<endl; 
}
int main()
{
	f(0);
	f(NULL);
	f((int*)NULL); 
	return 0;
}

所以C++使用一个关键字nullptr来解决这个麻烦

注意
  1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的.
  1. 在C++11中,sizeof(nullptr)sizeof((void*)0)所占的字节数相同。
  1. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】C++11——左右值|右值引用|移动语义|完美转发

文章目录一、左值与右值1.概念2.引用3.注意二、右值引用的意义1.左值引用意义2.右值引用和移动语义3.容器新增三、万能引用四、完美转发一、左值与右值 1.概念 左值是什么&#xff1f;右值是什么&#xff1f; 左值是一个表示数据的表达式&#xff08;如变量名或解引用的指针&…

学校学生心理测评系统

青少年在线心理测评系统 这款系统&#xff0c;是和北大合作开发&#xff0c;并真实用于线上测评场景&#xff0c;该项目有完整后台&#xff0c;以及学生管理等模块。 我们欢迎以下形式合作&#xff1a; 单纯研究项目。合作对该测评平台进行升级。单纯使用。 请联系我们 silv…

MyBatis里面用了多少种设计模式?

在MyBatis的两万多行的框架源码中&#xff0c;使用了大量的设计模式对工程架构中的复杂场景进行解耦&#xff0c;这些设计模式的巧妙使用是整个框架的精华。经过整理&#xff0c;大概有以下设计模式&#xff0c;如图1所示。图101类型&#xff1a;创建型模式▊ 工厂模式SqlSessi…

英飞凌Tricore原理及应用介绍04_中断请求及仲裁过程

目录1.概述2. 中断请求及过程仲裁3. 中断传到CPU会被即时响应吗&#xff1f;1.概述 在Tricore架构中允许有多个中断源包括片上外设及外部中断世间产生的中断请求&#xff0c;以打断中断服务的提供者如CPU或DMA通道&#xff0c;那你知道在Tricore里中断请求在内核中的仲裁及处理…

【java基础】ArrayList源码解析

文章目录基本介绍构造器指定初始容量默认创建通过集合创建添加add扩容机制批量添加addAll添加指定位置add添加多个元素到指定位置addAll删除删除指定元素remove删除指定索引元素remove条件删除removeIf批量删除removeAll修改修改指定位置set替换所有满足要求元素replaceAll一些…

vscode环境配置(支持跳转,阅读linux kernel)

目录 1.卸载clangd插件 2.安装C插件 3. 搜索框内输入 “intell”&#xff0c;将 C_Cpp&#xff1a;Intelli Sense Engine 开关设置为 Default。 4.ubuntu安装global工具 5.vscode安装插件 6.验证是否生效 7.建立索引 1.卸载clangd插件 在插件管理中卸载clangd插件 2.安…

课设-机器学习课设-实现新闻分类

✅作者简介&#xff1a;CSDN内容合伙人、信息安全专业在校大学生&#x1f3c6; &#x1f525;系列专栏 &#xff1a;课设-机器学习 &#x1f4c3;新人博主 &#xff1a;欢迎点赞收藏关注&#xff0c;会回访&#xff01; &#x1f4ac;舞台再大&#xff0c;你不上台&#xff0c;…

linux下安装SonarQube

目录1. 准备安装环境2. 安装postgres数据库3. 安装SonarQube4. 使用SonarQube1. 准备安装环境 这里安装SonarQube的系统环境是Red Hat Enterprise Linux release 8.7 &#xff0c;然后将jdk的压缩包&#xff08;jdk-17.0.2_linux-x64_bin.tar.gz&#xff09;和sonarQube的压缩…

Web Components学习(2)-语法

一、Web Components 对 Vue 的影响 尤雨溪在创建 Vue 的时候大量参考了 Web Components 的语法&#xff0c;下面写个简单示例。 首先写个 Vue 组件 my-span.vue&#xff1a; <!-- my-span.vue --> <template><span>my-span</span> </template>…

Spring——spring整合JUnit

JUnit定义: Junit测试是程序员测试&#xff0c;即所谓 白盒测试 &#xff0c;因为程序员知道被测试的软件如何&#xff08;How&#xff09;完成功能和完成什么样&#xff08;What&#xff09;的功能。 Junit是一套框架&#xff0c;继承TestCase类&#xff0c;就可以用Junit进行…

基于Selenium+Python的web自动化测试框架(附框架源码+项目实战)

目录 一、什么是Selenium&#xff1f; 二、自动化测试框架 三、自动化框架的设计和实现 四、需要改进的模块 五、总结 总结感谢每一个认真阅读我文章的人&#xff01;&#xff01;&#xff01; 重点&#xff1a;配套学习资料和视频教学 一、什么是Selenium&#xff1f; …

SpringBoot bean 加载顺序如何查看(源码解读)

背景 SpringBoot bean 加载顺序如何查看&#xff0c;想看加载了哪些bean&#xff0c; 这些bean的加载顺序是什么&#xff1f; 实际加载顺序不受控制&#xff0c;但会有一些大的原则&#xff1a; 1、按照字母顺序加载&#xff08;同一文件夹下按照字母数序&#xff1b;不同文件…

界面开发(4)--- PyQt5实现打开图像及视频播放功能

PyQt5创建打开图像及播放视频页面 上篇文章主要介绍了如何实现登录界面的账号密码注册及登录功能&#xff0c;还简单介绍了有关数据库的连接方法。这篇文章我们介绍一下如何在设计的页面中打开本地的图像&#xff0c;以及实现视频播放功能。 实现打开图像功能 为了便于记录实…

CobaltStrike攻击payload(有效载荷)介绍

HTA文档Office宏payload生成器有效载荷生成器windows可执行程序windows可执行程序windows stageless生成所有有效载荷HTA文档该模块为HTML Application attack&#xff08;HTML应用攻击&#xff09;。简单来说&#xff0c;就是这个包生成一个运行有效负载的HTML应用程序该模块下…

TCP UPD详解

文章目录TCP UDP协议1. 概述2. 端口号 复用 分用3. TCP3.1 TCP首部格式3.2 建立连接-三次握手3.3 释放连接-四次挥手3.4 TCP流量控制3.5 TCP拥塞控制3.6 TCP可靠传输的实现3.7 TCP超时重传4. UDP5.TCP与UDP的区别TCP UDP协议 1. 概述 TCP、UDP协议是TCP/IP体系结构传输层中的…

Flink 定时加载数据源

一、简介 flink 自定义实时数据源使用流处理比较简单&#xff0c;比如 Kafka、MQ 等&#xff0c;如果使用 MySQL、redis 批处理也比较简单 如果需要定时加载数据作为 flink 数据源使用流处理&#xff0c;比如定时从 mysql 或者 redis 获取一批数据&#xff0c;传入 flink 做处…

三、HTTP协议之三

文章目录一、HTTPS协议概述二、 HTTPS使用成本三、从HTTP到HTTPS四、HTTP协议的瓶颈五、双工通信的websocket六、HTTP2.0一、HTTPS协议概述 二、 HTTPS使用成本 HTTPS对性能的影响 https之所有安全是因为使用TLS(SSL)来加密传输. 三、从HTTP到HTTPS 了解个大概 第一步&#x…

react:二、jsx语法规则

目录 1.传输数据的xml和json格式举例 2.jsx语法规则 3.js语句跟js表达式的区别 4.jsx的小练习 1.传输数据的xml和json格式举例 2.jsx语法规则 1.定义虚拟DOM时&#xff0c;不要写引号。 2.标签中混入JS表达式时要用{}。 3.样式的类名指定不要用class&#xff0c;要用cla…

第十一章 寡头垄断市场中的企业决策

寡头垄断市场的定义、条件 寡头垄断市场&#xff1a;少数几家企业控制了某一行业的市场&#xff0c;供给该行业生产的大部分产品 寡头垄断市场应具备的条件&#xff1a; 一个行业或市场中&#xff0c;只有少数几家企业企业之间存在着相互制约、相互依存的关系新企业进入行业比…

golang大杀器GMP模型

golang 大杀器——GMP模型 文章目录golang 大杀器——GMP模型1. 发展过程2. GMP模型设计思想2.1 GMP模型2.2 调度器的设计策略2.2.1 复用线程2.2.2 利用并行2.2.3 抢占策略2.2.4 全局G队列2.3 go func()经历了那些过程2.4 调度器的生命周期2.5 可视化的CMP编程2.5.1 trace方式2…