C++类和对象2:默认成员函数

news2024/12/25 16:52:26

 我们通过this指针可以看出来,C++其实隐藏了非常多的东西,很多事情它会在编译的时候包揽,那么作为最为重要的类和对象,它是不是还隐含了更多我们平常看不到的东西呢?

我们创建一个空类里面啥也不放。

class Text{};

 看上去啥也没有,但其实里面是有默认的成员函数的,不光有,还整整有6个

目录

默认成员函数:

 1.构造函数:

 默认生成的构造函数特性

默认构造函数:

2.析构函数:

析构函数的应用方法:

3.拷贝构造函数:

4.赋值运算符重载

运算符重载:

赋值操作符的重载:

 自己实现的赋值重载:

编译器默认生成的赋值重载:

流插入和流提取运算符重载

 浅谈友元:

const成员

5和6.取地址及const取地址操作符重载


默认成员函数:

 1.构造函数:

功能是初始化,虽然它的名字是构造,但是它只是在创建完对象之后直接初始化。它是一个很怪的函数,很特殊。构造函数的命名应与当前类名相同

首先,构造函数在我们没有去写的时候,编译器会自己为其直接编写一个默认的构造函数。

构造函数可以被重载,这也意味着可以提供多个构造函数与多种初始化方案

简单总结一下:

构造函数特性:

1. 函数名与类名相同。
2. 无返回值。
3. 对象实例化时编译器自动调用对应的构造函数。
4. 构造函数可以重载。


 以日期类为例,我们结合缺省值,可以重载构造函数。

class Date
{
public:

	Date(int year=2022, int month=12, int day=29)
	{
		_year = year ;
		_month= month ;
		_day = day   ;
	}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day  << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};


 默认生成的构造函数特性

 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦
用户显式定义编译器将不再生成

那么编译器默认生成的构造函数又是怎么样的?

我们注释掉重载完的构造函数,直接打印看看

 发现是随机值。

那问题就来了,如果编译器自己会生成一个默认的构造函数,而这个构造函数也只能给个随机值,那不是根本没啥用?但是其实构造函数非常的”双标“,至于是什么样的如下所示。

双标的构造函数:

构造函数对内置类型不处理。它只会对非内置类型进行初始化,而非内置类型的类型是除去语言自带的类型如int char这类的,所以当创建的对象为自定义类型如当前的Date或者是结构体这类的,会对自定类型成员调用的它的默认成员函数,反之,构造函数完全不会理会非内置类型,非内置类型内部存放的就都是随机值。就比如我们日期类内部的成员变量,都是随机值。

当我们以自定类型调用默认构造函数时,效果如下:


class Text
{
public:
	Text()
	{
		cout << "这个自定义类型的构造函数已被调用" <<  endl;
	}

private:
	int text;

};


class Date
{
public:

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day  << endl;
	}

private:
	int _year;
	int _month;
	int _day;
	Text tx;
};

我们可以看到,创建以Date这个类创建对象的时候,直接初始化了里面的Tx ,也就是直接创建了这个类型的对象,创建的依据就是Class A内部的构造函数被触发了。

C11对于这个特性所增加的补丁

显然这种双标带来的蛋疼感也不是一点点,所以在C11的版本中上了个补丁,允许我们在对内置类型进行声明的时候给予一个缺省值,这里看着其实很像初始化,但其实他的运算逻辑是缺省值的逻辑,也就是没有传递参数的时候默认给的值

 虽然不算非常方便,不过也算得上补救的一种,至少不会往里头放随机值了


默认构造函数:

我们会有一个先入为主的概念误区,那就是我们觉得只有我们不写的时候编译器自己给的叫默认构造函数,但其实真正的默认构造函数的概念是无参的构造函数和全缺省的构造函数,也就是如下两种函数也算默认构造函数 。

 总结为:不传参数的就是默认构造函数

默认构造函数有且只有一个,当我们尝试绕开这项规则的时候,就会报错。

 


2.析构函数:

构造函数是创建对象,那么对象的销毁则是析构函数

class Date
{
public


    //构造函数
    Date()
    {}

    //析构函数
    ~Date()
    {}


	void Print()
	{
		cout << _year << "-" << _month << "-" << _day  << endl;
	}

private:
	int _year;
	int _month;
	int _day;

};

析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由
编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

析构函数的特性:

1. 析构函数名是在类名前加上字符 ~
2. 无参数无返回值类型。
3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

析构函数面对自定类型,会调用其析构函数。

析构函数的销毁顺序:后定义的先销毁,符合栈的性质

举例:

 答案:BADC

解析:析构函数的销毁顺序是后来的先销毁,那么我们先观察本题的创建顺序:C A B D

但是各类修饰符会影响变量的声明周期,以及变量的创建范围,C是全局变量,是程序最开始所创建的变量,那么它会被最后销毁。而D则是Static改变了局部变量的生存作用域,所以静态的变量会在局部变量析构之后析构故答案为BADC。


析构函数的应用方法:

析构函数会对自定义类型调用其构造函数,而构造函数本身是清理和释放空间,那么我们使用的时候只需要遵循以下的方法即可

如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类


3.拷贝构造函数:

当我们打算以d1的形式再次创建一个新对象的时候,这个时候我们会使用拷贝构造函数。

所以在C++中,当出现了这样的需求的时候,就会使用到拷贝构造函数。

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存
在的类类型对象创建新对象时由编译器自动调用。

1.拷贝构造函数也是特殊的成员函数,它是构造函数的一种重载形式

2.拷贝构造函数的参数有且只能有一个,并且它的参数类型为该类型的对象的引用,使用传值调用会直接报错,因为会发生无限递归。

// Date(const Date& d) // 正确写法
Date(const Date& d) // 错误写法:编译报错,会引发无穷递归
{
    _year = d._year;
    _month = d._month;
    _day = d._day;
}

为什么会发生无限递归呢?传值调用究竟做错了什么?

我们先来看什么时候拷贝构造函数会被触发:

Date d1(2022,9,26)

Date d2(d1);

 假若我们的拷贝构造函数是如下的错误写法,会发生什么呢?

Date(const Date d)

首先是最基本的传值调用的特质,也就是形参的产生。我们在这里再次复习一次形参是实参的拷贝。这个时候,传值调用所产生的拷贝相当于再次触发了一次拷贝构造函数的条件,也就是相同类所创建的对象中,新建一个同类对象。

 总结:拷贝构造函数在传值调用时会因为形参的拷贝而不断再次触发拷贝构造函数,正确使用时以使用其同类型的引用。

显视声明拷贝构造函数的时候,参数应加上const,以防止写反了的错误发生,由于引用是变量的别名,若是发生则会更改到被拷贝的原对象,const则可以有效的解决这个问题。


那么拷贝构造函数究竟是如何拷贝的呢?

同样的,它既然是构造函数的重载,那么它的本质也是双标的。当我们使用编译器默认生成的拷贝构造函数时它的拷贝情况如下:

对于内置变量来说,它会一个一个字节的将原对象内部的内置变量拷贝至目标变量,但这个拷贝本质上是一种浅拷贝。

浅拷贝:

浅拷贝更像是一种获取然后覆盖,很像memcpy,我们回顾一下memcpy的基本实现:memcopy为了实现适用于内存中的覆盖以及拷贝,使用了char*来一个个拷贝,这样子可有有效保证拷贝的正确性,却也会在面对指针的时候产生问题。

当我们希望借助拷贝构造函数来实现两个对象之间的复制时,如果这个类型的对象内部是有指针的话,拷贝构造函数的浅拷贝原则只会把原指针复制并给到新指针里面,这样子的话跟我们希望额外开辟空间的基本需求不同,且会在析构函数调用的时候崩溃,因为编译器对同一块空间进行了两次析构。

而在这里,为了避免浅拷贝所带来的一系列问题,我们需要使用深拷贝,也就是我们自己写拷贝构造函数,让其开辟空间。

而当构造拷贝函数在应对自定义类型时,会直接调用其自身的拷贝构造函数。

 拷贝构造函数典型调用场景:
 1.使用已存在对象创建新对象
     2.函数参数类型为类类型对象
       3.函数返回值类型为类类型对象


4.赋值运算符重载

赋值运算符重载同前文的成员函数相同,会在没有显式调用的时候自己生成一个默认的,但是在了解之前我们先整理一下运算符重载的概念


运算符重载:

加减乘除运算符都只能方便的计算变量,在C++中,为了带上自定义变量类型一块玩,设定了运算符重载的功能,也就是为了能让自定义对象能用运算符。

这项功能可以实现自定义类型的一些运算效果,如比较大小,加减乘除,或者就拿我们的Date类型来说,实现两个Date之间的天数之差。

函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)

 重载过程

 比如一个简单的检查两个类是否相等的操作符,我们重载来玩玩:

与编写函数不同,我们写形参的时候不应该写成传值调用,不然又会去调用拷贝构造函数直接白忙活了,所以我们还是需要使用引用,和拷贝构造函数的理由相同,我们应该尽量防止犯错的问题发生,加一个const上去。

那么,根据我们求相等的逻辑,写出来应该不算难

 但是这里报错了,我们反应过来,我们在尝试访问私有变量。

 歇逼了,那咋办呢?

我们暂时先忽略这个问题,先看一下假如我们的重载运算符生效了的打印格式

 

这样会报一堆错,因为流插入运算符的运算优先级要比==高。

加上括号可以有效规避因为流的运算顺序造成的报错问题。

 

回到刚才的问题,我们怎么获得私有的成员变量呢?

在这里可以使用友元,但是之后再说,我们可以开墙角用函数把他们拿出来,也就是直接在类内部创建成员函数,返回的是私有成员变量的值。

但是这样比较呆,其实更好的方法是将我们的重定向函数直接放进类里面。

但问题又出现了,这样子依然编译失败,为什么?

 这怎么就参数过多了?我使用的操作符需要两个操作数不是很合理吗?这里的问题其实是this指针的存在所引起的。成员函数会默认有This做参数,所以在这里其实有了三个参数,那么很简单我们直接删掉一个就好了。

在这里,编译器还是非常智能的,当编译器检测到我们使用这个操作符与全局变量时,会直接使用这种形式:

赋值操作符的重载:

 自己实现的赋值重载:

 前面的铺垫完了,那么正式进入我们的正题,赋值赋值操作符的重载。

同拷贝构造函数不同,两个已经存在的对象之间的拷贝才是赋值重载,

int main ()
{
    Date d1(2022,12,31);
    Date d2(2023,1,1);

    d1 = d2;
}

题外话:

那么来了个刁钻的问题,这个是拷贝构造还是赋值重载呢?

Date d3 = d2;

但其实也没啥刁钻的,这个依旧是拷贝构造,d4连实体都还没有呢,怎么称之为赋值呢?

那我们尝试实现一下赋值的重载

	//赋值操作符重载,为了防止触发拷贝构造,使用传引用
	void operator = (const Date& d1)
	{
		_year = d1._year;
		_month = d1._month;
		_day = d1._day;
	}

这样子写本身没有任何问题,但是它没有实现链式访问,一个正常的赋值操作符应该实现链式赋值的功能,也就是i = j = 10这种

那我们就写个带返回值版本的

	//实现链式访问版本
	Date operator = (const Date& d1)
	{
		_year = d1._year;
		_month = d1._month;
		_day = d1._day;
	}

但这个还是不够好,为啥?

因为发生了一些多余的拷贝,我们应该合理的应用好引用,将返回值也设置为引用。这样子可以减少拷贝的发生,注意,在这个过程中,被销毁的是this指针,而非*this,*this所指向的d1依然没有被下销毁。

	//优化版本
	Date& operator = (const Date& d1)
	{
		_year = d1._year;
		_month = d1._month;
		_day = d1._day;
	}

编译器默认生成的赋值重载:

既然是赋值重载是默认成员函数中的一员,那么当我们不写它的时候会编译器默认生成的效果是怎么样的?

编译器默认生成的赋值重载函数的泛用度和拷贝构造函数相同,用于赋值日期类这类不需要额外写析构函数的就足以应付了,但是相同的是,它的原理与拷贝构造函数相同,发生的是浅拷贝。如果我i们用默认的赋值重载函数对栈类型进行赋值操作,也会发生析构两次同一空间的问题发生,所以面对这类类型我们需要自己写赋值重载函数。

但是我们发现,其实编译器自己生成的已经实现了字节序拷贝,我们还需要花那么大功夫自己重载一个吗?

我们以栈的赋值重载为例,我们使用编译器默认生成的赋值重载函数

 为什么崩溃了?

原因:

所以解决方法是:直接free掉被赋值的空间,重新开一个和源相同大小的空间,用memcpy把数据拷贝过去,之后返回一个this指针就好了。

以Stack插入扩容为例,需要规避掉刁钻角度的情况发生,也就是自己给自己赋值这种操作,所以我们需要检查一下

	Stack& operator =(const Stack& st1)
	{
		if (this != &st1)
		{
			free(_a);
			int* tmp = (int*)malloc(st1._capacity * sizeof(int));
			if (tmp == nullptr)
			{
				perror("malloc fail!");
				exit(-1);
			}
			_a = tmp;
			memcpy(_a, st1._a, st1._top);
			_top = st1._top;
			_capacity = st1._capacity;
		}
		return *this;
	}

 this指针出了这个函数的作用域是不会被销毁的,它依然存在,那么为了最优解,我们是可以用引用的

接下来是写自增的重载,++和--

那么这里就有一个头疼的问题,自增都是单操作数单操作符,编译器怎么知道是前置还是后置?

所以C++给了个标记:

 但是在这里,这个int仅做标记,不需要传参,本身自增也用不着。


流插入和流提取运算符重载

> 本身在C++内部是支持内置变量重载的,为了实现对类的流插入和提取,我们 可以重载它们。需要调用Cout的话C++是支持这个类型的也就是ostream:我们用这个类型创建一个变量:ostream out

相应的,这个ostream是输出,输入则是istream

重载的时候相当于重写一遍流输出,写成如下这样

 但是重载完了之后缺会报错

 

 换一个写法就不会

这就很蛋疼了,我重载你不是让你来耍杂技的,你这样子可不符合使用习惯啊!

原因是this指针默认占用了第一个操作数

所以重载这两个操作符的时候一般不写成成员函数,因为Date对象默认就是左操作数不符合使用习惯,而且写在类里面第一个操作数绝对会是this指针,所以一般情况下不将流插入重载写成成员函数。

那么就把它拿出来写:

 但是在这里报了个错,原因其实是全局函数的重复定义问题

 在这里,我们的项目的声明与定义是分离的,所以会出现一个老问题,类似于头文件的多次包含的问题:

 

两个文件内部都包含了一次head.h,造成了这个重载函数的重定义。不同于我们当时的解决办法,我们当时使用了pragma once来防止重复调用,但是pragma once只能防止文件展开两次,而非不展开

当然,在这里其实不只是这个重载函数会报这样的错,其他全局函数,包括全局变量都会出现这个问题

 解决办法:

1.声明与定义分离

声明和定义也可以解决,因为有了定义与声明才会进符号表。

2.加个static

static之所以可以解决这个问题还需要归功于它的基本定义:当static修饰全局变量时,会影响变量的生命周期,当然在修饰全局函数以及变量的时候也会修改它们的链接属性也就是修改成仅在当前文件可见

总而言之:不要在.h里面定义全局变量

 这个问题解决后,我们面对的另一个问题则是如何访问到私有变量。在这里可以使用友元。


 浅谈友元:

友元相当于访问私有变量的绿色通道。

友元可以在类里面的任意位置声明,为白名单上的函数提供通道,只需要在需要的函数前面加上一个friend就好了。

 但是这样其实破环了我们封装的本意,一般只有再不得不用的情况下我们才会使用友元。


const成员

当我们以const类型创建一个类的对象的时候,调用其成员函数会报错

原因其实是权限放大

我们回顾一下隐藏的this指针的格式:Date* const this

而传参对象的格式: const Date d2

传入成员函数,也就是当前对象自己,即d2的地址而其类型是const Date*

对比两个类型,一个是对this指针本身加上const,另一个则是对this指针所指向的对象加上const

 

 那这下怎么办呢?const对象都没法调用自己的成员函数了!

解决办法则是:C++允许在成员函数后面加上一个const,允许类似d2这种对象类型能正常的使用成员函数。在这里加上的const修饰的则不是this指针本身,而是它指向的那个变量,也就是变成了:const Date* const this说的通俗易懂一点就是把这个指针和他指向的变量都锁住了

 但是这里有个疑问,我们针对d2做出的修改,怎么d1这个朴实无华的对象还是能继续调用呢?

因则是权限的缩小,尽管这个形参已经被const锁的明明白白的,但是并不妨碍传参的时候初始化。而一个const对象唯一能被改动的时刻就是初始化的时候

为此我还专门写了个样例:

  将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

总结下来:凡是内部不改变成员变量,也就是*this对象数据的,这些成员函数应该加上const

反正遵循不放过一个的原则


5和6.取地址及const取地址操作符重载

这两大爷不需要怎么关注,默认生成的就够用,不需要我们手动重载,这里偷个懒

 当然要防止刁钻需求,比如不要返回地址的时候,还是需要重载的

 


到这,全部的成员函数就概述完毕了!不过还没结束!类和对象真是难啃对吧!不过剩下的都是部分细节问题了!

感谢阅读!希望对你有点帮助!

 

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

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

相关文章

2_类加载子系统

目录 概述 类加载器子系统作用 类的加载过程 加载阶段 加载class文件的方式 链接阶段 准备 Prepare 解析 Resolve 初始化阶段 类加载器的分类 虚拟机自带的加载器 扩展类加载器&#xff08;Extension ClassLoader&#xff09; 应用程序类加载器&#xff08;系统类加…

阿里云计算工程师ACP考题归类解析

目录考纲答题技巧四式记的牢三妙招一、对象存储OSS二、专有网络VPC三、服务器ECS四、安全五、阿里云弹性伸缩Auto Scaling五、内容分发网络CDN总结考纲 重点学习ECS、VPC、OSS三部分。 答题技巧四式 战略是先做简单后做难度高的。 一、简化 做题问三个问题&#xff0c;按回答…

【云原生 | Kubernetes 实战】20、K8s Ingress 实现业务灰度发布

目录 通过 Ingress-nginx 实现灰度发布 一、Ingress Controller 多种发布策略介绍 场景一&#xff1a;将新版本灰度给部分用户 场景二&#xff1a;切一定比例的流量给新版本 二、模拟部署生产测试版本 Web 服务 2.1 部署一个 v1 版本: 2.2 再部署一个 v2 版本: 2.3 再…

论文投稿指南——中文核心期刊推荐(化学)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

本地方法接口

什么是本地方法 简单地讲&#xff0c;一个Native Methodt是一个Java调用非Java代码的接囗。一个Native Method是这样一个Java方法&#xff1a;该方法的实现由非Java语言实现&#xff0c;比如C。这个特征并非Java所特有&#xff0c;很多其它的编程语言都有这一机制&#xff0c;…

AQS核心原理之

AQS系列 1、AQS核心原理之 2、ReentrantLock 原理及示例 文章目录AQS系列一、什么是AQS?二、AQS特性三、AQS内部维护 state四、队列4.1 同步等待队列4.2 条件等待队列5、总结一、什么是AQS? AQS全称是 AbstractQueuedSynchronizer&#xff08;抽象对了同步器&#xff09;&am…

Cento6从零开始用Nginx+mysql+php搭建Discuz在线论坛系统

首先我的liunx使用版本是 centos6.5 32位 discuz版本是Discuz_X3.2_SC_UTF8.zip Xshell版本是6 xftp是7版本 mysql也是是这个版本&#xff1a;mysql这里写目录标题1.yum安装php2.安装nginx包3.安装php-fpm4.安装php-mysql5. 安装Discuz在线论坛系统由于目前yum源已经无法使用需…

力扣 2037. 使每位学生都有座位的最少移动次数

题目 一个房间里有 n 个座位和 n 名学生&#xff0c;房间用一个数轴表示。给你一个长度为 n 的数组 seats &#xff0c;其中 seats[i] 是第 i 个座位的位置。同时给你一个长度为 n 的数组 students &#xff0c;其中 students[j] 是第 j 位学生的位置。 你可以执行以下操作任…

unidbg案例-爱库存app之sig和sign分析

新年的第一篇文章,新的一年继续加油,奥利给!冲冲冲。 今天分析的app是爱库存,版本号6.1.6,这次还是使用unidbg分析该样本,加密参数有很多,不过只关注sig和sign两个参数。 老规矩,上来先抓个包。 1.抓包 可以看到上面👆🏻的sign,就是本次研究的重点。 2.jadx静…

A* 算法详解(超级详细讲解,附有大图)

目录 引入 一.基本概念 二.算法原理 ①用宽度优先搜索 ②狄克斯特拉算法 ③A*算法 三.需要注意 四.c伪代码 最后 引入 今天想跟大家聊的&#xff0c;是我们经常用到&#xff0c;但是却让大家觉得十分神秘的那个算法&#xff1a;A* 。 这是一个远古而又非常经典的游戏…

【C++ STL】-- 用一棵红黑树的插入实现同时封装map与set

用一棵红黑树同时封装map与set的意义&#xff1a;所谓的 “用一棵红黑树同时封装map与set” 只是在程序员的角度&#xff0c;通过一系列手段&#xff0c;以一个红黑树同时满足map与set。但是在编译器的角度&#xff0c;实际上并不是一颗树实现的&#xff0c;程序员所写的只是一…

机器学习 10:激活函数大全

虽称为激活函数大全&#xff0c;但也不敢太过自满&#xff0c;如有遗漏与错误&#xff0c;还请指正 文章目录线性激活函数Sigmoid 函数LogSigmoidSwishTanh / 双曲正切激活函数TanhShrinkSoftsignReLU 函数BReLULeaky ReLUPReLURReLUELUSELUCELUGELUSoftmax 函数Maxout 函数Sof…

Android 实现多语言

工具下载连接 链接&#xff1a;https://pan.baidu.com/s/1Wq9DTzhP2fkHXLEbOQFr9A?pwdlmcz 提取码&#xff1a;lmcz 1.将你需要的翻译的strings放到exe目录下 2.双击执行xml转xls.exe 英文 日文 韩文&#xff08;使用空格分割&#xff09;回车&#xff0c;会在当前目录下生…

jvm学习的开端(一)----类的加载(类加载子系统)

文章目录1.Loading&#xff08;加载阶段&#xff09;2.Linking&#xff08;链接阶段&#xff09;2.lnitialization&#xff08;初始化阶段&#xff09;来自 百度百科&#xff1a; 类加载器子系统负责从文件系统或者网络中加载class文件&#xff0c;class文件在文件开头有特定的…

【java项目】飞机大战

文章目录项目-飞机大战窗口的创建背景图片的添加/点击事件的启动游戏物体父类的编写背景的移动双缓存技术--解决文字闪动背景图片循环出现我方战斗机的添加和鼠标控制添加首颗子弹批量添加子弹敌方飞机的批量添加功能我方子弹与敌方飞机的碰撞检测我方子弹与敌方飞机碰撞时的处…

单片机基础之单片机中断、定时器中断、PWM及SG90舵机的初识认知

目录 一、初探单片机中断 二、定时器中断相关寄存器 1、中断寄存器 2、中断结构 3、用定时器中断方式控制LED&#xff0c;代码编程测试 三、初识PWM 1、什么是占空比 2、如何输出PWM信号 四、SG90舵机基本认知 1、什么是舵机 2、怎么控制舵机 3、舵机编程实战 一、…

Jetson nano 入手系列之2—板载摄像头IMX219启动

Jetson nano 入手系列之2—板载摄像头IMX219启动1.亚克力板安装2.摄像头启动3.nvgstcapture常用命令3.1 Set sensor orientation3.2 Get Image Capture Resolution3.3 Capture3.4 quit参考文献Jetson nano 入手系列&#xff1a; Jetson nano 入手系列之1—如何SSH远程登录 Jets…

Redis学习(一)

Redis入门 Redis是一个基于内存的key-value结构数据库&#xff0c;读写性能较高 Redis数据类型 Redis存储的是key-value结构的数据&#xff0c;其中key是字符串类型&#xff0c;value有5种数据类型&#xff1a; 1.字符串 string 2.哈希 hash 3.列表 list 4.集合 set 5.有序集…

Altium Designer 20 凡亿教育视频学习-01

课程视频&#xff1a;第1课 课程介绍.mp4_哔哩哔哩_bilibili 第一部分学习 学习方法 工程具备文件 一定需要先建立工程&#xff0c;再来创建原理图库、原理图等文件 栅格大小改变 栅格的大小我们常在绘制原理图的时候改变&#xff0c;因为有时候我们需要画一个细线&#…

【PCB专题】什么是通孔、盲孔、埋孔?

PCB板是由基板和PP叠加而成的。不同层上走了各种信号线和电源,这些信号和电源在不同的电路层之间切换时需要依靠过孔(通孔、盲孔和埋孔)连接。如下图所示的6层板,使用了2阶HDI方案:有机械孔和激光孔。 过孔的作用就像是水管一样,连接了不同的平面。PCB板上的过孔作用就是…