【C++学习】类和对象(上)

news2024/10/6 12:21:37

前言:
由于之前电脑“嗝屁”了,导致这之前一直没有更新博客,今天才拿到电脑,在这里说声抱歉。接下来就进入今天的学习,在之前我们已经对【C++】进行了初步的认识,有了之前的知识铺垫,今天我们将来带领大家学习我们【C++】中的一个重要知识,即“类和对象”的学习。这个知识点我将分为三期进行讲解。好了,废话不多说直接进入本期【类和对象(上)】的学习。

本文目录

  • 1.面向过程和面向对象初步认识
  • 2.类的引入
    • 2.1类的解读
  • 3.类的定义
  • 4.类的访问限定符及封装
    • 4.1 访问限定符
  • 5.类的作用域
  • 6.类的实例化
  • 7.类对象模型
    • 7.1 如何计算类对象的大小
    • 7.2 类对象的存储方式
  • 8.this指针
    • 8.1 this指针的引出
    • 8.2 this指针的特性
    • 👉8.3 this指针存在哪里?
    • 👉8.4 this指针可以为空吗?

1.面向过程和面向对象初步认识

在正式开始学习之前,我们先来了解一个概念,那就是【面向对象和面向过程】的区别。

👉C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

我们通过日常生活中的洗衣服案例用通俗易懂的话来带领大家认识。

在这里插入图片描述
在生活中洗衣服通常要进行以上过程,而【面向对象】关心的就是将这些具体的过程/解决问题的步骤按部就班的进行下去,每个步骤可以将其封装成一个函数,这些函数按照一定的次序来调用,最终完成所需要做的事情,我们将这种思想称之为 【面向对象】。

👉C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

我们还是以洗衣服为例进行理解说明:
在这里插入图片描述
对于“我们”来说,洗衣服就很少会亲自动手去洗,至少“我”本人就是一直往洗衣机丢。我们将衣服,洗衣液,放到洗衣机里面(由洗衣机完成后续工作)而对于“我们”来说并不用关心衣服怎么来洗,洗衣机会帮我们完成接下来的任务,洗衣机实际是真正洗衣服的。我们不需要考虑其中具体过程,经过别的物品之手完成此事便可,我们将这种思想称之为【面向对象】,通过【面向对象】的方式处理,“人”“脏衣服”“洗衣机”“洗衣液”“水”均为对象,我们“洗衣服这件事情”是通过这些对象之间的“交互”把事情做完的。


2.类的引入

C++在C语言的基础上做了一些改进,使得C++具有了面向对象编程的特性。其中最重要的改进就是提供了类的概念。

2.1类的解读

👉类的基本思想是数据抽象和封装。是具有相同的属性和操作的一组对象的集合,它为属于该类的全部对象提供了统一的抽象描述。封装实现了类的接口和实现的分离。封装隐藏了类的实现,封装过后,用户只能访问类的接口,而不能访问类的实现。

在类和对象阶段,主要是研究类的封装特性,那什么是封装呢?

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。

封装本质上是一种管理,让用户更方便使用类。比如:对于电脑这样一个复杂的设备,提供给用户的就只有开关机键、通过键盘输入,显示器,USB插孔等,让用户和计算机进行交互,完成日常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件。
在这里插入图片描述
对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此计算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可。

在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。

有了基本认识过后,我们可能会想到“类”是怎么来的呢?

在之前我们已经说过了,由于【C++】兼容我们的【C】,它最开始就是从结构体延伸而来的,在【C++】中照样可以使用结构体,但是实际上在【C++】中我们把结构体升级为了今天我们将会探讨的“类”。

我们还是以直观形象的代码为例进行理解,接下来我将通过【C】和【C++】两种语法使用情况下写出两种代码,具体如下:

// C++兼容C结构体用法
typedef struct ListNode
{
	int val;
	struct ListNode* next;
}LTN;



// C++把结构体升级成了类
struct ListNode
{
	int val;
	ListNode* next;
};

👉解析:
在【C】语言中,我们定义的结构体,struct ListNode是它的类型,而在【C++】当中我们的类型就是ListNode,所以大家才会看到下面那种代码格式。

此时,大家可能就会好奇,既然【C++】中的类是由【C】语言中的结构体引入来的,那么是否这两者之间就是一样的呢?答案当然是否定的,大家试着想想如果都是一样的话,我们在【C】语言中已经学过了,在【C++】完全就没必要在引入新概念了。

👉那么类和结构体之间到底有什么区别呢?

1.C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数;
2.结构使用栈存储,而类使用堆存储。结构在声明的时候就已经为其分配栈上的内存了,而类需要用new为其分配堆上的内存。;
3.结构体内的变量和函数一般是 public 的,可以在结构体作用域之外的地方使用,但是类的变量和函数一般是 private 的,只能被类作用域内的函数使用,类外不可以直接获取到类中的变量。(public 和private 具体什么意思后面会讲)

具体什么意思呢?我们一点点的来进行理解,在我们之前学习数据结构的时候,学到过【栈】的基本知识,首先是定义了一个结构体,在定义了各功能函数紧接着去一一实现,即数据和方法是分离开的。但是在【C++】中方法可以定义在其里面,即功能函数的实现可以定义在“类”里面。通过代码大家仔细体会:

struct Stack
{
	// 成员函数
	void Init(int n = 4)
	{
		//...
		capacity = n;
		size = 0;
	}

	void Push(int x)
	{
		//...
		a[size++] = x;
	}

	// 成员变量
	int* a;
	int size;
	int capacity;

};

int main()
{
	Stack zp; // 用类stack实例化出对象zp
	zp.Init(10);

	zp.Push(1);
	zp.Push(2);
	zp.Push(3);
	
	return 0;
}

上面结构体的定义,在C++中更喜欢用【class】来代替。


3.类的定义

定义一个类,本质上是定义一个数据类型的蓝图。这实际上并没有定义任何数据,但它定义了类的名称意味着什么,也就是说,它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作。

在这里插入图片描述

👉class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。

👉类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。
例如,我们使用关键字 【class】 定义 【student 】数据类型,如下所示:

class Date
{
 private:
    	int _year;
    	int _month;
    	int _day;
};

关键字 【public】 确定了类成员的访问属性。在类对象作用域内,公共成员在类的外部是可访问的。您也可以指定类的成员为 【private 】或 【protected】,这个我们稍后会进行讲解。


👉 类中函数的两种定义方式:

1. 声明和定义全部放在类体中;
注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。

2.类声明放在.h文件中,成员函数定义放在.cpp文件中(推荐)
注意:成员函数名前需要加类名::

对于第一种方法,就是我们上边写【栈】的那种方法。

至于第二种方法,就是声明和实现分开的方法,这种方法我们之前写数据结构时都是用的这种方法。(一般情况下,更期望采用第二种方式)
在这里插入图片描述

最后,说明一点,在类中定义成员函数以及成员变量时,不需要考虑定义的先后顺序,也就是说,即使成员变量放在成员函数的下面,成员函数中依然可以使用成员变量


4.类的访问限定符及封装

在上述类的定义的两种方式中,声明和定义方式下我们采用的是【struct】关键字,大家是否验证过当我们换成【C++】中的【class】之后是否还能正常编译成功呢?在这里给出大家答案,之后大家可以下去测试,当我们换成【class】之后程序跑起来就会出现报错的情况,具体如下:
在这里插入图片描述
但是当我们使用【class】之后,程序就会出现以下现象:
在这里插入图片描述
那么到底是什么原因呢?这就需要研究访问限定符的问题了。

4.1 访问限定符

C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。

在这里插入图片描述
👉【访问限定符说明】

  1. public修饰的成员在类外可以直接被访问
  2. protected和private修饰的成员在类外不能直接被访问,现阶段我们只要会用public和private就可以(此处protected和private是类似的)
  3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
  4. 如果后面没有访问限定符,作用域就到 } 即类结束。
  5. class的默认访问权限为private,struct为public(因为struct要兼容C)

👉注意:

在这里插入图片描述

还有一个细节问题,就是我们的成员函数在定义时,为了防止之后的冲突,一般进行一些限制会在其前面或者后面加【_】(根据个人习惯)。

👉注意事项:

1.不能在类的声明中对数据变量进行初始化;
2.在类中声明的任何成员不能使用 extern、auto 和 register 存储类型关键字修饰;
3.类声明中可以给出成员函数的参数的默认值;
4.类中可以不含有任何成员变量和成员函数,这样的类被称为空类。
5. 访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

此外,在定义类的成员函数的时候,如果不在类的内部定义(在内部给出定义,默认为内联函数),使用具体如下:

返回值类型 类名::成员函数名(形参列表)
{
	函数体
}

5.类的作用域

类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 【::】作用域操作符指明成员属于哪个类域。

class Person
{
public:
	void PrintPersonInfo();
private:
	char _name[20];
	char _gender[3];
	int  _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
	cout << _name << " " << _gender << " " << _age << endl;
}

6.类的实例化

用类类型创建对象的过程,称为类的实例化

  1. 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它;
  2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量

Person p;//p占有实际的物理空间,这里就是一个实例化的过程
Person p1;
Person p2;
int main()
{
 Person._age = 100;   // 编译失败:error C2059: 语法错误:“.”
 return 0;
}

Person类是没有空间的,只有Person类实例化出的对象才有具体的年龄。


7.类对象模型

7.1 如何计算类对象的大小

class Date
{
public:
	// 定义
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

//private:
	int _year;  // 声明
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2;

	d1.Init(2023, 2, 2);
	d1._year++;
    
    d2.Init(2022, 2, 2);
	d2._year++;

	cout << sizeof(d1) << endl;
}

问题:类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算一个类的大小?
我们直接运行程序,得到的结果如下:
在这里插入图片描述

此时,通过上述结合代码我们可以想到,打印出来的大小似乎只打印了成员变量的大小,而成员函数似乎不在我们的对象里面。要理解这个问题我们就需要探讨为什么成员变量在对象中,成员函数不在对象中呢?

7.2 类对象的存储方式

👉对象中包含类的各个成员,首先我们需要理解我们硬是要把成员函数的地址存到对象当中可以吗?答案当然是可以的,但是为什么不放到对象里面呢?大家可以想一想,当我们真的放到对象里面的时候会不会存在巨大的浪费,每个对象里面成员变量是独立的,但是成员函数是公共的,假设当我有10个函数,就有10个指针,就有40个字节,当我们每个对象都放一份时就会造成巨大的浪费。因此就没有必要在放到对象里面去,那么不当到对象里面应该放到哪去呢?我们可以放到一个公共的区域,这个公共的区域就是【代码段】,调用时就不到对象里面去找,而去这个公共的区域去查找。

因此在上述代码中就只需计算成员变量的大小,因此就为12.
在这里插入图片描述
因此实例化后的对象的大小,只需要计算成员变量大小即可,当然,类对象大小的计算与struct一样遵循结构体内存对齐规则。
我们通过一些例子来进行深入了解:

class A1 {
public:
    void f1() {}
private:
    int _a;
};
// 类中仅有成员函数
class A2 {
public:
    void f2() {}
};
// 类中什么都没有---空类
class A3
{};

int main()
{
    cout << sizeof(A1) << endl;
    cout << sizeof(A2) << endl;
    cout << sizeof(A3) << endl;


    return 0;
}

输出结果为:
在这里插入图片描述
👉结论:
一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象用来占位,标识对象被实例化定义出来了。


8.this指针

8.1 this指针的引出

我们通过以下代码来引入指针问题:

class Date
{
public:
	// 定义
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

//private:
	int _year;  // 声明
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2;

	d1.Init(2023, 2, 2);
	d1._year++;
    
    d2.Init(2022, 2, 2);
	d2._year++;

	cout << sizeof(d1) << endl;
}

👉对于上述类,有这样的一个问题:

Date类中有 Init 这个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init
函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?

这就引入了即将要学的指针的知识:
C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

编译器在编译过后,它会自主的做一件事(对我们来说不能做),增加一个【this】,并且调用的地方也会被改。所以这里的“年月日”并不是我们声明的,而是【d1 or d2】的,具体到底是【d1】的还是【d2】的,如果是【d1】调用即是赋值给【d1】的,【d2】同理。(在实参或形参处千万不能自己显示去加,这是编译器自己做的,但是函数体内部可以使用这个this指针。
在这里插入图片描述

函数体内部使用这个this指针:

class Date
{
public:
	// 定义
	void Init(int year, int month, int day)
	{
		cout << this << endl;
		this->_year = year;//这里可以使用
		this->_month = month;
		this->_day = day;
	}

private:
	int _year;  // 声明
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2;

	d1.Init(2023, 2, 2);
	d2.Init(2022, 2, 2);
	
}

输出结果为:
在这里插入图片描述

8.2 this指针的特性

  1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
  2. 只能在“成员函数”的内部使用
  3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
  4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递

在这里插入图片描述

👉8.3 this指针存在哪里?

其实编译器在生成程序时加入了获取对象首地址的相关代码。并把获取的首地址存放在了寄存器【ecx】中(VC++编译器是放在ECX中,其它编译器有可能不同)。也就是成员函数的其它参数正常都是存放在栈中。而this指针参数则是存放在寄存器中。
在这里插入图片描述

👉8.4 this指针可以为空吗?

我们还是借助代码来进行理解:

class Date
{
public:
	// 定义
	void Init(int year, int month, int day)
	{
		cout << this << endl;
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

	void func()
	{
		cout << this << endl;
		cout << "func()" << endl;
	}

private:
	int _year;  // 声明
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2;

	d1.Init(2023, 2, 2);
	d2.Init(2022, 2, 2);
	
	Date* ptr = nullptr;
	//ptr->Init(2022, 2, 2); // 运行崩溃

	ptr->func();           // 正常运行
    (*ptr).func();         // 正常运行
}

👉解析:

1.对于【ptr->func();】这行代码执行起来,最后的结果是什么样的呢?

当我们运行代码后,我们的程序是正常运行的。我们一步步分析,开始时去调用这个【func】这个成员函数时会显得十分奇怪。为什么呢?因为这是一个【date】的指针,但是却是一个空指针,结果显示却是正常运行。**大家是不是都“蒙圈”了呀!!!**怎么会是正常运行呢?
在这里插入图片描述

2.对于【ptr->Init(2022, 2, 2); 】这行代码运行起来之后结果是怎么样的呢?

在这里插入图片描述

上面两个问题我们结合起来看。首先大家是否明白【func】和【Init】是否在对象里面,在【C】语言中我们学过在对象调用就用【.】,而指针调用则用【->】,我们这个函数显然是不在对象里面的,那么要调用【func】这个函数就要转换为【call】即一个地址,那么这个地址到哪里去找呢?我们在之前说过成员函数是在公共区域,所以是去公共区域部分去找,就是代码段,所以说虽然这里有个【->】,但并没有发生解引用操作。其次,我们调用成员函数需要传递【this】指针,所以【ptr->func();】并没有解引用,但是这个【ptr】传递给了【this】指针,所以这里的【this】是个空,并不会报错,所以【ptr->func();】这行运行起来之后是正常运行。而对于【ptr->Init(2022, 2, 2); 】这行代码而言,同理调用的时候不会崩,但是紧随之后用【this】去进行解引用操作了,所以程序就会崩溃。

最后看一行代码:【 (*ptr).func(); 】 这行代码运行后结果怎么样呢?

有了上面的知识我们知道,在调用的时候这里是不会发生错误的,大家注意这里的【ptr】是传递给【this】,所以是能够正常运行的!!!
在这里插入图片描述
我们通过调试,在汇编情况看下这两行代码:
在这里插入图片描述
大家会发现这两行代码的从汇编视角下看没有区别!!!

👉注意:
有没有解引用的行为取决于要访问右边的东西在不在对象里面,而不是用没用那个符号。千万不要被事物的表面现象所迷惑!!!


到此,类和对象(上)的学习便到此结束了。大家一定要结合知识点,多去总结和理解,争取消化掉这部分知识。

本期知识如果对你有帮助的话,记得点赞三连哟!!!

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

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

相关文章

初识BFC

初识BFC 先说如何开启BFC&#xff1a; 1.设置display属性&#xff1a;inline-block&#xff0c;flex&#xff0c;grid 2.设置定位属性&#xff1a;absolute&#xff0c;fixed 3.设置overflow属性&#xff1a;hidden&#xff0c;auto&#xff0c;scroll 4.设置浮动&#xf…

英雄算法学习路线

文章目录零、自我介绍一、关于拜师二、关于编程语言三、算法学习路线1、算法集训1&#xff09;九日集训2&#xff09;每月算法集训2、算法专栏3、算法总包四、英雄算法联盟1、英雄算法联盟是什么&#xff1f;2、如何加入英雄算法联盟&#xff1f;3、为何会有英雄算法联盟&#…

Linux系统安装mysql(rpm版)

目录 Linux系统安装mysql&#xff08;rpm版&#xff09; 1、检测当前系统中是否安装MySQL数据库 2、将mysql安装包上传到Linux并解压 3、按照顺序安装rpm软件包 4、启动mysql 5、设置开机自启 6、查看已启动的服务 7、查看临时密码 8、登录mysql&#xff0c;输入临时密…

C++ STL学习之【vector的使用】

✨个人主页&#xff1a; Yohifo &#x1f389;所属专栏&#xff1a; C修行之路 &#x1f38a;每篇一句&#xff1a; 图片来源 The power of imagination makes us infinite. 想象力的力量使我们无限。 文章目录&#x1f4d8;前言&#x1f4d8;正文1、默认成员函数1.1、默认构造…

STM32之SPI

SPISPI介绍SPI是串行外设接口(Serial Peripherallnterface)的缩写&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;并且在芯片的管脚上只占用四根线&#xff0c;节约了芯片的管脚&#xff0c;同时为PCB的布局上节省空间&#xff0c;提供方便…

蓝桥杯嵌入式(G4系列):定时器捕获

前言&#xff1a; 定时器的三大功能还剩下最后一个捕获&#xff0c;而这在蓝桥杯嵌入式开发板上也有555定时器可以作为信号发生器供定时器来测量。 原理图部分&#xff1a; 开发板上集成了两个555定时器&#xff0c;一个通过跳线帽跟PA15相连&#xff0c;最终接到了旋钮R40上&…

STM32F103CubeMX定时器

前言定时器作为最重要的内容之一&#xff0c;是每一位嵌入式软件工程师必备的能力。STM32F103的定时器是非常强大的。1&#xff0c;他可以用于精准定时&#xff0c;当成延时函数来使用。不过个人不建议这么使用&#xff0c;因为定时器很强大&#xff0c;这么搞太浪费了。如果想…

Zookeeper的Java API操作

Zookeeper的Java API操作一、先启动Zookeeper集群二、IDEA 环境搭建三、创建子节点四、获取子节点并监听节点变化五、判断 Znode 是否存在六、Watcher工作流程一、先启动Zookeeper集群 二、IDEA 环境搭建 1.创建一个Maven工程&#xff1a;ZookeeperProject 2.在pom.xml文件添…

ARM uboot 的移植4 -从 uboot 官方标准uboot开始移植

一、添加DDR初始化1 1、分析下一步的移植路线 (1) cpu_init_crit 函数成功初始化串口、时钟后&#xff0c;转入 _main 函数&#xff0c;函数在 arch/arm/lib/crt0.S 文件中。 (2) 在 crt0.S 中首先设置栈&#xff0c;将 sp 指向 DDR 中的栈地址&#xff1b; #if defined(CONF…

CNCF x Alibaba云原生技术公开课 【重要】第九章 应用存储和持久化数据卷:核心知识

1、Pod Volumes 场景 同一个pod中的某个容器异常退出&#xff0c;kubelet重新拉起来&#xff0c;保证容器之前产生数据没丢同一个pod的多个容器共享数据 常见类型 本地存储&#xff0c;常用的有 emptydir/hostpath&#xff1b;网络存储&#xff1a;网络存储当前的实现方式有两…

2021年我国半导体分立器件市场规模已达3037亿元,国内功率半导体需求持续快速增长

半导体分立器件是由单个半导体晶体管构成的具有独立、完整功能的器件。例如&#xff1a;二极管、三极管、双极型功率晶体管(GTR)、晶闸管(可控硅)、场效应晶体管(结型场效应晶体管、MOSFET)、IGBT、IGCT、发光二极管、敏感器件等。半导体分立器件制造&#xff0c;指单个的半导体…

proteus I2C Debugger 查看 AT24C02写入读取

I2C Debugger仪器&#xff0c;在仿真调试期中&#xff0c;该仪器可以显示I2C数据传送时间、S&#xff08;START状态&#xff09;、Sr(ReStart状态&#xff09;、A&#xff08;Ask响应&#xff09;、N &#xff08;No ask状态&#xff09;、P&#xff08;Stop状态&#xff09;、…

中值滤波+Matlab仿真+频域响应分析

中值滤波 文章目录中值滤波理解中值滤波的过程Matlab 实现实际应用频域分析中值滤波是一种滤波算法&#xff0c;其目的是去除信号中的噪声&#xff0c;而不会对信号本身造成太大的影响。它的原理非常简单&#xff1a;对于一个给定的窗口大小&#xff0c;将窗口内的数值排序&…

【C++进阶】四、红黑树(三)

目录 一、红黑树的概念 二、红黑树的性质 三、红黑树节点的定义 四、红黑树的插入 五、红黑树的验证 六、红黑树与AVL树的比较 七、完整代码 一、红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可…

嵌入式安防监控项目——html框架分析和环境信息刷新到网页

目录 一、html控制LED 二、模拟数据上传到html 一、html控制LED 简单来说就是html给boa服务器发了一个控制指令信息&#xff0c;然后boa转发给cgi进程&#xff0c;cgi通过消息队列和主进程通信。主进程再去启动LED子线程。 这是老师给的工程。 以前学32都有这工具那工具来管…

导航技术调研(CSDN_0023_20221217)

文章编号&#xff1a;CSDN_0023_20221217 目录 1. 惯性导航 2. 组合导航技术 3. 卡尔曼滤波 1. 惯性导航 惯性导航系统(INS-Inertial Navigation System)是上个世纪初发展起来的。惯性导航是一种先进的导航方法&#xff0c;但实现导航定位的原理却非常简单&#xff0c;它是…

RHCSA-用户和组管理和文件系统权限(3.11)

目录 用户&#xff08;UID&#xff09; 用户类别&#xff08;UID&#xff09;&#xff1a; 用户的增删改查&#xff1a; 修改用户密码&#xff1a; 查看用户是否存在&#xff1a; 组&#xff08;GID&#xff09; 组的增删改查&#xff1a; 设置组密码&#xff1a; 用户…

idea集成GitHub

设置 GitHub 账号绑定账号有两种方式&#xff1a;1. 通过授权登录2.如果上述登录不成功&#xff0c;用Token口令的方式登录&#xff0c;口令在github账号哪里生成&#xff0c;点击settings --->Developer settings --->pwrsonal access tokens ----> 复制口令到idea 口…

设置cpp-httplib 服务器模式模式下的线程池大小 以及如何增加默认处理函数 以便能够实现http请求转发

先说说默认的创建的线程池数量 原因是某天调试在gdb调试下 一启动程序发现 开启了好多线程 如下图 因为我们程序 没几个线程 数了下 居然有60多个线程 不需要那么多 所以看下 httplib的源码 构造函数的时候 设置了最大线程池数量 看下这个宏 然后打印了下 发现 居然那么大 …

FusionCompute安装和配置步骤

1. 先去华为官网下载FusionCompute的镜像 下载地址&#xff1a;https://support.huawei.com/enterprise/zh/distributed-storage/fusioncompute-pid-8576912/software/251713663?idAbsPathfixnode01%7C22658044%7C7919788%7C9856606%7C21462752%7C8576912 下载后放在D盘中&am…