类与对象(上篇)
前言
在之前我们学的C++入门主要是为现在学习类与对象打基础,今天我们才算真正开始学习C++了。因为类与对象的知识点比较多,所以我们将它分为三部分讲解,今天我们学习类与对象的上篇。
一、面向过程和面向对象的初步认识
1、面向过程
面向过程顾名知义,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。例如:C语言。
2、面向对象
面向对象,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。例如:C++,java(注意:C++兼容C,所以C++并不是纯面向对象的语言,是支持面向对象和面向过程的“混编”)。
3、举个例子
外卖系统分别用面向过程与面向对象是怎样实现的?如下图所示:

tip: 现在大家先对概念理解一下,随着以后的学习会慢慢理解面向对象的思想。
二、类的引入
在C语言中,数据与方法是分离的。而在C++中,数据与方法没有分离。所以在C++中struct被升级成了类——结构体内不仅可以定义变量,也可以定义函数。
代码示例:写一个简易的栈类
#include<iostream>
#include<stdlib.h>//展开命名空间
using namespace std;
//栈类
typedef int DataType;//栈的元素类型
struct Stack
{//成员函数//栈的初始化void Init(int capacity = 4){//在堆区开辟capacity个栈空间_array = (DataType*)malloc(sizeof(DataType) * capacity);if (nullptr == _array){perror("malloc fail");return;}//初始化栈的容量与栈顶位置_capacity = capacity;_top = 0;//指向栈顶位置的下一个}//入栈void push(const DataType& x){//判断是否扩容if (_top == _capacity){//扩容}//入栈_array[_top] = x;_top++;}//访问栈顶元素DataType Top(){return _array[_top - 1];}//销毁void Destroy(){free(_array);_array = nullptr;_capacity = 0;_top = 0;}//成员变量DataType* _array;//指向堆区开辟的数组int _capacity;//栈的容量int _top;//栈顶位置
};int main()
{//C++兼容C,struct以前的用法都可以继续使用struct Stack s1;//C++类名就是类型,所以可以直接写StackStack s2;s2.Init();//缺省参数——没有传实参,使用缺省值s2.push(1);s2.push(1);cout << s2.Top() << endl;s2.Destroy();return 0;
}
tip:
①C++将struct升级成了类,不仅可以定义变量,还可以定义函数。
②C++中类名就是类型,在C里面struct 类名组合在一起才是类型。因为C++兼容C所以两种写法都可以,struct以前的用法都可以继续使用。
③我们发现在类中变量成员在声明前面可以使用,这是因为类域是一个整体,所以变量写在后面,也不用声明。
⑤虽然struct被升级成了类,但是在C++中更喜欢用class来代替。
三、类的定义
1、类定义的代码示例
class className
{//类体:由由成员变量和成员函数组成
}; //注意与struct一样后面要有分号
解读:
①class是定义类的关键字,className为类名,{}中为类的主体,注意类定义结束时后面分号不能省略。
②类体中的内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或成员函数。
2、类的两种定义方法
①声明和定义全部放在类体中 ,需要注意:成员函数如果在类中定义,默认为内联函数,最后由编译器决定。
class Person
{//函数的声明与实现都在类中void showInfo(){cout << _name << " " << _age << endl;}//成员函数char* _name;int _age;
};
②类声明放在.h文件中,成员函数定义放在.cpp文件中。如下图:

tip:类成员函数定义时,注意要成员函数名前面要类名::,表明它是那个类的。
总结:对于这两种方法,平时我博客讲解的时候为了方便使用方法1定义类,但是建议大家在以后写项目和工作时使用方法2。
3、成员变量的命名习惯
为了避免成员变量与成员函数的参数同名,我们一般可以①成员变量加前缀_;②成员变量加前缀my_;③成员变量加后缀_等方法。
代码示例:
class Date
{
public:void Init(int year){//因为成员变量加了前缀_,所以这里我们能很好的区分该语句是给对象的_year赋值_year = year;}
private:int _year;
};
四、类的访问限定符与封装
1、类的访问限定符
(1)引入访问限定符
我们先来看两段代码:
代码1:能运行吗?
struct Person
{char _name[10];int _age;
};int main()
{//定义对象p1Person p1;//直接修改对象p1的年龄p1._age = 18;return 0;
}
代码2:能运行吗?
class Person
{char _name[10];int _age;
};int main()
{//定义对象p1Person p1;//直接修改对象p1的年龄p1._age = 18;return 0;
}
答案是:代码1能运行,代码2不能运行,出现语法错误,这是为什么呢?这就是我们接下来要讲解的类的访问限定符。
(2)访问限定符
C++实现封装的方式:用类将对象的属性与方法结合在一起,让对象更加完善,通过访问权限选择性的将接口提供给外部的用户使用。

(3)访问限定符说明
①public修饰的成员在类外可以直接被访问。
②protected和private修饰的成员在类外不能直接被访问。(在C++初阶protected和private类似,在后面进阶讲继承的时候才能体现他们的区别)
③访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现为止。
④如果后面没有访问限定符,作用域就到“}”即类的结束。
⑤class的默认访问权限为private,struct为public(因为struct要兼容C)。
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别。
(4)问题:C++中struct和class的区别
C++需要兼容C,所以C++中struct可以当作结构体使用。另外C++中struct还可以用来定义类。和class定义类一样,区别是struct定义的类默认访问权限是public,class定义的类默认权限是private。注意:在继承和模板参数列表位置,struct和class也有区别,后序再给大家讲解。
2、封装
(1)面向对象的三大特性
面向对象的三大特性:封装、继承、多态。
(2)什么是封装
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交换。
在我们生活中有许多封装的实例,例如:你家的房子,就是一个封装。如果不封装的话,那谁都可以进你家了。
(3)封装的本质
封装的本质是一种管理,让用户更方便使用类。
在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制那些方法可以在类外直接被使用。

五、类的作用域
1、类域
①类定义了一个新的作用域,类的所有成员都在类的作用域中。
②在类体外定义成员时,需要使用::作用域操作符指明成员属于哪个类域。
③类域是一个整体,成员变量不是一定写在成员函数后面的。
代码示例:
#include<iostream>
using namespace std;class Person
{
public:void PrintPersonInfo();
private:char _name[20];char _gender[3];int _age;
};//这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{cout << _name << " " << _gender << " " << _age << endl;
}
2、简单总结我们已经学过的域
①我们已经学习了四种域:局部域、全局域、命名空间域、类域。
②同一个域不能定义同名变量,不同域可以定义同名变量。
③域都会影响访问,但只有局部域和全局域影响生命周期。
④编译器访问变量规则:一般默认先在局部找,找不到再去全局找(都找不到则报错);特殊类方法先局部找,找不到去类域找,最后再去全局找。
⑤命名空间域与全局域平行,但是如果不展开就不会访问。
⑥::作用域操作符,指定访问某个域的变量。指定方式:域名::变量名。
六、类的实例化
1、定义
用类类型创建对象的过程,称为类的实例化。
2、实例化的说明
①类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它。
②一个类可以实例化出多个对象,实例化出的对象才占用实际的物理空间,存储类的成员变量。
③类就像是设计图,类实例化出对象就像现实中使用建筑设计图建造出的房子。 图纸并没有实体,同样类也只是一个设计,只有实例化出的对象才能实际存储数据,占用物理空间。

代码示例:
#include<iostream>
using namespace std;class Person
{
public:void PrintPersonInfo(){cout << _name << " " << _sex << " " << _age << endl;}
public:char* _name;char* _sex;int _age;
};int main()
{//下面语句是否正确?//Person::_age = 18;//错误,因为类没有实例化,并没有开辟空间。只有类实例化出的对象才有具体的年龄。//tip:类的对象要整体实例化才可以。//类实例化对象/对象定义Person man;//tip:只有类实例化,开辟了空间,才能存储数据man._name = (char*)"zhangsan";man._sex = (char*)"男";man._age = 18;man.PrintPersonInfo();return 0;
}
七、类对象模型
1、如何计算类的大小
问题: 类中既有成员变量,也有成员函数,那么一个类的对象中包含什么?如何计算一个类的大小?
我们先来一段代码示例,用编译器运行计算看类A的大小是多少。
#include<iostream>
using namespace std;class A
{
public://成员函数void f(){}
private://成员变量int _a;char _ch;
};int main()
{//实例化对象A a;//打印类对象的大小cout << sizeof(a) << endl;return 0;
}
运算结果:类A的大小

解读:
①类对象存储: 类对象只保存类的成员变量,不保存类的成员函数。(为什么会这样呢?详细讲解在后面类对象存储猜测)
②类的大小计算: 与C语言计算结构体的方式一样,需要注意内存对齐。
③回顾内存对齐的规则:
1、结构体的第一个成员,对齐到结构体变量在内存中存放位置的0偏移量。
2、从第二个成员开始,每个成员变量都要对齐到(一个对齐数)的整数倍。
- 对齐数=编译器默认的一个对齐数与一个结构体成员自身大小的较小值。
- VS默认对齐数为8;Linux gcc没有默认对齐数,对齐数就是结构体成员自身大小。
3、结构体总大小,必须是所有成员变量的对齐数中最大对齐数的整数倍。
4、如果是嵌套结构体的情况,嵌套的结构体对齐到自己最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
④内存对齐的意义:
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据;某些硬件平台只能在某些地址处取某些特定的数据,否则抛出硬件异常(例:int——>对齐到4的整数倍)。
2、性能原因:计算机读取数据时,并不是想访问哪个字节就访问哪个字节,而是从结构体的对齐边界开始按照访问倍数去访问。假设CPU一次访问4个字节(具体与硬件有关),对齐访问_a只要访问一次,不对齐_a要访问两次,如下图所示:
如图可知,内存对齐是拿空间换时间。
⑤类A的内存大小为8,如图所示:

2、类对象的存储猜测
①对象中包含类的各个成员:

缺陷: 不同对象中成员变量不同,但是调用同一个函数,如果按照此方式存储,当一个类创建多个对象时,**每个对象都会保存一份代码,相同代码保存多次,浪费空间。
②只保存成员变量,成员函数存放在公共的代码段:

tip:关于上述两种存储方式,计算机按照方式二来存储。
3、空类与仅有成员函数的类大小
代码示例:
#include<iostream>
using namespace std;//类中仅有成员函数
class A1
{
public:void f(){}
};//类中什么都没有——空类
class A2
{};int main()
{//输出A1,A2的大小cout << sizeof(A1) << endl;cout << sizeof(A2) << endl;return 0;
}
运行结果:

总结:
①没有成员变量的类对象,需要一个字节,是为了占位(不存储有效数据),表示对象存在。
②一个类的大小,实际就是该类中成员变量之和,还需要注意内存对齐。
八、this指针
1、this指针的引出
我们来定义一个日期类Data:
#include<iostream>
using namespace std;class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year; int _month;int _day;
};
int main()
{Date d1, d2;d1.Init(2022, 1, 11);d2.Init(2022, 1, 12);d1.Print();d2.Print();return 0;
}
运行结果:

问题: d1与d2调用同一个函数print,为什么打印结果不一样呢?(在类的存储模型我们知道成员函数与对象无关,它存储在公共区域。)
答案是: C++中引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数”添加了一个隐藏的this指针参数,让该this指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。如下图所示:

2、this指针的特点
(1)语法规定:this指针不能在形参和实参显示传递,但是可以在函数内部显示使用
①调用成员函数时,不能显示传递对象的地址给this,因为编译器会自动传递了,不需要用户传递。
tip: 既然编译器会自动传递对象地址,为什么不通过类来调用函数——因为通过类来调用函数,不会传this指针;通过对象调用函数,虽然不再对象里找函数,但是会传this指针。
②定义成员函数时,也不能显示定义this指针,因为编译器会自动定义。
tip: this指针是一个关键字,指向当前对象地址。
③this指针可以在函数体内部显示使用,如下代码所示:
void Print(){//语法规定:this指针不能在形参和实参显示传递,但是可以在函数内部显示使用//函数体中所有成员变量都要通过this指针访问//1、在函数体中,访问成员变量,你不写他会自动添加thiscout << _year << "-" << _month << "-" << _day << endl;//2、在函数体内可以自己显示使用this指针cout << this->_year << "-" << this->_month << "-" << this->_day << endl;}
tip: 在函数内部,你访问对象的成员变量你不写this指针它会自动添加,你也可以显示使用。
(2)this指针的类型:类类型* const,即成员函数中,不能给this指针赋值
tip:左定值,右定向。
const在*的左边,则指针指向的变量的值不能通过指针改变;在 * 的右边,则指针的指向不能改变。
代码示例:
int main()
{int a = 10;//右定向int* const pa = &a;int b = 9;//pa = &b;//报错,左值不可修改,即指针指向不能改变*pa = b;//可以修改指向变量的值return 0;
}
3、面试题
问题1: this指针存在哪里?
答案是:this指针本质上是“成员函数”的形参,所以this指针与普通参数一样存在函数调用的栈帧里面。如下图汇编代码:

tip: 在VS集成开发环境下,对this指针进行了优化,对象地址是放在ecx寄存器,ecx存储this指针的值。
问题2: this指针可以为空吗?
我们先来看两段代码,判断A、编译报错 B、运行崩溃 C、正常运行
代码1:
class A
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}
代码2:
class A
{
public:void PrintA(){cout << _a << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->PrintA();return 0;
}
答案是: 代码1:C、运行成功;代码2:B、运行崩溃。解析如下图所示:

4、this指针的好处

tip: C就像手动挡需要自己控制变速箱,C++有了封装,引入this指针就像自动挡电脑程序控制变速箱。简单来说,就是更简单,不易出错了
相关文章:
类与对象(上篇)
前言 在之前我们学的C入门主要是为现在学习类与对象打基础,今天我们才算真正开始学习C了。因为类与对象的知识点比较多,所以我们将它分为三部分讲解,今天我们学习类与对象的上篇。 一、面向过程和面向对象的初步认识 1、面向过程 面向过程顾…...
使用SpringBoot集成MyBatis对管理员的查询操作
增删改查中的查询操作,对所有的普通管理员进行查询操作。 效果展示: 不仅可以在打开页面时进行对管理员的自动查询操作,还可以在输入框进行查询。 首先是前端向后端发送POST请求,后端接收到请求,如果是有参数传到后端…...
数据报文去哪儿了
背景 今天遇到一个诡异的现象,当接口附加一个IP时,主IP业务正常,附加IP死活不行,tcpdump抓包确可以正常抓到到业务的报文,但是在PREROUTING raw添加规则确没有命中,说明报文没有到netfilter框架内ÿ…...
Mysql中join on中的like使用
1、使用mysql中的函数CONCAT(str1,str2,…) 返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。 SELECT * FROM Table1 INNER JOIN Table2 ON Table1.col LIKE CONCAT(%, Table2.col, %) 2、放弃使用join语句 SELECT * FROM Table1, T…...
微信运营神器:从群发到批量添加,让你的微信营销更轻松
在这个数字化时代,微信已经成为了我们生活中不可或缺的一部分。对于许多企业和个人来说,微信营销也是非常重要的一部分。但是,微信营销并不是一件容易的事情,需要花费大量的时间和精力。为了解决这个问题,今天我们将向…...
白杨SEO:2B企业营销是什么?当下主流的短视频直播平台有哪些?企业营销要做短视频直播选哪个平台更好?
今天白杨SEO就正式来讲讲2B企业营销选择哪个短视频直播平台更好? 图片在公众号:白杨SEO上看。 文章大纲提前看: 1、先说说2B企业营销是什么? 2、当下主流的短视频直播平台有哪些? 3、2B企业营销要做短视频直播选哪…...
将word中的表格无变形的弄进excel中
在上篇文章中记录了将excel表拷贝到word中来: 记录将excel表无变形的弄进word里面来-CSDN博客 本篇记录:将word中的表格无变形的弄进excel中。 1.按F12,“另存为...”,保存类型:“单个文件页面”,保存。…...
美国服务器在大陆连不上怎么回事?
在租用任何美国服务器之前,都需要先搞清楚一些使用问题,毕竟服务器能够不间断地访问也是站在们所期望的。但有时,美国服务器网站或许也会突然出现在大陆打不开的情况,在面临这种情况时,我们应该怎么做? 查看连不…...
postgresql数据库中update使用的坑
简介 在数据库中进行增删改查比较常见,经常会用到update的使用。但是在近期发现update在oracle和postgresql使用却有一些隐形区别,oracle 在执行update语句的时候set 后面必须跟着1对1的数据关联而postgresql数据库却可以一对多,这就导致数据…...
高可用elasticsearch集群搭建
目录 一、环境准备 二、机器配置 2.1 创建用户 2.2 修改用户权限 2.3 解析主机名 2.4 优化最大文件数 2.5 优化最大进程数 2.6 优化虚拟内存 2.7 重载配置 三、部署 3.1 创建文件夹并赋予权限 3.2 解压安装包并赋予权限 3.3 配置环境变量 3.4 创建数据、证书存放目录并赋…...
Linux本地MinIO存储服务远程调用上传文件
🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,…...
C语言 子函数调malloc申请内存返回给主函数使用——可行,但要注意
一般情况,子函数中动态申请内存,将地址返回给主函数,理论上应该也是可以的,需要子函数返回动态内存地址,主函数实参是相应的地址变量即可。只不过,主函数实参传入子函数之前,可能会将指针置空&a…...
Python入门教程之条件语句与运算符优先级详解
文章目录 Python 条件语句Python运算符优先级关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小游戏源码五、面试资料六、Python兼职渠道 Python 条件语句 …...
高通Camera HAL3: CamX、Chi-CDK要点
目录 一、概述 二、目录 三、CamX组件之前的关系 一、概述 高通CamX架构是高通实现的相机HAL3架构,被各OEM厂商广泛采用。 二、目录 代码位于vendor/qcom/proprietary下: camx:通用功能性接口的代码实现集合chi-cdk:可定制化…...
springboot+vue热带野生动物园景点预约门票订票系统
热带野生动物园景点预约订票系统为野生动物园提供景点管理服务的系统,通过登录系统,管理该野生动物园所有的景点信息、景点分类信息、野生动物园新闻、通知公告、回复会员留言等,并可以通过订单管理查看会员预定的订单信息,对订单…...
Flutter和Android的混合跳转
1、项目特点 项目是Flutter作为主工程,将Android module或SDK作为模块嵌入到flutter中,与通常所熟悉的Android(或iOS)工程将flutter 为module嵌入到工程中有所不同。 2、业务需求 任意界面间的跳转,不管是flutter页…...
CyberRT-共享内存实现
CyberRT共享内存类图 共享内存消息发布 数据用共享内存发布时,首先会创建ShmTransmitter对象,包含两个主要成员segment和notifier,Segment用于创建共享内存(上面绿色部分),Notifer 最终构建ReadableInfo通…...
linux通过串口传输文件
简介 在嵌入式调试过程中,我们经常会使用调试串口来查看Log或者执行指令,其实,调试串口还有另一种功能,就是传输文件,本文说明使用MobaXterm串口工具来传输文件。 环境要求 嵌入式系统需要安装lsz和lrz,…...
uniapp 打包后各静态资源加载失败的问题(背景图,字体等)
原因: 1.部署地址不在域名根目录下 解决办法(推荐办法2): 办法1.如果部署在域名的文件夹下(例如h5), 则运行的基础路径修改为/h5/ 且注意路由模式 办法2.不修改运行的基础路径(还是./), 将代码中涉及背景图(background-image)和字体资源的路径前统一加,如图: tips: 标签内s…...
关于git hooks
Git hooks 是一种在 Git 仓库中触发自定义脚本的机制。这些脚本可以在特定的 Git 操作(如提交、推送、合并等)发生时执行。通过使用 Git hooks,你可以在版本控制的不同阶段自动运行脚本,以执行一些定制化的操作。 在 Git 中&…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...

