【C++】—— 类和对象(一)

【C++】—— 类和对象(一)

  • 1、类的定义
  • 2、实例化
    • 2.1、实例化的概念
    • 2.2、对象大小
      • 2.2.1、对象的大小包括什么
      • 2.2.2、内存对齐规则
      • 2.2.3、空类的大小
  • 3、 t h i s this this 指针
  • 4、练习
    • 4.1、题一
    • 4.2、题二

1、类的定义

1.1、类定义

1.1.1、类定义格式

  • c l a s s class class 为定义类的关键字, c l a s s class class 后接类的名字(自己定),{ } 为类的主体,注意类定义结束时,后面的 不能省略

  • 类体中的内容为类的成员:类中的变量称为类的成员变量属性,类中的函数称为类的成员函数方法

  
下面我们简单写一个栈类来感受一下

class Stack
{
public://成员函数void Init(int n = 4){_a = (int*)malloc(sizeof(int) * n);if (nullptr == _a){perror("malloc fail");exit(1);}_capccity = n;_top = 0;}void Push(int x){// ...扩容_a[top++] = x;}void Destroy(){fail(_a);_a = nullptr;_capacity = 0;_top = 0;}private://成员变量int* _a;size_t _capacity;size_t _top;
};//分号不能省略

  C++中,并没有规定成员函数和成员变量的位置,只要他们在类中就行,把成员变量混在几个函数的中间也是可以的。但一般来讲都是成员函数在上,成员变量在下。
  

1.1.2、成员变量的标识

  • 为了区分成员变量,一般习惯上成员变量会加上一个特殊的标识,如成员变量前或后加上 _ ;或 m ( m e m b e r ) m(member) m(member) 开头;或 m m m_ 开头。这点C++并没有明确规定,具体看公司的要求

  
  在声明栈类的成员变量时,大家可能发现我在变量名前都加上了 “_”,为什么要这么做呢?
  我们来看一个日期类

class Date
{
public:void Init(int year, int month, int day){year = year;month = month;day = day;}private:int year;int month;int day;
};

  可以看到,上述日期类的成员变量与 I n i t Init Init 函数中的形参无法区分,所以为了区分成员变量,要在成员变量前加上特殊的标识
  

1.1.3、C++ 中的 s t r u c t struct struct

  • C++ 中 s t r u c t struct struct 也可以定义类,C++ 中兼容了 C语言 中 s t r u c t struct struct 的用法,同时 s t r u c t struct struct 升级成了
  • 明显的变化是: s t r u c t struct struct 中可以定义函数。 s t r u c t struct struct c l a s s class class 定义类只有一点细微的差别(下面会说),但一般情况下我们还是推荐使用 c l a s s class class 定义类

  
  在C语言,我们定义一个链表的节点,往往是这样定义的:

typedef struct ListNodeC
{int val;struct ListNode* next;
}ListNodeC;

  
在 C++中, s t r u c t struct struct 升级成了

  1. 类可以定义函数
  2. 名称就可以代表类型,不需要 s t r u c t struct struct + 名称

  

// 不再需要typedef,ListNodeCPP就可以代表类型
struct ListNodeCPP
{void Init(int x){next = nullptr;val = x;} ListNodeCPP* next;int val;
};

  当然,C++ 是兼容 C 的,所以上面的那种方式 C++ 也支持
  

1.1.4、C++ 中的内联函数

  • 在类中定义的成员函数默认是 i n l i n e inline inline,而如果进行声明和定义的分离:声明在类中;定义在类外,则不然。

  

1.1.5、总结

  • c l a s s class class 为定义类的关键字 S t a c k Stack Stack 为类的名字{ } 中为类的主体,注意类定义结束时后面分号不能省略。类体中内容称为类的成员:类中的变量称为类的属性成员变量;类中的函数称为类的方法或者成员函数
      
  • 为了区分成员变量,一般习惯上成员变量会加一个特殊标识,如成员变量前面或者后面加 _ 或者 m m m 开头,注意 C++ 中这个并不是强制的,只是一些管理,具体看公司要求
      
  • C++ 中 s t r u c t struct struct可以定义类,C++ 兼容 C 中 s t r u c t struct struct 的用法,同时 s t r u c t struct struct 升级成了类,明显的变化是 s t r u c t struct struct 中可以定义函数,一般情况下我们还是推荐使用 class 定义类
      
  • 定义在类里面的成员函数默认为 i n l i n e inline inline

  

1.2、访问限定符

  可能有小伙伴注意到了,前面定义栈类日期类时,出现了 p u b l i c public public p r i v a t e private private 两个关键字,他们有什么用呢?我们一起来看看

  • C++ 一种实现封装的方式,用类将对象的属性和方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用
  • p u b l i c public public 修饰的成员类外可以直接被访问 p r o t e c t e d protected protected p r i v a t e private private 修饰的成员类外不能直接被访问。现阶段我们认为 p r o t e c t e d protected protected p r i v a t e private private 是一样的,以后集成章节才能体现出他们的区别.
  • 访问权限作用域从该访问限定符出现的位置开始,直到下一个访问限定符出现为止,如果后面没有访问限定符,作用域就到 } (收括号)即类结束
  • c l a s s class class 定义成员没有被访问限定符修饰时默认 p r i v a t e private private s t r u c t struct struct 默认 p u b l i c public public 。这也是 c l a s s class class s t r u c t struct struct唯一区别
  • 一般成员变量都会被限制为 p r i v a t e private private/ p r o t e c t e d protected protected,需要给别人使用的成员函数为 p u b l i c public public。当然这只是一般情况,并没有硬性规定

  

在这里插入图片描述

  
举个栗子:

在这里插入图片描述

  当然,一般情况下也没有人会这样写。一般都是公有的放一起,私有的放一起。
  
像这样:

在这里插入图片描述

  
  

1.3、类域

  在C++中,凡是用 { } 括起来的都会形成一个 。类也不例外,类定义了一个新的作用域: 类域,类的所有成员都在类的作用域中。

  不知大家有没有注意到,在前面定义的栈类中,成员函数的命名不再像之前 C语言 写栈时那样要加上栈的标识,如: void STDestroy()。之前 C语言 这样写是因为结构体和函数是分离的,栈叫 D e s t r o y Destroy Destroy ,队列也叫 D e s t r o y Destroy Destroy 就有可能搞混,且同一个域中也不允许出现同名的变量或函数。
  现在他们是栈类的成员函数,在类域之中,即使后面定义的一个队列域有同名的成员函数,也不会冲突。因为名字冲突只发生在同一个域中,不同域可以有相同名字

  那当成员函数的声明和定义分离时,即声明在类内,定义在类的外面,又该如何定义函数呢?

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

  
  我们知道,任何一个变量,编译器都会去找他的出处(声明/定义)。编译器默认只会在全局域或当前函数局部域去找,并不会去类域中找。那怎么办呢?我们告诉他去指定的类域中找就行了。

  • 在类体外定义成员时,需要使用 : : 作用域操作符 指明成员属于哪个类域
class Date
{
public:void Init(int year, int month, int day);private:int _year;int _month;int _day;
};void Date::Init(int year, int month, int day)
{_year = year;_month = month;_day = day;
}

  这样就行了

  • 类域影响的是编译的查找规则
      
    上述程序 I n i t Init Init 如果不指定类域 D a t e Date Date,那么编译器就把 I n i t Init Init 当成全局函数,那么编译时,找不到 _ y e a r year year 等成员的声明/定义在哪里,就会报错。
    指定类域 D a t e Date Date,就是告诉编译器 I n i t Init Init 是成员函数,在当前域找不到的 _ y e a r year year 等成语,就会到类域中去查找。

  

2、实例化

2.1、实例化的概念

  在讲解类的实例化之前,我们先来思考一个问题

在这里插入图片描述

上述成员变量是声明还是定义呢?

答案是 声明
  对变量来说,到底是声明还是定义是看他是否有开空间开了空间的是定义;没开空间的是声明
  

int main()
{Date::_year = 0;return 0;
}

  我们直接这样访问是会报错的,因为 _ y e a r year year 只是一个声明,并没有开空间。

  那什么时候开空间呢?
  用该类型实例化出一个对象才是开空间

int main()
{Date d1;Date d2;Date d3;return 0;
}

  上述就是类的实例化,类和对象是一对多的关系,一个类可以实例化出多个对象
  
  怎么理解这个实例化呢?我们可以用图纸和实物建筑来类比

在这里插入图片描述

  类就相当于图纸,图纸上有房子上的各种信息,当不能进去住人;而实例化对象就像是依照着图纸将房子盖好,盖好的房子是可以住人的,相当于实例化开了空间。

  

2.2、对象大小

2.2.1、对象的大小包括什么

  在学习 C语言 结构体时,我们知道结构体中就存着成员,这些成员要按照内存对齐的规则去进行计算大小。类的对象中的成员变量也是如此,成员变量是存储在对象中的。
  现在的问题是:成员函数是否是存储在对象中的呢?
答案是:不需要
  
为什么呢?我们用日期类来举例

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和d2Date d1;Date d2;d1.Init(2024, 3, 31);d1.Print();d2.Init(2024, 7, 5);d2.Print();return 0;
}

  
  上述代码中,示例化出了 d 1 d1 d1 d 2 d2 d2 两个对象
  我们给两个对象的年月日(成员变量)初始化了不同的值,所以他们的成员变量是不一样的,他们要各种存储自己的成员变量,因此成员变量肯定是存储在对象中
  
  那现在的 d 1 d1 d1 d 2 d2 d2 调用 P r i n t Print Print 函数是调用同一个函数还是不同的函数?
  很显然是同一个函数
  既然都是一样的,那在各自的对象中都存一份,是不是太浪费空间了。我要是实例化10000个对象那不是要重复存储10000份?
  我们通过汇编代码可以看到两个对象调用的都是同一个函数
  

在这里插入图片描述
  
两个 c a l l call call 指令, c a l l call call 的地址都是一样的,表明跳转的是同一个函数
  
  在这里插入图片描述
  
c a l l call call 指令跳转到 jmp 指令
  在这里插入图片描述
  
j m p jmp jmp 指令再跳转到函数

  成员函数其实是存在一个公共的区域

  既然函数不存在对象里面,那函数指针有必要存在对象里面吗?
  也是没必要的,原因还是重复存储浪费空间。
  

  • 函数指针是⼀个地址调⽤函数被编译成汇编指令[ c a l l call call 地址],其实编译器在编译链接时,就要找到函数的地址,不是在运⾏时找,只有动态多态是在运⾏时找,就需要存储函数地址,这个我们以后再学习

  

2.2.2、内存对齐规则

类的大小计算和结构体的计算是一样的,这里我们简单回顾一下。详情请看【C语言】——结构体

  • 第一个成员在与结构体偏移量为 0 的地址处。
  • 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
  • 注意:对齐数 = 编译器默认的一个对齐数与该成员大小的较小值
  • VS 中默认的对齐数是 8
  • 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍
  • 如果嵌套了结构体的情况,嵌套的结构体对齐到之间的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(函嵌套结构体的对齐数)的整数倍

  

2.2.3、空类的大小

class A
{public :void Print(){//...}
};
int main()
{A a;cout << sizeof(a) << endl;return 0;
}

  现在有一个问题: a a a 的大小是多大呢?
  
运行结果:

在这里插入图片描述

  为什么该对象没有成员变量还有 1 字节的大小呢
  这里的 1 为了占位
  因为如果一个空间对不给,怎么证明这个对象存在过呢,所以这里给了1个空间大小,纯粹是为了占位表示对象存在
  

3、 t h i s this this 指针

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;Date d2;d1.Init(2024, 3, 31);d1.Print();d2.Init(2024, 7, 5);d2.Print();return 0;
}

  现在,我们知道 d 1 d1 d1 d 2 d2 d2 调用的都是同一个 I n i t Init Init 函数和 P r i n t Print Print 函数,那既然是同一个函数为什么能打印出各自的成员变量呢?他们是怎么区分 d 1 d1 d1 d 2 d2 d2 的呢?

在这里插入图片描述

  
  C++中,给了一个隐含的 t h i s this this指针 解决这个问题

  • 编译器编译后,类的成员函数默认会在形参的第一个位置,增加一个当前类类型的指针,叫做 t h i s this this指针。比如 D a t e Date Date 类的 I n i t Init Init 的真实原型为: void Init(Date* const this, int year,int month, int day)
  • 类的成员函数中访问成员变量,本质是通过 t h i s this this 指针访问的,如 I n i t Init Init 函数中给 _ y e a r year year 赋值, this->_year = year;
  • C++ 规定不能在实参和形参的位置显示的写 t h i s this this指针(编译时编译器会处理),但是可以在函数体内显示使用 t h i s this this 指针

  
  因此,上述代码底层是这样的:

class Date
{
public:void Init(Date* const this, year, int month, int day){this->_year = year;this->_month = month;this->_day = day;}void Print(Date* const this){cout << this->_year << "/" << this->_month << "/" << this->_day << endl;}private:int _year;int _month;int _day;
};
int main()
{Date d1;Date d2;d1.Init(&d1, 2024, 3, 31);d1.Print(&d1);d2.Init(&d2, 2024, 7, 5);d2.Print(&d2);return 0;
}

:这只是底层,实际代码是不允许这样写的。因为 t h i s this this 指针不能在实参和形参显示写;但在函数体内可以使用 this 指针
  
  
那么 t h i s this this指针是存在哪一个区域的呢?

在这里插入图片描述

  首先,肯定不是对象里面。因为我们前面讲解对象大小时,并没有计算 t h i s this this 指针
  我们来看, t h i s this this 指针是一个形参,那形参是存在哪里的呢?
  答案是:
  但这答案也不完全对。
  因为 t h i s this this 指针需要频繁调用,因此有些编译器(如VS)会对其进行优化,放在寄存器

  

4、练习

4.1、题一

下面程序的运行结果是?
A、编译报错    B、正常运行    C、运行崩溃

class A
{public :void Print(){cout << "A::Print()" << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}

  首先把 A 排除了,因为上述程序就算出错那也是因为空指针的问题出错,对空指针的解引用什么时候是编译报错呢?
  
  这题的答案:B

  我们来看p->Print();,这句代码转换成汇编指令是: c a l l call call 指令 -> j m p jmp jmp 指令 -> P r i n t Print Print函数;那 P r r i n t Prrint Prrint 函数在哪呢?在公共代码区,并不在对象中;同时 P r i n t Print Print函数需要传递 t h i s this this 指针,这里传的是 p p p,即 n u l l p t r nullptr nullptr
  
  这一切都没有问题。虽然传递了 n u l l p t r nullptr nullptr t h i s this this 指针,但是函数内并没有对其进行解引用
  我们不要看到对象调用函数:p->Print();就以为是对 n u l l p t r nullptr nullptr 进行了解引用,我们要关注代码的底层
  那为什么需要对象取调用呢?因为 P r i n t Print Print 是其成员函数,在其类域之中,它要过编译那关,语法那关

  

4.2、题二

下面程序的运行结果是?
A、编译报错    B、正常运行    C、运行崩溃

class A
{public :void Print(){cout << "A::Print()" << endl;cout << _a << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}

答案:C

  这题与上题的区别是 P r i n t Print Print 函数中多了cout << _a << endl;
  前面的步骤都是与上题一样,但到了cout << _a << endl;语句时,要对 t h i s this this 指针进行解引用cout << this->_a << endl;,因为 t h i s this this 指针是空指针,对空指针进行解引用自然就运行崩溃啦

  
  
  
  
  


  好啦,本期关于类和对象的知识就介绍到这里啦,希望本期博客能对你有所帮助。同时,如果有错误的地方请多多指正,让我们在C语言的学习路上一起进步!

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

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

相关文章

lenovo联想ThinkBook 14 G4+ IAP/ARA(21CX,21D0)笔记本原装出厂Windows11系统预装OEM镜像下载

ThinkBook 14 G4 IAP【21CX】原厂系统Win11恢复安装包&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1iY9BxidIbv4RnXKaqbydTA?pwd9wc6 提取码&#xff1a;9wc6 ThinkBook 14 G4 ARA【21D0】原厂系统Win11恢复安装包&#xff1a; 链接&#xff1a;https://pan.ba…

nest学习笔记(一)

介绍 nest是一个用于构建高效&#xff0c;可拓展的nodejs服务端应用程序的框架&#xff0c;它使用渐进式javascript&#xff0c;使用Typescript构建并且完全支持Typescript&#xff0c;而且运行开发者使用javascript编写代码&#xff0c;提供了OOP、FP、FRP nest的底层是基于…

Linux编程:使用python或者shell获取系统信息

0. 概要 在日常的系统管理和性能监控中&#xff0c;获取系统信息是一个非常常见的需求。 本文将介绍如何使用Python和Shell脚本来获取这些系统信息。 1. 使用Python获取系统信息 使用psutil库来获取系统的CPU、内存、磁盘和网络信息。 1.1 安装psutil库 首先&#xff0c;我…

盗梦空间续集(InceptionNeXt):使用Inception优化加速ConvNeXt实现ImageNet-1K的最佳精度

Abstract 灵感来自ViT的长距离建模能力&#xff0c;大核卷积最近被广泛研究和采用&#xff0c;以扩大感受野并提高模型性能&#xff0c;例如显著的工作ConvNeXt采用77深度卷积。虽然这种深度算子只消耗少量的FLOPs&#xff0c;但由于高内存访问成本&#xff0c;它在强大计算设…

java实战项目--拼图小游戏(附带全套源代码)

个人主页VON 所属专栏java实战项目游戏参考黑马程序员 一、效果展示 二、功能介绍 游戏中所有的图片以及代码均已打包&#xff0c;玩家直接安装游戏即可&#xff0c;不用idea也可以畅玩。 游戏功能比较单一&#xff0c;只有简单的拼图功能。 a&#xff1a;展示原图重新游戏&a…

《汇编语言 基于x86处理器》- 读书笔记 - 第3章-汇编语言基础

《汇编语言 基于x86处理器》- 读书笔记 - 第3章-汇编语言基础 3.1 基本语言元素3.1.1 第一个汇编语言程序常见汇编语言调用规范 3.1.2 整数常量&#xff08;基数、字面量&#xff09;3.1.3 整型常量表达式3.1.4 实数常量十进制实数十六进制实数&#xff08;编码实数&#xff09…

USB 2.0 协议专栏之 USB 2.0 概述(一)

前言&#xff1a;本篇博客为手把手教学的 USB 2.0 协议栈类精品博客&#xff0c;该专栏博客侧重针对 USB 2.0 协议进行讲解。Universal Serial Bus 作为如今最常见的通信接口&#xff0c;被广泛应用于&#xff1a;Keyboard、Mouse、Communication Device Class 和 Mass Storage…

“论企业集成架构设计及应用”写作框架,软考高级论文,系统架构设计师论文

原创范文 论企业集成架构设计及应用企业集成架构(Enterprise Integration Arhitecture&#xff0c;EIA) 是企业集成平台的核心&#xff0c;也是解决企业信息孤岛问题的关键。企业集成架构设计包括了企业信息、业务过程、应用系统集成架构的设计。实现企业集成的技术多种多样&a…

什么是 Windows 服务

什么是 Windows 服务 Windows 服务是 Windows 操作系统的核心。它们控制着操作系统的运行&#xff0c;定义了图形用户界面&#xff08;GUI&#xff09;与系统硬件之间的通信以及其他许多功能。没有这些服务&#xff0c;Windows 操作系统将无法正常运行。 对普通用户而言&…

【人工智能】人工智能概述(二)人工智能的关键技术

文章目录 一. 机器学习与深度学习1. 机器学习2. 深度学习 二. 计算机视觉1. 基本概念和分类2. 未来计算机视觉面临的主要挑战 三. 自然语言处理1. 基本概念与分类2. 自然语言处理面临的四大挑战 四. 知识图谱1. 基本概念2. 应用场景 五. SLAM技术1. 基本概念2. 主要分类 六. 人…

DSP教学实验箱_数字图像处理操作_案例分享:5-13 灰度图像二值化

一、实验目的 学习灰度图像二值化的原理&#xff0c;掌握图像的读取方法&#xff0c;并实现在LCD上显示二值化前后的图像。 二、实验原理 图像二值化 图像的二值化处理就是将图像上的点的灰度置为 0 或 255&#xff0c;也就是将整个图像呈现出明显的黑白效果。即将 256 个亮…

AJAX(1)——axios库的使用

什么是AJAX? AJAX是异步的JavaScript和XML。简单来说&#xff0c;就是使用XMLHttpRequest对象与服务器通信。它可以使用JSON,XML,HTML和text文本等格式发送和接收数据。AJAX最吸引人的就是它异步的特性&#xff0c;也就是说它可以在不重新刷新页面的情况下与服务器通信&#…

昇思25天学习打卡营第25天|LLM应用-基于MindNLP+MusicGen生成自己的个性化音乐

打卡 目录 打卡 应用任务简介 生成音乐 预训练权重模型下载 无提示生成 文本提示生成 音频提示生成 生成配置 应用任务简介 MusicGen 来自 Meta AI 的 Jade Copet 等人提出的基于单个语言模型&#xff08;LM&#xff09;的音乐生成模型&#xff0c;能够根据文本描述或…

NFS服务器环境搭建

1、什么是NFS ● 定义&#xff1a; NFS是一种在计算机系统之间共享文件和目录的协议&#xff0c;最初由Sun Microsystems开发&#xff0c;现在已经成为广泛使用的网络文件系统之一。 ● 核心功能&#xff1a; 通过网络&#xff08;特别是TCP/IP网络&#xff09;实现文件共享…

微信小程序配置访问服务器失败所发现的问题及解决方案

目录 事前现象问题1&#xff1a;问题现象&#xff1a;问题分析&#xff1a; 问题2&#xff1a;问题现象&#xff1a;问题分析&#xff1a;解决方案&#xff1a; 事后现象 事前现象 问题1&#xff1a; 问题现象&#xff1a; 在本地调试时&#xff0c;一切顺利&#xff0c;但一…

Flink Doirs Connector 常见问题:Doris目前不支持流读

常见问题 Doris Source 在数据读取完成后&#xff0c;流为什么就结束了&#xff1f; 目前 Doris Source 是有界流&#xff0c;不支持 CDC 方式读取。 问题&#xff1a;对于 Flink Doris DataStream&#xff0c;Flink 想要在 流式读取 Doirs / 实时读 Doris&#xff0c;目前读…

03--KVM虚拟化

前言&#xff1a;这里开始涉及到云计算内容&#xff0c;虚拟化使云计算发展&#xff0c;云计算推动虚拟化进步&#xff0c;两者相辅相成&#xff0c;这一章总结一下kvm虚拟化的解决方案。 1、基础概念 1.1、云计算 以前要完成信息处理, 是需要在一个客观存在的计算机上完成的…

Node.js版本管理工具之NVM

目录 一、NVM介绍二、NVM的下载安装1、NVM下载2、卸载旧版Node.js3、安装 三、NVM配置及使用1、设置nvm镜像源2、安装Node.js3、卸载Node.js4、使用或切换Node.js版本5、设置全局安装路径和缓存路径 四、常用命令技术交流 博主介绍&#xff1a; 计算机科班人&#xff0c;全栈工…

卷积神经网络(一)---原理和结构

在介绍卷积神经网络之前&#xff0c;先提出三个观点&#xff0c;正是这三个观点使得卷积神经网络能够真正起作用。 1. 局部性 对于一张图片而言&#xff0c;需要检测图片中的特征来决定图片的类别&#xff0c;通常情况下这些特征都不是由整张图片决定的&#xff0c;而是由一些…

vscode 环境

这张截图显示的是在VS Code&#xff08;Visual Studio Code&#xff09;中选择Python解释器的界面。不同的Python解释器及其虚拟环境列出了可选项&#xff0c;用户可以根据需要选择合适的解释器来运行Python代码。以下是对截图中信息的详细解释&#xff1a; 解释器选择界面 当…