Linux学习笔记(应用篇三)
基于I.MX6ULL-MINI开发板
- LED学习
- GPIO应用编程
- 输入设备
开发板中所有的设备(对象)都会在/sys/devices 体现出来,是 sysfs 文件系统中最重要的目录结构
| /sys下的子目录 | 说明 |
|---|---|
| /sys/devices | 这是系统中所有设备存放的目录,也就是系统中的所有设备在 sysfs 中的呈现、表达,也是 sysfs 管理设备的最重要的目录结构。 |
| /sys/block | 块设备的存放目录,这是一个过时的接口,按照 sysfs 的设计理念,系统所有的设备都存放在/sys/devices 目录下,所以/sys/block 目录下的文件通常是链接到/sys/devices 目录下的文件。 |
| /sys/bus | 这是系统中的所有设备按照总线类型分类放置的目录结构,/sys/devices 目录下每一种设备都是挂在某种总线下的,譬如 i2c 设备挂在 I2C 总线下。同样,/sys/bus 目录下的文件通常也是链接到了/sys/devices 目录。 |
| /sys/class | 这是系统中的所有设备按照其功能分类放置的目录结构,同样该目录下的文件也是链接到了/sys/devices 目录。按照设备的功能划分组织在/sys/class 目录下,譬如/sys/class/leds目录中存放了所有的 LED 设备,/sys/class/input 目录中存放了所有的输入类设备。 |
| /sys/dev | 这是按照设备号的方式放置的目录结构,同样该目录下的文件也是链接到了/sys/devices 目录。该目录下有很多以主设备号:次设备号(major:minor)命名的文件,这些文件都是链接文件,链接到/sys/devices 目录下对应的设备。 |
| /sys/firmware | 描述了内核中的固件。 |
| /sys/fs | 用于描述系统中所有文件系统,包括文件系统本身和按文件系统分类存放的已挂载点。 |
| /sys/kernel | 这里是内核中所有可调参数的位置。 |
| /sys/module | 这里有系统中所有模块的信息。 |
| /sys/power | 这里是系统中电源选项,有一些属性可以用于控制整个系统的电源状态。 |
应用层想要对底层硬件进行操控,通常可以通过两种方式:
- /dev/目录下的设备文件(设备节点);
- /sys/目录下设备的属性文件。
LED学习
led设备路径
/sys/class/leds/sys-led

brightness:LED亮度,可读可写,0亮,非0灭
max_brightness:LED最大亮度,只读
trigger:触发模式,可读可写,模式如下:
none(无触发)、mmc0(当对 mmc0 设备发起读写操作的时候 LED 会闪烁)、timer(LED 会有规律的一亮一灭,被定时器控制住)、heartbeat(心跳呼吸模式,LED 模仿人的心跳呼吸那样亮灭变化)。
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#define LED_TRIGGER "/sys/class/leds/sys-led/trigger"
#define LED_BRIGHTNESS "/sys/class/leds/sys-led/brightness"
/*
在 C 语言中,反斜杠 \ 的作用是 行连接符(line continuation character)。
它允许你在多个行中编写一条连续的语句,而不需要写成一行。
具体来说,反斜杠告诉编译器:下一行是当前行的延续,继续合并在一起,而不加上额外的换行符。
*/
#define USAGE() fprintf(stderr,"usage:\n" \" %s<on|off>\n" \" %s<trigger><type>\n",argv[0],argv[0]) //argv[0]存放程序的名称或路径int main(int argc, char *argv[])//argc参数个数,argv[]参数
{int fd1, fd2;//校验传参if(2>argc){USAGE();return 1;}// 打开sysfs中的trigger和brightness文件fd1 = open(LED_TRIGGER, O_RDWR);if (0 > fd1) {perror("open LED_TRIGGER error");return 1;}fd2 = open(LED_BRIGHTNESS, O_RDWR);if (0 > fd2) {perror("open LED_BRIGHTNESS error");close(fd1);return 1;}//根据传参控制LEDif(!strcmp(argv[1],"on")){//判断传入的第一个参数是否是onwrite(fd1,"none",4);//往trigger写入none,共4个字节,trigger设置为无触发write(fd2,"1",1);//点亮LED}else if(!strcmp(argv[1],"off")){//判断传入的第一个参数是否是offwrite(fd1,"none",4);write(fd2,"0",1);//熄灭LED}else if(!strcmp(argv[1],"trigger")){//如果传入的第一个参数是trigger但是参数个数不是三个,提示用法if(3!=argc){USAGE();return 1;}if(0 > write(fd1,argv[2],strlen(argv[2]))){//判断写入是否正确,将第三个参数即触发模式传给fd1 (none、mmc0、timer、heartbeat)perror("write error");return 1;}}elseUSAGE();return 0;
}

GPIO应用编程
GPIO目录
/sys/class/gpio
一共包含了 5 个 GPIO控制器,分别为 GPIO1、GPIO2、GPIO3、GPIO4、GPIO5,在这里分别对应 gpiochip0、gpiochip32、gpiochip64、gpiochip96、gpiochip128 这 5 个文件夹,每一个 gpiochipX 文件夹用来管理一组 GPIO

每一个gpiochipX文件夹里面有以下内容

base:与 gpiochipX 中的 X 相同,表示该控制器所管理的这组 GPIO 引脚中最小的编号,如
gpiochip32的base就是32
label:该组 GPIO 对应的标签,也就是名字
ngpio:该控制器所管理的 GPIO 引脚的数量,引脚编号范围是:base ~ base+ngpio-1
GPIO5_IO10在sysfs中对应的编号:128+10=138
export
export:用于将指定编号的 GPIO 引脚导出。在使用 GPIO 引脚之前,需要将其导出,导出成功之后才能使用它。注意 export 文件是只写文件,不能读取,将一个指定的编号写入到 export 文件中即可将对应的 GPIO 引脚导出
如下图,这个文件夹就是导出来的 GPIO 引脚对应的文件夹,用于管理、控制该 GPIO 引脚

unexport
unexport:将导出的 GPIO 引脚删除。当使用完 GPIO 引脚之后,我们需要将导出的引脚删除,同样该文件也是只写文件、不可读

gpioX文件夹里的文件

direction:配置 GPIO 引脚为输入或输出模式。该文件可读、可写,读表示查看 GPIO 当前是输入还是输出模式,写表示将 GPIO 配置为输入或输出模式;读取或写入操作可取的值为"out"(输出模式)和"in"(输入模式)
value:在 GPIO 配置为输出模式下,向 value 文件写入"0"控制 GPIO 引脚输出低电平,写入"1"则控制 GPIO 引脚输出高电平。在输入模式下,读取 value 文件获取 GPIO 引脚当前的输入电平状态。
active_low:这个属性文件用于控制极性,可读可写,默认情况下为 0,如果设置为1,则逻辑1为低电平,逻辑0为高电平
edge:控制中断的触发模式,该文件可读可写。在配置 GPIO 引脚的中断触发模式之前,需将其设置为输入模式
非中断引脚:echo "none" > edge
上升沿触发:echo "rising" > edge
下降沿触发:echo "falling" > edge
边沿触发 :echo "both" > edge
输出代码
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>static char gpio_path[100];//存放gpio设备文件路径//修改GPIO的状态
static int gpio_config(const char *attr, const char *value)//attr:修改的选项(direction、active_value、value)value:传入的值
{char file_path[100];int fd;int len;sprintf(file_path, "%s/%s", gpio_path, attr);//将/sys/class/gpio/gpiox/(direction或active_value或value)传给file_pathif(0 > (fd = open(file_path,O_WRONLY))){perror("open error");return fd;}len = strlen(value);if(len!= write(fd,value,len))//向file_path写入value,即修改gpio的状态{perror("write error");close(fd);return 1;}close(fd);return 0;
}int main(int argc, char *argv[])
{//判断传参是否正确if(3!=argc){fprintf(stderr,"usage: %s<gpio><value>\n", argv[0]);return 1;}//判断gpiox文件是否导出sprintf(gpio_path,"/sys/class/gpio/gpio%s",argv[1]);if(access(gpio_path,F_OK))//判断路径是否存在,不存在则创建,F_OK参数用于判断文件是否存在{int fd;int len;if(0 > (fd = open("/sys/class/gpio/export",O_WRONLY)))//打开export文件并将路径存放在fd,准备写入{perror("open error");return 1;}len = strlen(argv[1]);if(len != write(fd,argv[1],len))//向export写入gpio号,即导出gpio文件{perror("write error");close(fd);return 1;}close(fd);//关闭文件}//修改gpio的状态if(gpio_config("direction","out"))//配置为输出模式{return 1;}if(gpio_config("active_low","0"))//默认极性{return 1;}if(gpio_config("value",argv[2]))//控制GPIO高低电平{return 1;}//退出程序return 0;}
中断输入代码
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <poll.h>static char gpio_path[100];//存放gpio设备文件路径//修改GPIO的状态
static int gpio_config(const char *attr, const char *value)//attr:修改的选项(direction、active_low、value)value:传入的值
{char file_path[100];int fd;int len;sprintf(file_path, "%s/%s", gpio_path, attr);//将/sys/class/gpio/gpiox/(direction或active_low或value)传给file_pathif(0 > (fd = open(file_path,O_WRONLY))){perror("open error");return fd;}len = strlen(value);if(len!= write(fd,value,len))//向file_path写入value,即修改gpio的状态{perror("write error");close(fd);return 1;}close(fd);return 0;
}int main(int argc, char *argv[])
{struct pollfd pfd;//用于poll调用来监视文件描述符的事件,记得包含头文件poll.hchar file_path[100];//存储/sys/class/gpio/gpiox/value的路径int ret; //poll函数的返回值char value; //从GPIO引脚读取的值//判断传参是否正确if(2!=argc){fprintf(stderr,"usage: %s<gpio> <value>\n", argv[0]);return 1;}//判断gpiox文件是否导出sprintf(gpio_path,"/sys/class/gpio/gpio%s",argv[1]);if(access(gpio_path,F_OK))//判断路径是否存在,不存在则创建,F_OK参数用于判断文件是否存在{int fd;int len;if(0 > (fd = open("/sys/class/gpio/export",O_WRONLY)))//打开export文件并将路径存放在fd,准备写入{perror("open error");return 1;}len = strlen(argv[1]);if(len != write(fd,argv[1],len))//向export写入gpio号,即导出gpio文件{perror("write error");return 1;}close(fd);//关闭文件}//修改gpio的状态if(gpio_config("direction","in"))//配置为输入模式{return 1;}if(gpio_config("active_low","0"))//默认极性{return 1;}if(gpio_config("edge","both"))//设置中断触发方式,both是边沿触发{return 1;}//打开value属性文件sprintf(file_path,"%s/%s",gpio_path,"value");if(0 > (pfd.fd = open(file_path,O_RDONLY)))//用pfd.fd存储vlaue的文件路径{perror("open error");return 1;}/*调用pollstruct pollfd{int fd; //文件描述符short events; //等待的事件short revents; //返回的事件}*/pfd.events = POLLPRI;//只关心高优先级数据可读(中断)read(pfd.fd,&value, 1);//在进入循环之前,先读取一次GPIO状态,以清除先前的状态for( ; ; ){ret = poll(&pfd,1,-1);//调用poll,阻塞直到事件发生if(0 > ret){perror("poll error");return 1;}else if(0 == ret){fprintf(stderr,"poll timeout.\n");continue;}//校验高优先级数据是否可读if(pfd.revents & POLLPRI){if(0 > lseek(pfd.fd,0,SEEK_SET))//使用lseek重置文件指针,确保每次读取最新的GPIO状态{perror("lseek error");return 1;}if(0 > read(pfd.fd,&value,1)){perror("read error");return 1;}printf("gpio中断触发<value=%c\n",value);}}//退出程序return 0;
}
poll函数复习
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
/*
fds:指向一个 struct pollfd 类型的数组,储存关心的文件描述符
nfds:fds数组中元素的个数
timeout:决定poll函数的阻塞行为-1:一直阻塞,直到有信号来0:不阻塞>0:阻塞时间上限
*///struct pollfd 结构体
struct pollfd {int fd; /* 文件描述符 */short events; /* 等待的事件 */short revents; /* 返回的事件 */
};

输入设备
读取输入设备时,应用程序打开输入设备对应的设备文件,向其发起读操作,每一次 read 操作获取的都是一个 structinput_event 结构体类型数据,该结构体定义在<linux/input.h>头文件中
struct input_event {struct timeval time;__u16 type; //描述发生了哪一种类型的时间__u16 code; //该类事件具体是哪个事件,如键盘上不同的按键1、2、3...__s32 value;
/*
内核每次上报事件都会向应用层发送一个数据 value,对 value 值的解释随着 code 的变化而变化。譬如对于按键事件(type=1)来说,如果 code=2(键盘上的数字键 1,也就是 KEY_1),那么如果 value 等于 1,则表示 KEY_1 键按下;value 等于 0 表示 KEY_1 键松开,如果 value 等于 2则表示 KEY_1 键长按。再比如,在绝对位移事件中(type=3),如果 code=0(触摸点 X 坐标 ABS_X),那么 value 值就等于触摸点的 X 轴坐标值;同理,如果 code=1(触摸点 Y 坐标 ABS_Y),此时value 值便等于触摸点的 Y 轴坐标值;所以对 value 值的解释需要根据不同的 code 值而定
*/
};
type

code
Key

相对位移

绝对位移

通过数据同步使得应用程序得知本轮已经读取到完整的数据同步类事件有如下,所有的输入设备都需要上报同步事件,上报的同步事件通常是SYN_REPORT,而 value 值通常为 0
查看输入设备是哪个设备节点
cat /proc/bus/input/devices

输入设备代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>int main(int argc, char *argv[])
{struct input_event in_ev = {0};int fd = -1;int value = -1;//校验传参if(2 != argc){fprintf(stderr, "Usage: %s <input_dev>\n", argv[0]);return 1;}// 打开输入事件文件if(0 > (fd = open(argv[1], O_RDONLY))){perror("open error");return 1;}for( ; ; ){// 读取输入事件if(sizeof(struct input_event) != (read(fd, &in_ev, sizeof(struct input_event)))){perror("read error");break;}// 按键输入的类型if(EV_KEY == in_ev.type){switch (in_ev.value){case 0:printf("code<%d>:松开\n", in_ev.code);break;case 1:printf("code<%d>:按下\n", in_ev.code);break; case 2:printf("code<%d>:长按\n", in_ev.code);break; }}}
}
开发板KEY0按键测试

键盘测试
接入键盘,我使用的是2.4G连接方式

查看设备时发现有两个

event3是键盘上的按键

event4是键盘上的旋钮
由此可知这两个东西不是同一个设备

鼠标测试


只能读取鼠标的左、右和滚轮的按下和松开

相关文章:
Linux学习笔记(应用篇三)
基于I.MX6ULL-MINI开发板 LED学习GPIO应用编程输入设备 开发板中所有的设备(对象)都会在/sys/devices 体现出来,是 sysfs 文件系统中最重要的目录结构 /sys下的子目录说明/sys/devices这是系统中所有设备存放的目录,也就是系统中…...
LLM动态Shape实现原理与核心技术
LLM动态Shape实现原理与核心技术 目录 LLM动态Shape实现原理与核心技术1. **动态Shape核心原理**2. **实现方法与关键技术**3. **示例:vLLM处理动态长度输入**4. **动态Shape vs 静态Shape对比**5. **性能优化案例**总结`SamplingParams` 是什么常见参数及作用使用示例1. 动态…...
MyBatis 语法不支持 having 节点
MyBatis 不支持 having 节点 比如在 GROUP BY 之后添加了 HAVING 子句,其内容为SUM(vsbsad.business_income) > 0,该子句会对分组后的 SUM(vsbsad.business_income) 结果进行过滤,仅保留求和结果不为负数的分组记录。但是试过不支持。可把…...
【redis】事务详解,相关命令multi、exec、discard 与 watch 的原理
文章目录 什么是事务原子性一致性持久性隔离性 优势与 MySQL 对比用处 事务相关命令开启事务——MULTI执行事务——EXEC放弃当前事务——DISCARD监控某个 key——WATCH作用场景使用方法实现原理 事务总结 什么是事务 MySQL 事务: 原子性:把多个操作&am…...
数据库基础知识点(系列七)
视图和索引相关的语句 1.引入视图的主要目的是什么? 答:数据库的基本表是按照数据库设计人员的观点设计的,并不一定符合用户的需求。SQL Server 2008可以根据用户需求重新定义表的数据结构,这种数据结构就是视图。视图是关系数据…...
FreeRTOS 队列结构体 xQUEUE 深度解析
一、核心成员与功能设计 FreeRTOS 的队列结构体 xQUEUE 是任务间通信(IPC)的核心数据结构,通过统一的设计支持队列、信号量、互斥量等多种同步机制。其设计体现了 **"数据拷贝 结构复用"** 的理念,兼顾轻量化与扩展…...
3.3 Taylor公式
1.定义 1.1 taylor公式 1.2 麦克劳林公式 1.3 推论 1.4 拉格朗日余项和皮亚诺型余项 2. 例题 3.几种特殊函数的麦克劳林展开...
2000-2019年各省地方财政行政事业性收费收入数据
2000-2019年各省地方财政行政事业性收费收入数据 1、时间:2000-2019年 2、来源:国家统计局、统计年鉴 3、指标:行政区划代码、地区、年份、地方财政行政事业性收费收入 4、范围:31省 5、指标说明:地方财政行政事业…...
Ftrans飞驰云联受邀参加“2025汽车零部件CIO年会“并荣获智象奖
2025年3月6日,由栖观汽车、栖观资讯和飞羽商务主办的“2025第二届中国汽车&零部件CIO年会暨智象奖颁奖盛典”于上海盛大召开,Ftrans飞驰云联作为国内领先的企业文件传输与数据交换解决方案提供商,受邀出席了年会,并凭借卓越的…...
C++vector常用接口和模拟实现
C中的vector是一个可变容量的数组容器,它可以像数组一样使用[]进行数据的访问,但是又不像C语言数组空间是静态的,它的空间是动态可变的。 在日常中我们只需要了解常用的接口即可,不常用的接口查文档即可。 1.构造函数 //空构造…...
oracle查询归档日志使用量
1.统计最近30天的数据 SELECT TRUNC(first_time, DD) "日期", SUM(blocks * block_size) / 1024 / 1024 / 1024 "大小(GB)" FROM v$archived_log WHERE first_time > SYSDATE - 30 -- 统计最近30天的数据 GROUP BY TRUNC(first_time, DD) ORDER BY 1 D…...
计算机二级WPS Office第七套WPS演示
解题过程...
2025-03-26 学习记录--C/C++-PTA 6-3 求链式表的表长
合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。💪🏻 一、题目描述 ⭐️ 6-3 求链式表的表长 本题要求实现一个函数,求链式表的表长。 函数接口定义: &…...
【Mysql】事务管理:原理、操作与应用
文章目录 一、事务概述二、事务的特性(ACID)原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability) 三、事务的操作事务的提交方式查看和…...
PHP框架 ThinkPHP 漏洞探测分析
目录 1. PHP历史利用最多的漏洞有哪些? 2. 如何在信息收集的过程中收到框架信息?有什么根据? 3. ThinkPHP框架漏洞扫描有哪些工具?红队攻击有哪些方式? 漏洞扫描工具 红队攻击方式 4. TPscan工具的主要作用及实际…...
A Brief History: from GPT-1 to GPT-3
This is my reading notes of 《Developing Apps with GPT-4 and ChatGPT》. In this section, we will introduce the evolution of the OpenAI GPT medels from GPT-1 to GPT-4. GPT-1 In mid-2018, OpenAI published a paper titled “Improving Language Understanding …...
大模型在支气管肺癌预测及临床决策中的应用研究报告
目录 一、引言 1.1 研究背景与意义 1.2 研究目的 二、大模型预测支气管肺癌的原理与技术基础 2.1 大模型简介 2.2 数据收集与预处理 2.3 模型训练与优化 三、术前预测 3.1 病情评估 3.1.1 肿瘤大小、位置及分期预测 3.1.2 转移风险预测 3.2 手术风险预测 3.2.1 患…...
SylixOS 中 select 原理及使用分析
1、select接口简介 1.1 select接口使用用例 select 是操作系统多路 I/O 复用技术实现的方式之一。 select 函数允许程序监视多个文件描述符,等待所监视的一个或者多个文件描述符变为“准备好”的状态。所谓的”准备好“状态是指:文件描述符不再是阻塞状…...
软考笔记——软件工程基础知识
第五章节——软件工程基础知识 软件工程基础知识 第五章节——软件工程基础知识一、软件工程概述1. 计算机软件2. 软件工程基本原理3. 软件生命周期4. 软件过程 二、软件过程模型1. 瀑布模型2. 增量模型3. 演化模型(原型模型、螺旋模型)4. 喷泉模型5. 基于构建的开发…...
FastGPT原理分析-数据集创建第二步:处理任务的执行
概述 文章《FastGPT原理分析-数据集创建第一步》已经分析了数据集创建的第一步:文件上传和预处理的实现逻辑。本文介绍文件上传后,数据处理任务的具体实现逻辑。 数据集创建总体实现步骤 从上文可知数据集创建总体上来说分为两大步骤: &a…...
基于Python的3D贴图制作技术研究与实践
摘要:本文深入探讨了利用Python进行3D贴图制作的技术,介绍了Python在3D图形领域的应用优势,阐述了3D贴图的基本原理和常见类型。详细讲解了借助Python的相关库,如Pillow、OpenCV、PyTorch3D开展3D贴图制作的流程,包括纹…...
【MySQL数据库】视图 + 三范式
视图 视图的基本介绍 MySQL中的视图(View)是一种虚拟的表,其内容是从一个或多个基本表中检索出来的。视图可以简化复杂的查询操作,提高查询效率,同时也可以对敏感数据进行安全性控制。下面是关于MySQL视图的一些基本…...
STM32学习笔记之存储器映射(原理篇)
📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…...
如何通过数据可视化提升管理效率
通过数据可视化提升管理效率的核心方法包括清晰展示关键指标、及时发现和解决问题、支持决策优化。其中,清晰展示关键指标尤为重要。通过数据可视化工具直观地呈现关键绩效指标(KPI),管理者能快速、准确地理解业务现状,…...
数据结构:利用递推式计算next表
next 表是 KMP 算法的核心内容,下面介绍一种计算 next 表的方法:利用递推式计算 如图 6.3.1 所示,在某一趟匹配中,当对比到最后一个字符的时候,发现匹配失败(s[i] ≠ t[j])。根据 BF 算法&…...
每日算法-250326
83. 删除排序链表中的重复元素 题目描述 思路 使用快慢指针遍历排序链表。slow 指针指向当前不重复序列的最后一个节点,fast 指针用于向前遍历探索。当 fast 找到一个与 slow 指向的节点值不同的新节点时,就将 slow 的 next 指向 fast,然后 …...
trino查询mysql报Unknown or incorrect time zone: ‘Asia/Shanghai‘
问题 trino查询mysql时报Error listing schemas for catalog mysql: java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.,trino的日志中看到Unknown or incorrect time zone…...
java学习笔记7——面向对象
关键字:static 类变量 静态变量的内存解析: 相关代码: public class ChineseTest {public static void main(String[] args) {System.out.println(Chinese.nation); //null 没赋值前System.out.println(Chinese.nation); //中国 静态变量赋值…...
leetcode day31 453+435
453 用最少数量引爆气球 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。 一支弓箭可以沿着 x 轴从不同点 完全垂直 地…...
C++三大特性之继承
1.继承的概念及定义 回忆封装 C Stack类设计和C设计Stack对比。封装更好:访问限定符类的数据和方法放在一起 -> 避免底层接口的暴露,数据更加的安全,程序的耦合性更高迭代器的设计,封装了容器底层结构,在不暴露底层…...


