(学习总结17)C++继承

C++继承

  • 一、继承的概念与定义
    • 继承的概念
    • 继承定义
      • 1. 定义格式
      • 2. 继承基类成员访问方式的变化
    • 继承类模板
  • 二、基类和派生类间的转换
  • 三、继承中的作用域
    • 隐藏规则
  • 四、派生类的默认成员函数
    • 4个常见默认成员函数
    • 实现一个不能被继承的类
  • 五、继承与友元
  • 六、继承与静态成员
  • 七、多继承及其菱形继承问题
    • 继承模型
    • 虚继承
    • 多继承中指针偏移问题
  • 八、继承和组合

以下代码环境为 VS2022 C++

一、继承的概念与定义

继承的概念

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许我们在保持原有类特性的基础上进行扩展,增加方法(成员函数)和属性(成员变量),这样产生新的类,称为派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。将一个功能设计成函数是函数层次的复用,继承是类设计层次的复用。

下面设计了两个没有继承的类 Student 和 Teacher,Student 和 Teacher 都有 姓名 / 地址 / 电话 / 年龄 等成员变量,都有 identity 身份认证的成员函数,设计到两个类里面就是冗余的。当然他们也有一些不同的成员变量和函数,比如老师独有成员变量是职称,学生的独有成员变量是学号;学生的独有成员函数是学习,老师的独有成员函数是授课

class Student
{
public:void identity(){// ...}void study(){// ...}protected:string _name = "peter"; // 姓名string _address;		// 地址string _tel;			// 电话int _age;				// 年龄int _stuid;				// 学号
};class Teacher
{
public:void identity(){// ...}void teaching(){//...}protected:string _name = "张三";	// 姓名string _address;		// 地址string _tel;			// 电话int _age = 18;			// 年龄string _title;			// 职称
};

下面公共的成员都放到 Person 类中,Student 和 teacher 都继承 Person,可以复用这些成员,不需要重复定义,省去了很多麻烦。

class Person
{
public:void identity(){cout << "void identity()" << _name << endl;}protected:string _name = "张三";	// 姓名string _address;		// 地址string _tel;			// 电话int _age;				// 年龄
};class Student : public Person
{
public:void study(){// ...}protected:int _stuid;				// 学号
};class Teacher : public Person
{
public:void teaching(){//...}protected:string _title;			// 职称
};

继承定义

1. 定义格式

下面看到 Person 是基类,也称作父类。Student 是派生类,也称作子类。(因为翻译的原因,所以既叫 基类 / 派生类,也叫 父类 / 子类)

在这里插入图片描述

2. 继承基类成员访问方式的变化

类成员 / 继承方式public 继承protected 继承private 继承
基类的 public 成员派生类的 public 成员派生类的 protected 成员派生类的 private 成员
基类的 protected 成员派生类的 protected 成员派生类的 protected 成员派生类的 private 成员
基类的 private 成员在派生类中不可见在派生类中不可见在派生类中不可见
  1. 基类 private 成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它

  2. 基类 private 成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为 protected。

  3. 根据上面的表格总结会发现,基类的私有成员在派生类都是不可见。基类的其他成员在派生类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。

  4. 使用关键字 class 时默认的继承方式是 private,使用 struct 时默认的继承方式是 public,不过最好显示的写出继承方式

  5. 在实际运用中一般使用都是 public 继承,几乎很少使用 protetced / private 继承,也不提倡使用 protetced / private 继承,因为 protetced / private 继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强。

class Person
{
public:void identity(){cout << "void identity()" << _name << endl;}protected:string _name = "张三";	// 姓名string _address;		// 地址string _tel;			// 电话private:int _age;				// 年龄
};// class Student : private Person
// class Student : protected Person
class Student : public Person
{
public:void study(){// ...}protected:int _stuid;				// 学号
};

继承类模板

继承是一种 is - a 的关系。例如 Stack 可以算是 vector,则 Stack 可以继承 vector 来实现:

#include <iostream>
#include <vector>template<class T>
class Stack : protected std::vector<T>
{
public:// 基类是类模板时,需要指定⼀下类域,// 否则编译报错找不到其标识符,// 因为 stack<int> 实例化时,也实例化 vector<int> 了// 但是模版是按需实例化,push_back 等成员函数未实例化,所以找不到void push(const T& n){std::vector<T>::push_back(n);}void pop(){std::vector<T>::pop_back();}T& top(){return std::vector<T>::back();}bool empty(){return std::vector<T>::empty();}
};int main()
{Stack<int> st;for (int i = 1; i <= 5; ++i){st.push(i);}while (!st.empty()){std::cout << st.top() << std::endl;st.pop();}return 0;
}

二、基类和派生类间的转换

  1. public 继承的 派生类对象 可以赋值给 基类的指针 / 基类的引用。这里有个形象的说法叫切片或者切割。寓意把派生类中基类那部分切出来,基类指针或引用指向的是派生类中切出来的基类那部分。

  2. 基类对象不能赋值给派生类对象。

  3. 基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针指向派生类对象时才是安全的。这里基类如果是多态类型,可以使用 RTTI(Run-Time Type Information)的 dynamic_cast 来识别后进行安全转换。

#include <iostream>
using namespace std;class Person
{
protected:string _name;	// 姓名string _sex;	// 性别int _age;		// 年龄
};class Student : public Person
{
public:int _No;		// 学号
};int main()
{Student stu;// 1.派⽣类对象可以赋值给基类的指针 / 引⽤Person* pp = &stu;Person& rp = stu;// 2.派⽣类对象可以赋值给基类的对象是通过调⽤基类的拷⻉构造完成的Person per = stu;// 3.基类对象不能赋值给派⽣类对象,这⾥会编译报错//sobj = pobj;return 0;
}

三、继承中的作用域

隐藏规则

  1. 在继承体系中基类和派生类都有独立的作用域。

  2. 派生类和基类中有同名成员,基类同名成员会被屏蔽,不能直接访问,这种情况叫隐藏。(在派生类成员函数中,可以使用 基类::基类成员 显示访问)

  3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。

  4. 注意在实际中在继承体系里面不使用多态最好不要定义同名的成员

#include <iostream>
using namespace std;// Student 的 _num 和 Person 的 _num 构成隐藏关系,
// 可以看出这样代码虽然能跑,但是⾮常容易混淆
class Person
{
protected:string _name = "张三";	// 姓名int _num = 111;			// ⾝份证号
};class Student : public Person
{
public:void Print(){cout << " 姓名:" << _name << endl;cout << " 身份证号:" << Person::_num << endl;cout << " 学号:" << _num << endl;}protected:int _num = 999;			// 学号
};int main()
{Student s1;s1.Print();return 0;
}

四、派生类的默认成员函数

4个常见默认成员函数

6 个默认成员函数,在派生类中生成方式:

  1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认或无参的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。

  2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。

  3. 派生类的 operator= 必须要调用基类的 operator= 完成基类的复制。需要注意的是派生类的 operator= 隐藏了基类的 operator=,所以显示调用基类的 operator=,需要指定基类作用域。

  4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。

  5. 派生类对象初始化先调用基类构造再调用派生类构造。

  6. 派生类对象析构清理先调用派生类析构再调用基类的析构。

  7. 在多态中一些场景析构函数需要构成重写,重写的条件之一是函数名相同。那么编译器会对析构函数名进行特殊处理,处理成 destructor(),所以基类析构函数不加 virtual 的情况下,派生类析构函数和基类析构函数构成隐藏关系。

#include <iostream>
using namespace std;class Person
{
public:Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person& p){cout << "Person operator=(const Person& p)" << endl;if (this != &p){_name = p._name;}return *this;}~Person(){cout << "~Person()" << endl;}protected:string _name;		// 姓名
};class Student : public Person
{
public:Student(const char* name, int num): Person(name), _num(num){cout << "Student()" << endl;}Student(const Student& s): Person(s), _num(s._num){cout << "Student(const Student& s)" << endl;}Student& operator = (const Student& s){cout << "Student& operator= (const Student& s)" << endl;if (this != &s){// 构成隐藏,所以需要显⽰调⽤Person::operator=(s);_num = s._num;}return *this;}~Student(){cout << "~Student()" << endl;}protected:int _num;			//学号
};int main()
{Student s1("jack", 18);Student s2(s1);Student s3("rose", 17);s1 = s3;return 0;
}

实现一个不能被继承的类

方法1:基类的构造函数私有,派生类的构成必须调用基类的构造函数,但是基类的构成函数私有化以后,派生类看不见就不能调用,那么派生类就无法实例化出对象。

方法2:C++11 新增一个 final 关键字,final 修饰基类,派生类就不能继承了。

#include <iostream>
using namespace std;// C++11的⽅法
class Base final	// 限制继承
{
public:void func5() { cout << "Base::func5" << endl; }protected:int _a = 1;private://C++98的⽅法//Base()//{//	//...//}
};class Derive :public Base
{void func4() { cout << "Derive::func4" << endl; }protected:int _b = 2;
};int main()
{Base b;Derive d;return 0;
}

五、继承与友元

友元关系不能继承,也就是说基类友元不能访问派生类 私有保护 成员 。

#include <iostream>
using namespace std;class Student;class Person
{friend void Display(const Person& p, const Student& s);protected:string _name = "张三";		// 姓名
};class Student : public Person
{friend void Display(const Person& p, const Student& s);	// 加上友元protected:int _stuNum = 18;		// 学号
};void Display(const Person& p, const Student& s)
{cout << p._name << endl;cout << s._stuNum << endl;
}int main()
{Person p;Student s;// 编译报错 Student::_stuNum ⽆法访问, 因为是 protected 成员// Display 也变成 Student 的友元即可解决Display(p, s);return 0;
}

六、继承与静态成员

基类定义了 static 静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个派生类,都只有一个 static 成员实例。

#include <iostream>
using namespace std;class Person
{
public:string _name;static int _count;
};int Person::_count = 0;class Student : public Person
{
protected:int _stuNum;
};int main()
{Person p;Student s;// 这⾥的运⾏结果可以看到⾮静态成员 _name 的地址是不⼀样的// 说明派⽣类继承下来了,⽗派⽣类对象各有⼀份cout << &p._name << endl;cout << &s._name << endl;// 这⾥的运⾏结果可以看到静态成员 _count 的地址是⼀样的// 说明派⽣类和基类共⽤同⼀份静态成员cout << &p._count << endl;cout << &s._count << endl;// 公有的情况下,⽗派⽣类指定类域都可以访问静态成员cout << Person::_count << endl;cout << Student::_count << endl;return 0;
}

七、多继承及其菱形继承问题

继承模型

单继承:一个派生类只有一个直接基类时称这个继承关系为单继承。

多继承:一个派生类有两个或以上直接基类时称这个继承关系为多继承,多继承对象在内存中的模型是,先继承的基类在前面,后面继承的基类在后面,派生类成员在放到最后面。
在这里插入图片描述

菱形继承:菱形继承是多继承的一种特殊情况。菱形继承的问题,从下面的对象成员模型构造,可以看出菱形继承有 数据冗余二义性 的问题,在 Assistant 的对象中 Person 成员会有两份。支持多继承就一定会有菱形继承,像 Java 就直接不支持多继承,规避掉了这里的问题。

在这里插入图片描述

#include <iostream>
using namespace std;class Person
{
public:string _name;			// 姓名
};class Student : public Person
{
protected:int _num;				// 学号
};class Teacher : public Person
{
protected:int _id;				// 职⼯编号
};class Assistant : public Student, public Teacher
{
protected:string _majorCourse;	// 主修课程
};int main()
{// 编译报错,因为对 _name 的访问不明确Assistant a;//a._name = "peter";// 需要显⽰指定访问哪个基类的成员可以解决⼆义性问题,// 但是数据冗余问题⽆法解决a.Student::_name = "xxx";a.Teacher::_name = "yyy";return 0;
}

虚继承

有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,如果 Assistant 多继承产生菱形继承,在一个基类被多个派生类继承时派生类加上 virtual 关键字就行,但底层实现就很复杂,性能也会有一些损失,所以最好不要设计出菱形继承。多继承可以认为是 C++ 的缺陷之一。

在这里插入图片描述

#include <iostream>
using namespace std;class Person
{
public:string _name;			// 姓名//int _tel;//int _age;//string _gender;//string _address;// ...
};// 使⽤虚继承 Person 类
class Student : virtual public Person
{
protected:int _num;				// 学号
};// 使⽤虚继承 Person 类
class Teacher : virtual public Person
{
protected:int _id;				// 职⼯编号
};// 教授助理
class Assistant : public Student, public Teacher
{
protected:string _majorCourse;	// 主修课程
};int main()
{// 使⽤虚继承,可以解决数据冗余和⼆义性Assistant a;a._name = "peter";return 0;
}

可以设计出多继承,但是不建议设计出菱形继承,因为菱形虚拟继承以后,无论是使用还是底层都会复杂很多,维护与使用也很麻烦。

#include <iostream>
using namespace std;class Person
{
public:Person(const char* name):_name(name){;}string _name;			// 姓名
};class Student : virtual public Person
{
public:Student(const char* name, int num):Person(name), _num(num){;}protected:int _num;				// 学号
};class Teacher : virtual public Person
{
public:Teacher(const char* name, int id):Person(name), _id(id){;}protected:int _id;				// 职⼯编号
};// 不要轻易使用菱形继承
class Assistant : public Student, public Teacher
{
public:Assistant(const char* name1, const char* name2, const char* name3):Person(name3), Student(name1, 1), Teacher(name2, 2){;}protected:string _majorCourse;	// 主修课程
};int main()
{// 思考⼀下这⾥ a 对象中 _name 是 "张三", "李四", "王五" 中的哪⼀个?Assistant a("张三", "李四", "王五");return 0;
}

多继承中指针偏移问题

指针偏移距离是根据类的大小,而类的大小同样遵循内存对齐规则,请参考:(学习总结6)C语言结构体的内存对齐和位段实现

#include <iostream>
using namespace std;class Base1 
{ 
public: int _b1; 
};class Base2 
{ 
public: int _b2; 
};class Derive : public Base1, public Base2 
{ 
public: char _ch;		int _d; 
};int main()
{Derive d;Base1* p1 = &d;Base2* p2 = &d;Derive* p3 = &d;cout << ((int)p1 - (int)(p1 - 1)) << endl;cout << ((int)p2 - (int)(p2 - 1)) << endl;cout << ((int)p3 - (int)(p3 - 1)) << endl;return 0;
}

八、继承和组合

继承是一种 is - a 的关系。也就是说每个派生类对象都是一个基类对象。

组合是一种 has - a 的关系。假设 B 组合了 A,每个 B 对象中都有一个 A 对象。

继承允许根据基类的实现来定义派生类的实现。这种通过生成派生类的复用通常被称为白箱复用(white-box reuse)。术语 “ 白箱 ” 是相对可视性而言:在继承方式中,基类的内部细节对派生类可见 。继承一定程度破坏了基类的封装,基类的改变,对派生类有很大的影响。派生类和基类间的依赖关系很强,耦合度高。

对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复用(black-box reuse),因为对象的内部细节是不可见的。对象只以 “ 黑箱 ” 的形式出现。 组合类之间没有很强的依赖关系,耦合度低。优先使用组合有助于保持每个类的封装性

优先使用组合,组合的耦合度低,代码维护性好。当然,重复较高的类之间关系就适合继承(is - a),另外要实现多态,也必须要继承。类之间的关系既适合用继承(is - a)也适用组合(has - a),就用组合

#include <iostream>
using namespace std;// Tire(轮胎) 和 Car(⻋) 更符合 has - a 的关系
class Tire 
{
protected:string _brand = "Michelin"; // 品牌size_t _size = 17;			// 尺⼨
};class Car 
{
protected:string _colour = "白色";		// 颜⾊string _num = "XXXXXXX";	// ⻋牌号Tire _t1;					// 轮胎Tire _t2;					// 轮胎Tire _t3;					// 轮胎Tire _t4;					// 轮胎
};// Car 和 BMW / Benz 更符合 is - a 的关系
class BMW : public Car
{
public:void Drive() { cout << "好开 - 操控" << endl; }
};class Benz : public Car 
{
public:void Drive() { cout << "好坐 - 舒适" << endl; }
};template<class T>
class vector
{};// Stack和vector的关系,既符合 is - a,也符合 has - a
template<class T>
class Stack1 : public vector<T>
{};template<class T>
class Stack2
{
public:vector<T> _v;
};int main()
{return 0;
}

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

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

相关文章

HTML 揭秘:HTML 编码快速入门

HTML 揭秘&#xff1a;HTML 编码快速入门 一 . 前端知识介绍二 . HTML 介绍三 . HTML 快速入门四 . HTML 编辑器 - VSCode4.1 插件安装4.2 修改主题配色4.3 修改快捷键4.4 设置自动保存4.5 创建 HTML 文件4.5 书写 HTML 代码4.6 常见快捷键 五 . 基础标签5.1 字体标签5.1.1 col…

物品识别——基于python语言

目录 1.物品识别 2.模型介绍 3.文件框架 4.代码示例 4.1 camera.py 4.2 interaction.py 4.3 object_detection.py 4.4 main.py 4.5 运行结果 5.总结 1.物品识别 该项目使用Python&#xff0c;OpenCV进行图像捕捉&#xff0c;进行物品识别。我们将使用YOLO&#xff08…

大数据处理技术:HBase的安装与基本操作

目录 1 实验名称 2 实验目的 3 实验内容 4 实验原理 5 实验过程或源代码 5.1 Hbase数据库的安装 5.2 创建表 5.3 添加数据、删除数据、删除表 5.4 使用Java操作HBase 6 实验结果 6.1 Hbase数据库的安装 6.2 创建表 6.3 添加数据、删除数据、删除表 6.4 使用Java操…

【Elasticsearch系列七】索引 crud

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

数据结构(Day13)

一、学习内容 内存空间划分 1、一个进程启动后&#xff0c;计算机会给该进程分配4G的虚拟内存 2、其中0G-3G是用户空间【程序员写代码操作部分】【应用层】 3、3G-4G是内核空间【与底层驱动有关】 4、所有进程共享3G-4G的内核空间&#xff0c;每个进程独立拥有0G-3G的用户空间 …

[数据集][目标检测]烟叶病害检测数据集VOC+YOLO格式612张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;612 标注数量(xml文件个数)&#xff1a;612 标注数量(txt文件个数)&#xff1a;612 标注类别…

【鸿蒙】HarmonyOS NEXT星河入门到实战7-ArkTS语法进阶

目录 1、Class类 1.1 Class类 实例属性 1.2 Class类 构造函数 1.3 Class类 定义方法 1.4 静态属性 和 静态方法 1.5 继承 extends 和 super 关键字 1.6 instanceof 检测是否实例 1.7.修饰符(readonly、private、protected 、public) 1.7.1 readonly 1.7.2 Private …

汽车免拆诊断案例 | 沃尔沃V40 1.9TD断续工作

故障现象 一辆04款的沃尔沃V40 1.9 TD&#xff0c;发动机代码D4192T3&#xff0c;使用博世EDC15C发动机管理。客户说车子断续工作&#xff0c;怀疑是正时皮带出现问题。卸下上皮带盖&#xff0c;检查发现皮带仍然在原来的位置上并且没有出现松动。起动发动机&#xff0c;车辆能…

安卓玩机工具-----ADB与 FASTBOOT模式 图形化 多功能玩机刷机工具

工具说明 这款工具是英文版。易于使用的工具提供了用于运行 ADB 和 Fastboot 命令的图形用户界面。ADB 功能包括旁加载、安装和卸载应用程序、测试设备以及重新启动到不同的模式。可以使用 fastboot 命令进行设备管理;其中包括检查 Antirollback 和 active slots 等变…

YOLOv8 人体姿态估计动作识别关键点检测(代码+教程)

YOLOv8 人体姿态判断 项目介绍 YOLOv8 人体姿态判断 是一个基于最新YOLOv8模型的深度学习项目&#xff0c;旨在识别和分析人体姿态。该项目利用先进的计算机视觉技术和深度学习框架&#xff0c;通过摄像头捕捉实时图像或处理存储图像&#xff0c;识别人体的关键点&#xff0c…

在线查看 Android 系统源代码 AOSPXRef and AndroidXRef

在线查看 Android 系统源代码 AOSPXRef and AndroidXRef 1. AOSPXRef1.1. http://aospxref.com/android-14.0.0_r2/1.2. build/envsetup.sh 2. AndroidXRef2.1. http://androidxref.com/9.0.0_r3/2.2. build/envsetup.sh 3. HELLO AndroidReferences 1. AOSPXRef http://aospx…

加密与安全_优雅存储用户密码的最佳实践

文章目录 Pre概述最佳实践避免使用MD5、SHA1等快速哈希算法加盐哈希 &#xff08;不推荐&#xff09;使用BCrypt、Argon2等慢哈希算法 (推荐)BCrypt Code1. 自动生成和嵌入盐2. 哈希结果的格式3. 代价因子 BCrypt特点 防止暴力破解1. 登录失败锁定2. 双因素认证&#xff08;2FA…

Golang | Leetcode Golang题解之第409题最长回文串

题目&#xff1a; 题解&#xff1a; func longestPalindrome(s string) int {mp : map[byte]int{}for i : 0; i < len(s); i {mp[s[i]]}res : 0for _, v : range mp {if v&1 1 {res v - 1} else {res v}}if res<len(s) {res}return res }

Python酷库之旅-第三方库Pandas(117)

目录 一、用法精讲 516、pandas.DataFrame.add_suffix方法 516-1、语法 516-2、参数 516-3、功能 516-4、返回值 516-5、说明 516-6、用法 516-6-1、数据准备 516-6-2、代码示例 516-6-3、结果输出 517、pandas.DataFrame.align方法 517-1、语法 517-2、参数 51…

Go语言基本语法

Go语言&#xff08;通常称为Golang&#xff09;是由Google开发的一种静态类型、编译型语言&#xff0c;它旨在简化系统编程、网络编程和并发编程的复杂性。 Go语言以其简洁、高效和易于理解的语法而受到开发者的喜爱。 Go语言的一些基本语法元素&#xff1a; 1. 包&#xff…

protobuf中c、c++、python使用

文章目录 protobuf实例&#xff1a;例题1&#xff1a;[CISCN 2023 初赛]StrangeTalkBot分析&#xff1a;思路&#xff1a;利用&#xff1a; 例题2&#xff1a;[CISCN 2024]protoverflow分析&#xff1a; protobuf Protocol Buffers&#xff0c;是Google公司开发的一种数据描述语…

数学学习记录

9月14日 1.映射&#xff1a; 2.函数: 9月15日 3.反函数&#xff1a; 4.收敛数列的性质 5.反三角函数&#xff1a; 9月16日 6.函数的极限&#xff1a; 7.无穷小和无穷大 极限运算法则&#xff1a;

远程Linux网络连接( Linux 网络操作系统 04)

接下来我们准备开始进入Linux操作系统的第二个模块的学习&#xff0c;不过在学习之前我们需要对如下进行简单的配置&#xff0c;通过外接辅助软件MobaXterm来进行虚拟操作系统的访问。接下来的课程我们会一直在MobaXterm中进行命令和相关知识的学习。 一、准备阶段 1.1 软件 …

学习笔记JVM篇(三)

一、垃圾回收机制 垃圾回收&#xff08;Garbage Collection&#xff09;机制&#xff0c;是自动回收无用对象从而释放内存的一种机制。Java之所以相对简单&#xff0c;很大程度是归功于垃圾回收机制。&#xff08;例如C语言申请内存后要手动的释放&#xff09; 优点&#xff…

数据清洗-缺失值填充-K-NN算法(K-Nearest Neighbors, K-NN算法)

目录 一、安装所需的python包二、采用K-NN算法进行缺失值填充2.1可直接运行代码2.2以某个缺失值数据进行实战2.2.1代码运行过程截屏&#xff1a;2.2.2填充后的数据截屏&#xff1a; 三、K 近邻算法 (K-Nearest Neighbors, KNN) 介绍3.1 K 近邻算法定义3.2 K 近邻算法的基本思想…