C++入门3+类和对象上

news2024/10/6 14:29:18

C++入门3+类和对象上

  • 一.内联函数
    • 1.宏函数的缺点
    • 2.宏函数的优点
    • 3.内联函数的语法
    • 4.内联函数的优缺点
    • 5.内联函数的使用条件
    • 6.内联函数的展开
    • 7.内联函数的一大注意事项
      • 1.内联函数声明跟定义分离
      • 2.内联函数声明跟定义分离的"奇怪"现象
  • 二.C++11对于C++语法的补充
    • 1.auto关键字
      • 1.auto关键字可以自动推导类型
      • 2.auto的局限性
        • 1.auto不能做参数
        • 2.auto不能用作返回值
        • 3.auto不能用来定义数组
        • 4.auto定义时必须初始化
    • 2.范围for
    • 3.nullptr
  • 三.类和对象上
    • 1.C++中的结构体对于C语言的优化
      • 1.C++中结构体的定义优化
      • 2.为什么C++要引入class关键字来定义类呢?
    • 2.类的书写形式
      • 1.类的访问限定符和封装
      • 2.类的声明和定义分离
    • 3.类的大小及类的实例化
      • 1.类的大小
      • 2.不含有任何成员变量的类的大小
      • 3.类的实例化
    • 4.this指针
      • 1.this指针的引出
      • 2.被编译器隐藏的this指针
      • 3.this指针的特性
        • 1.this指针的两个经典题目
        • 2.this指针的特性
    • 5.C和C++当中关于Stack的实现对比

一.内联函数

C++针对于C语言的宏函数进行了优化,设计出了内联函数这一语法

其中在著名书籍《Effective C++》中,作者提出了一个很好的条款
他建议在C++程序中使用

enum 枚举常量,const 定义的常量来替代宏定义的常量
使用内联函数来替代宏函数

1.宏函数的缺点


关于这些情况的举例,大家可以看我的另一篇博客:
C语言预处理及宏和函数的区别与各自优劣点的详解

2.宏函数的优点

在这里插入图片描述

3.内联函数的语法

这里以Add函数为例

inline int Add(int a,int b)
{
	return a+b;
}

只需要在函数前面加上关键字inline即可
可见语法非常简单

4.内联函数的优缺点

在这里插入图片描述

5.内联函数的使用条件

既然内联函数这么好,那么我们是不是就可以把所有的函数都设计成为内联函数呢?
当然是不行的,因为内联函数也是需要在调用的地方被展开的,只不过不是简单的宏的字符串替换而已

而且:
在这里插入图片描述
一般来说C++程序中10行以上的代码就无法成为内联函数
在《C++ primer》中关于inline的建议:
在这里插入图片描述
在这里插入图片描述

6.内联函数的展开

如果我们想看一下内联函数是怎么展开的呢?
这里使用的是VS2019,在默认配置下内联函数是不会展开的
那么怎么才能展开它呢?
在debug模式下,需要对编译器进行设置(因为debug模式下,编译器默认不会对代码进行优化)
在这里插入图片描述
右键找到属性
在这里插入图片描述
在调试信息格式这里修改为程序数据库这个选项
在这里插入图片描述
修改后:
在这里插入图片描述
在内联函数扩展这里改为只适用于_inline(/Ob1)
在这里插入图片描述
然后点击应用,确定
然后我们调试查看汇编代码
在这里插入图片描述
然后我们去掉inline,调试查看汇编代码
在这里插入图片描述
发现内联函数中没有call指令,也就是说inline函数并没有开辟栈帧,直接在原位置展开了

7.内联函数的一大注意事项

内联函数是不可以将声明跟定义分离的,为什么呢?

因为内联函数会直接在调用的地方展开,所以不需要去调用(汇编代码当中的call命令),
因此内联函数就不需要将地址存到符号表当中,因此在链接的时候通过符号表去查找函数的定义时便找不到内联函数的定义,因此会发生链接时错误

1.内联函数声明跟定义分离

下面给大家演示一下这个错误
我们定义了test.h,test.cpp,main.cpp并且生成解决方案:编译器爆出了链接时错误
在这里插入图片描述
那么请大家再看一下前面这段代码

2.内联函数声明跟定义分离的"奇怪"现象

在这里插入图片描述
这里为什么调用getf函数就可以成功执行f函数了呢?

因为getf函数是在test.cpp文件中定义的,也就是说getf函数的定义是跟f函数的定义放在同一个cpp文件中的,
因此getf函数想要寻找f函数根本不需要等到链接阶段(因为它们都被编译到了同一个.o目标文件中,而链接阶段是链接多个.o目标文件的阶段)

综上,内联函数声明跟定义分离的话,这个内联函数只能在它所定义的cpp文件中使用,在其他cpp文件中无法使用
因此内联函数不要声明跟定义分离

二.C++11对于C++语法的补充

1.auto关键字

1.auto关键字可以自动推导类型

//auto关键字
//可以自动推导类型
int main()
{
	int a = 0;
	int b = a;
	auto c = a;
	auto d = &a;
	auto* e = &a;

	auto& f = a;//f是a的别名,a是int,所以f也是int,因为f就是a
	f++;

	cout << typeid(c).name() << endl;//typeid可以打印对象的类型
	cout << typeid(d).name() << endl;
	cout << typeid(e).name() << endl;
	cout << typeid(f).name() << endl;
	//指针可以显式写,也可以隐式写
	//但是引用只能显式写
	/*
	int
	int *
	int *
	int
	*/
	return 0;
}

auto的真正有价值的用法:定义对象时,如果该对象的类型较长,用auto比较方便

//auto真正的用法:定义对象时如果类型较长,用它比较方便
#include <vector>
#include <string>
int main003()
{
	vector<string> v;
	vector<string>::iterator it = v.begin();
	//简化写法:让这个类型定义的短一些,方便
	auto it = v.begin();
	return 0;
}

这里的vector容器和string容器都属于C++STL库中的知识,我们以后会进行重点介绍
iterator:迭代器,我们以后也会重点介绍

这里的vector容器就相当于数据结构中的顺序表,string就相当于数据结构中的字符串

2.auto的局限性

1.auto不能做参数

因为无法进行自动推导
可以使用模板来解决(关于模板的知识我们以后会进行重点介绍)

2.auto不能用作返回值

auto不能做返回值(新的规则可能支持了,但是VS中不支持,而且auto作为返回值的类型并不好,就像是python中的函数返回值类型一样)

因为调用函数时看不到函数的返回值,所以调用函数时很麻烦,还需要去看那个函数的源代码,太不方便了

因此就算C++引入了auto作为返回值,但是建议不要用auto作为函数的返回值

3.auto不能用来定义数组
4.auto定义时必须初始化

否则无法知道用auto定义的变量到底是什么类型

2.范围for

int main()
{
	int arr[] = { 1,2,3,4,5 };
	//一般情况下这里都用auto
	//因为如果arr变为double,auto也不用改
	//依次取数组中的数据赋值给e对象,自动判断结束,自动++往后走
	for (auto e : arr)
	{
		cout << e << " ";
	}
	cout << endl;
	for (int e : arr)
	{
		cout << e << " ";
	}
	cout << endl;
	//修改数组中的每个数据
	//需要加上&才能修改,这是指针所替代不了的
	//因为指针赋值时需要取地址,而范围for是把数组中的数据进行赋值
	for (auto& e : arr)
	{
		e *= 2;
	}
	for (auto e : arr)
	{
		cout << e << " ";
	}
	cout << endl;
	/*
1 2 3 4 5
1 2 3 4 5
2 4 6 8 10
	*/
	return 0;
}

//这里arr传参时退化为指针,所以这里不能范围for
void testfor(int arr[])
{
	for (auto e : arr)//err
	{
		cout << e << " ";
	}
}

//二维数组呢?:也是指针,只不过是指向一维数组的指针
void testfor2(int arr[3][3])
{
	//int (*)[3]:数组指针
	//所以也不可以
	for (auto e : arr)//err
	{
		cout << e << " ";
	}
}

3.nullptr

在C++中NULL的定义跟在C语言中的定义不同
在这里插入图片描述
C语言中的: ((void*)0)

C++中的: 0

也就是说C语言中的NULL的确是空指针,而C++中的NULL却是字面常量0

大家看一下下面这种现象
请注意:函数的参数可以不要名字,只给一个类型
那这有什么意义呢?
我们在以后会学习运算符重载,而运算符重载中区分前置++和后置++时就需要用到这种参数
我们以后会重点讲解的
在这里插入图片描述
那么怎么修改这个错误呢?
C++11中新引入了一个关键字nullptr
这个nullptr就是(void*(0))
在这里插入图片描述

三.类和对象上

C++对于C语言中的结构体进行了优化,将结构体逐步演化成了类
又因为实际需求和C语言中的结构体的语法有所差异,(这个差异接下来会讲到)
所以引入一个关键字class来定义类

1.C++中的结构体对于C语言的优化

1.C++中结构体的定义优化

大家是不是在写C语言代码的时候都对一个现象感到很反感
比方说我要在C语言中定义一个单链表节点

struct SListNode
{
	struct SListNode* next;
	int val;
};
定义一个结构体变量必须要加struct关键字
struct SListNode* phead=NULL;

就算我们typedef起别名了
typedef struct SListNode
{
	//这里还要加上struct.....
	struct SListNode* next;
	int val;
}SLNode;
定义一个结构体变量必须要加struct关键字
SLNode* phead=NULL;

必须要加这个struct是真的挺让人难受的,C++创始人也是这么想的,所以在C++语法中可以这么写

struct SListNode
{
	//这里不需要加struct关键字
	SListNode* next;
	int val;
};
定义一个结构体变量不需要加struct关键字
SListNode* phead=nullptr;

第二个优化:C++中的结构体里面可以放函数
比方说我们要定义一个Stack栈
在C语言中我们只能这样定义

struct Stack
{
	int* a;
	int top;
	int capacity;
};
void StackInit(struct Stack* ps)
{
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}
void StackPush(struct Stack* ps, int x)
{
	//扩容
	//ps->a[ps->top++] = x;
}

而在C++中我们可以这么定义
请注意在C++中结构体,类都属于一个域,在不同的域中可以有重名函数
而且C++中的结构体中的函数访问结构体中的成员变量时可以不加结构体指针直接访问(其实是编译器帮助我们省略了this指针,这个我们在这篇博客最后会介绍this指针)

//C++中结构体
struct Stack1
{
	int* a;
	int top;
	int capacity;
	//这里的Init和Push可以不用加上结构体指针
	//因为类也是一个域,只有在同一个域中才会构成重载
	//类中的函数可以访问该类中的成员
	void Init()
	{
		a = nullptr;
		capacity = top = 0;
	}
	void Push(int x)
	{
		//扩容
		//a[top++] = x;
	}
};

C++中的结构体因此被称为类
不过C++中的结构体依然保留了C语言中结构体的用法,因为C++是兼容C语言的

而在C语言当中结构体中的成员变量是可以通过结构体类型的变量去访问的
也就是说C语言中的结构体中的成员变量是公有的
那么就会发生一个不太好的现象

2.为什么C++要引入class关键字来定义类呢?

首先要说明C++中的struct也是可以定义类的
只不过用class和用struct定义的类有一些区别

什么区别呢?
struct中的结构体的属性默认是公有的,也就是说结构体类型的成员变量是可以直接访问该结构体(类)的属性的

而class定义的类的属性默认是私有的,也就是说该结构体类型的成员变量是不可以访问该结构体的属性的

那么为什么要这么做呢?公有有什么不好的地方呢?私有有什么好的地方呢?

如果公有了,可能会发生下面这种现象:

int main()
{
	Stack st1;
	st1.Init();
	//比方说我们要判断这个栈是否为空
	//正常来说我们就是要调用Empty这个函数接口来判断这个栈是否为空
	if (st1.Empty())
	{
		//一顿操作
	}
	else
	{
		//一顿操作
	}
	//可是,如果这个程序员的代码素养并不好,那么他可能会想
	//你不就是想要判空吗,还需要调个函数,我直接看一下top等不等于0不就行了吗
	//那么他可能会写出这样的代码
	if (st1.top == 0)
	{
		//一顿操作
	}
	else
	{
		//一顿操作
	}
	//但是这个自作聪明的程序员忽视了一点,你定义栈的时候喜欢让top初始化为0,
	//那别人就是喜欢初始化为-1也没任何错误啊
	//你怎么知道这个栈的定义者定义的时候把top初始化为0还是-1呢?
	//你不知道啊
	//那么你还自作聪明的以你的想法去判断栈是否为空,这是一个不一定正确的想法
	//可能就会产生bug,而这种bug产生的原因就是你这个程序员的代码素养不好
	//因此C++创始人就想去限制你,强迫你去调用对应的接口来执行你想完成的操作
	//怎么限制呢,就是让你访问不到top,只能借助Empty这个函数来判空
	return 0;
}

也就是说:
C语言中代码的规范性极大程度上取决于程序员个人的代码素养
而我们的C++创始人针对这个问题
想要强制程序员:强制调用接口对数据成员进行操作从而规范代码

因此C++引入了class这个关键字

class定义的类默认是私有,但是函数也私有了,这怎么办?
这就要介绍一下类的访问限定符和封装的知识了

2.类的书写形式

1.类的访问限定符和封装

C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户来使用
在这里插入图片描述
在这里插入图片描述
一般情况下都用class定义类,只有极少数情况下喜欢用struct
所以可这样来定义一个类

class Stack
{
private:
	int* a;
	int top;
	int capacity;
public:
	//这里的Init和Push可以不用
	//因为类也是一个域,只有在同一个域中才会构成重载
	//类中的函数可以访问该类中的成员
	void Init()
	{
		a = nullptr;
		capacity = top = 0;
	}

	void Push(int x)
	{
		//扩容
		//a[top++] = x;
	}

	bool Empty()
	{
		return top == 0;
	}
};

2.类的声明和定义分离

我们知道C语言中再写大型项目时经常会分头文件和源文件进行声明和定义分离
那么在C++的类中也可以这样
下面以栈为例
在这里插入图片描述
跟C语言有区别的地方在于在源文件中定义函数时需要加上类的域访问限定符
例如这里的

void Stack3::Init()
{
//具体实现
}

有一点需要特别说明:
C++也支持某些函数直接在类里面定义,而另一些函数进行声明和定义分离
但是有一个默认规则:直接在类中定义的函数默认加上inline的修饰

C++中类的推荐写法是:
长的函数:声明和定义分离来写
短的函数:直接在类中定义,默认会加上inline修饰

3.类的大小及类的实例化

1.类的大小

类作为一个数据类型,就必然会有它在内存中所对应的大小,
而类跟结构体类似,但是类中还有成员函数,那么这个类的大小是多少呢?

在这里插入图片描述
这里类C的大小是8个字节
根据我们在C语言阶段学过的结构体内存对齐的知识,我们可以计算出如果这个类只有成员变量_c和_i,那么这个结构体的内存大小就是8
那么成员函数不占用类的空间吗?

答案是:不占用

为什么呢?

因为:类C所定义出的每一个对象都有只属于它的一份数据,这一份数据是唯一的,是与其他人的数据互相独立的数据,就像是我们每一个人的身份证号都不同,每个人的年龄,性别,姓名等等都是只属于我们自己的数据,他人数据的变化对我们没有任何影响

所以类必须包含这些成员变量

而成员函数就像是一些公共设施,比如:公园,图书馆等等,不属于我们任何人
但是我们任何人都有权利去使用这些公共设施,如果这些公共设施只属于我们每个人,也就是每一个人都有一份公园,图书馆等等,那是不可能的,那也是非常消耗社会资源的一种分配方式

在这里也是同一个道理,这些成员函数并不是每个人所必需的,是可以为所有人所共同享用的,因此这些成员函数并不需要包含在对应的类当中,而是存储在了公共代码区

2.不含有任何成员变量的类的大小

那么如果一个类不含有任何成员变量呢?
在这里插入图片描述
无成员变量的类的大小:1
为什么呢?
这是规定的,这1个字节并不存储有效数据,就是为了表示定义的对象存在过
但是这个无成员变量的类也是有意义的
例如后面讲的仿函数都是不定义成员变量的
如果这个类的大小为0的话,那么实例化出来的对象岂不是0字节,也就是这个对象连地址都没有,也就是根本就不存在,这就跟实例化冲突了

3.类的实例化

在这里插入图片描述
那么什么是类的实例化呢?
说白了,就是定义一个类Date类型的变量,(注意C++中类定义变量可以称为对象,一回事,不过更习惯称之为对象)

int main()
{
	Date d;//这就是类的实例化
	return 0;
}
类和对象就类似于设计图和房子
只有在建造了房子之后,这个设计图中的桌子,床等等才会有

在这里插入图片描述

4.this指针

1.this指针的引出

我们在定义一个类的时候可能会出现下面这种情况:
在这里插入图片描述
我们明明初始化了,为什么还会这样?
因为Date类中的成员变量跟Init初始化函数的形参重名了,编译器会就近认为
这里的year=year的赋值是形参给形参自身赋值,所以并没有改变成员变量

那么怎么办呢?

第一种解决方法:
用简称代替形参,不过并不是很好,因为形参名称不写全了可能会产生歧义,而且需要去猜测形参的含义会加大程序员的工作难度,影响项目开发

第二种解决方法:
成员变量加上一些修饰符:
例如
在前面或后面加上_
或者在前面加上m_(m:member成员的意思)
或者m第一个首字母大写(驼峰法命名)
等等等等

第三种解决方法:this指针

2.被编译器隐藏的this指针

在这里插入图片描述
然后我们回头看看C语言和C++中对于Stack类的定义
可以发现它们的定义其实是一样的,只不过C++省略了this指针,把this指针隐藏了
编译器帮我们添加了this指针

那么为什么会报错呢?
是因为我们在形参列表中把this指针给显式定义了,其实编译器想告诉我们的是:

你不需要管this指针的事情,我会帮你做好的,你只需要管怎么去定义和使用函数即可
你要是管了,那就本末倒置了,你所要做的不是去为this指针的事情操心,而是去好好地写好你的函数,调用好你的函数就可以了

其实这里的

d1.Print()
的本质就是Print(&d1);

同理:
Date* dp=&d1;
dp->Print();
的本质就是:Print(dp);

3.this指针的特性

1.this指针的两个经典题目

下面请大家看一下这个代码,做一下这个选择题

1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
	 void Print()
	 {
	 cout << "Print()" << endl;
	 }
private:
	 int _a;
};
int main()
{
	 A* p = nullptr;
	 p->Print();
	 return 0;
}

答案是C,为什么呢?
首先这个代码没有任何语法问题,编译阶段不会对空指针解引用这个行为进行检查的
在这里插入图片描述
p不是空指针吗,为什么还能正常运行呢?
因为Print()函数中并没有对this指针进行解引用
没有对空指针进行解引用,因此运行时便不会报错,因此正常运行

那么再请大家看一下这个代码结果是什么呢?

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{ 
public:
    void PrintA() 
   {
        cout<<_a<<endl;
   }
private:
 int _a;
};
int main()
{
    A* p = nullptr;
    p->PrintA();
    return 0;
}

首先,这个语法是没有问题的,编译阶段不会报错
但是Print函数当中出现了对空指针的解引用行为,因此这个代码在运行时会报错
在这里插入图片描述
在这里插入图片描述

2.this指针的特性

在这里插入图片描述
this指针被const修饰:
this指针不可以被赋值(即this指针的指向不可以被修改)
但是*this可以被赋值(即this指针所指向的对象的值可以被修改)

void Print(Date* const this)

还有一点:

this指针不能显式地传实参和形参
但是可以在类里面显式地使用
为什么支持显式地使用呢?
因为后面有一些情况下需要显式地写(有些情况下必须要使用this指针)
在上面的Date类中
void Print()
{
	cout << this->_year << " " << this->_month << " " << this->_day << endl;
}
这么定义Print函数也是可以的

说了这么多,这么麻烦,C++有什么厉害的呢?
类和对象有什么厉害的?
下面给大家表演一下

5.C和C++当中关于Stack的实现对比

这是C语言的实现

#include <assert.h>
typedef int DataType;
typedef struct Stack
{
	DataType* a;
	int capacity;
	int top;
}Stack;
void StackInit(Stack* ps)
{
	assert(ps);
	ps->a = (DataType*)malloc(sizeof(DataType) * 4);
	if (NULL == ps->a)
	{
		assert(0);
		return;
	}
	ps->capacity = 4;
	ps->top = 0;
}
void StackDestroy(Stack* ps)
{
	assert(ps);
	if (ps->a)
	{
		free(ps->a);
		ps->a = NULL;
		ps->capacity = 0;
		ps->top = 0;
	}
}
void CheckCapacity(Stack* ps)
{
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity * 2;
		DataType* temp = (DataType*)realloc(ps->a,newcapacity * sizeof(DataType));
		if (temp == NULL)
		{
			perror("realloc申请空间失败!!!");
			return;
		}
		ps->a = temp;
		ps->capacity = newcapacity;
	}
}
void StackPush(Stack* ps, DataType data)
{
	assert(ps);
	CheckCapacity(ps);
	ps->a[ps->top] = data;
	ps->top++;
}
int StackEmpty(Stack* ps)
{
	assert(ps);
	return 0 == ps->top;
}
void StackPop(Stack* ps)
{
	if (StackEmpty(ps))
		return;
	ps->top--;
}
DataType StackTop(Stack* ps)
{
	assert(!StackEmpty(ps));
	return ps->a[ps->top - 1];
}
int StackSize(Stack* ps)
{
	assert(ps);
	return ps->top;
}
int main()
{
	 Stack s;
	 StackInit(&s);
	 StackPush(&s, 1);
	 StackPush(&s, 2);
	 StackPush(&s, 3);
	 StackPush(&s, 4);
	 printf("%d\n", StackTop(&s));
	 printf("%d\n", StackSize(&s));
	 StackPop(&s);
	 StackPop(&s);
	 printf("%d\n", StackTop(&s));
	 printf("%d\n", StackSize(&s));
	 StackDestroy(&s);
	 return 0;
}

下面是C++的实现

typedef int DataType;
class Stack
{
public:
	void Init()
	{
		_a = (DataType*)malloc(sizeof(DataType) * 4);
		if (NULL == _a)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		_capacity = 4;
		_top = 0;
	}
	void Push(DataType data)
	{
		CheckCapacity();
		_a[_top] = data;
		_top++;
	}
	void Pop()
	{
		if (Empty())
			return;
		_top--;
	}
	DataType Top()
	{
		return _a[_top - 1];
	}
	int Empty()
	{
		return 0 == _top;
	}
	int Size()
	{
		return _top;
	}
	void Destroy()
	{
		if (_a)
		{
			free(_a);
			_a = NULL;
			_capacity = 0;
			_top = 0;
		}
	}
private:
	void CheckCapacity()
	{
		if (_top == _capacity)
		{
			int newcapacity = _capacity * 2;
			DataType* temp = (DataType*)realloc(_a, newcapacity * sizeof(DataType));
			if (temp == NULL)
			{
				perror("realloc申请空间失败!!!");
				return;
			}
			_a = temp;
			_capacity = newcapacity;
		}
	}
private:
	DataType* _a;
	int _capacity;
	int _top;
};
int main()
{
	 Stack s;
	 s.Init();
	 s.Push(1);
	 s.Push(2);
	 s.Push(3);
	 s.Push(4);
	 printf("%d\n", s.Top());
	 printf("%d\n", s.Size());
	 s.Pop();
	 s.Pop();
	 printf("%d\n", s.Top());
	 printf("%d\n", s.Size());
	 s.Destroy();
	 return 0;
}

折起来之后C++只有一个class
而C语言有一堆函数,还有一堆形参,而且传参的时候比起C++来很麻烦
在这里插入图片描述
怎么样,C++比C语言简洁吧.
为什么会这样呢?这一切都要多亏了类和对象的设计理念
还有编译器为我们隐藏的this指针
在这里插入图片描述

以上就是C++入门3和类和对象上的全部内容,希望对大家有所帮助!

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

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

相关文章

【Nginx34】Nginx学习:安全链接、范围分片以及请求分流模块

Nginx学习&#xff1a;安全链接、范围分片以及请求分流模块 又迎来新的模块了&#xff0c;今天的内容不多&#xff0c;但我们都进行了详细的测试&#xff0c;所以可能看起来会多一点哦。这三个模块之前也从来都没用过&#xff0c;但是通过学习之后发现&#xff0c;貌似还都挺有…

python模块之feapder 爬虫框架

一、简介 官网&#xff1a;https://feapder.com/#/ feapder是一款上手简单&#xff0c;功能强大的Python爬虫框架&#xff0c;内置AirSpider、Spider、TaskSpider、BatchSpider四种爬虫解决不同场景的需求&#xff0c;但像任何工具一样&#xff0c;它也有其优点和缺点。以下是…

如何利用考培系统进行个性化学习和评估

考培系统作为一种现代化的学习和评估工具&#xff0c;可以为学生提供个性化的学习和评估服务。它利用先进的技术和算法&#xff0c;根据学生的学习情况和需求&#xff0c;为其量身定制学习计划&#xff0c;并提供相应的评估反馈。 1. 个性化学习 考培系统通过分析学生的学习情…

QML(25)——文本输入框组件的区别(TextField TextInput TextArea TextEdit)

目录 效果展示适用场景文本组件TextLabelText和Label的区别 单行文本输入框TextFieldTextInputTextField 和 TextInput的区别 多行文本输入框TextAreaTextArea 和 TextEdit 的区别 效果展示 适用场景 场景组件属性短文本Text长文本 末尾省略Textelide: Text.ElideRight文本设置…

通用FIFO设计深度8宽度64,verilog仿真,源码和视频

名称&#xff1a;通用FIFO设计深度8宽度64&#xff0c;verilog仿真 软件&#xff1a;Quartus 语言&#xff1a;verilog 本代码为FIFO通用代码&#xff0c;其他深度和位宽可简单修改以下参数得到 reg [63:0] ram [7:0];//RAM。深度8&#xff0c;宽度64 代码功能&#xff1a…

ArmSoM-RK3588编解码之mpp解码demo解析:mpi_dec_test

1. 简介 [RK3588从入门到精通] 专栏总目录 mpi_dec_test 是rockchip官方解码 demo 本篇文章进行mpi_dec_test 的代码解析&#xff0c;解码流程解析 2. 环境介绍 硬件环境&#xff1a; ArmSoM-W3 RK3588开发板 软件版本&#xff1a; OS&#xff1a;ArmSoM-W3 Debian11 3.…

低代码助力软件开发

低代码开发工具正在日益变得强大&#xff0c;它正不断弥合着前后端开发之间的差距。对于后端来说&#xff0c;基于低代码平台开发应用时&#xff0c;完全不用担心前端的打包、部署等问题&#xff0c;也不用学习各种框架&#xff08;Vue、React、Angular等等&#xff09;&#x…

GO 语言如何用好变长参数?

函数重载 对于函数重载相信编码过的 xdm 肯定不会陌生&#xff0c;函数重载就是在同一个作用域内定义多个具有相同名称但参数列表不同的函数 此处的参数列表不同&#xff0c;可以是参数的类型不同&#xff0c;参数的个数不同 那么我们一起分别来看看 C 语言&#xff0c;C 语…

物联网专业前景怎么样?

物联网专业前景怎么样&#xff1f; 物联网专业在当今技术发展迅速的背景下具有广阔的前景。以下是物联网专业的一些优势和就业前景&#xff1a; 1.市场需求大&#xff1a;物联网作为人工智能、云计算和大数据等技术的结合&#xff0c;已经成为许多行业的核心需求。各行各业都需…

【智能指针】

目录&#xff1a; 前言智能指针&#xff08;一&#xff09;智能指针初始了解内存泄漏1. 内存泄漏分类2. 如何检测内存泄漏3. 如何避免内存泄漏使用智能指针之前&#xff0c;异常安全的处理 &#xff08;二&#xff09;智能指针实现既原理智能指针RAII使用智能指针之后&#xff…

060:mapboxGL点击某处,通过flyTo,以动画的形式聚焦到此点

第060个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中点击某处,通过flyto,以动画的形式聚焦到此点。这里用到了flyTo的方法,里面可以设置bearing,zoom,pitch等众多的属性内容。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示…

数据结构与算法-(10)---列表(List)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

Linux 最大可以打开多少文件描述符?

Linux 最大可以打开多少文件描述符&#xff1f; 在日常开发中&#xff0c;对文件的操作可谓是再寻常不过的意见事情。那么你是否有这样一个疑问&#xff0c; 我最多可以打开多少个文件呢&#xff1f; 在Linux系统中&#xff0c;当某个程序打开文件时&#xff0c;内核返回相应…

SQL查询命令互转vba格式

最近搞个Excel的vba查询数据库&#xff0c;发现vba有代码行长度限制需要转换下就弄了这个&#xff0c;布局和功能暂且这样了&#xff0c;哪位大佬如果有兴趣的可以再美化下&#xff01; 这次更新了SQL命令互转VBA格式&#xff0c; SQL原始格式要分行的不能一坨贴进去&#xff0…

Java日志系统之JUL

目录 JUL介绍 JUL的使用 日志级别 指定日志输出地址 Logger对象的父子关系 Logger读取配置文件 JUL介绍 Java自带的框架&#xff0c;使用简单&#xff0c;无需引入依赖 JUL的使用 public class JULTest {Testpublic void testLogger() throws Exception{//获取日志记录…

2 用TensorFlow构建一个简单的神经网络

上一篇&#xff1a;1 如何入门TensorFlow-CSDN博客 环境搭建 后续介绍的相关代码都是在pycharm运行&#xff0c;pycharm安装略。 打开pycharm&#xff0c;创建一个新的项目用于tensorflow编码练习&#xff0c;在Terminal输入命令&#xff1a; # 依赖最新版本的pip pip inst…

[AutoSAR系列] 1.2 AutoSar 综述

AutoSAR是一种汽车工业领域的标准化软件架构,旨在简化不同汽车制造商之间的软件开发和交互。该标准于2003年由一系列欧洲汽车制造商成立的AutoSAR联盟制定并发布,目前已经成为全球范围内的标准。下面将对AutoSAR的概念、架构和实现进行综述。 1. 概述 AutoSAR是汽车电子控制…

Qt 读写文件(QFileQTextStreamQDataStream) 详解

一、读写文本文件 (QFile 类) Qt QFile类是一个用于读取和写入文件的类&#xff0c;它提供了对文件的访问、读取和写入等操作。它既可以操作文本文件&#xff0c;也可以操作二进制文件。 QFile类的功能包括&#xff1a; 打开、关闭文件读取文件内容写入文件内容支持文本模式…

如何让ChatGPT生成图片?

目录 一、那么如何解决让ChatGPT具有画图能力的问题呢&#xff1f; 二、那ChatGPT为什么能生成图片呢&#xff1f; 我们都知道ChatGPT只是个纯文本的AI模型&#xff0c;不具备画图能力。它可以生成文本&#xff0c;但如果让他生成图片就会显示如下的声明&#xff1a; 但通过本…

前端多媒体处理工具——ffmpeg的使用

写在前面 在前端领域&#xff0c;FFmpeg 是一个非常有用的工具&#xff0c;它提供了多种媒体格式的封装和解封装&#xff0c;包括多种音视频编码、多种协议的流媒体、多种色彩格式转换、多种采样率转换、多种码率切换等。可以在多种操作系统安装使用。 安装 下载FFmpeg 在网…