C++面向对象设计:深入理解多态与抽象类实现技巧
面向对象的多态
- 一、概念
- 二、实现
- 1. 静态多态
- 1.1 函数重载
- 1.2 运算符重载
- 2. 动态多态
- 2.1 虚函数
- 2.2 纯虚函数
- 三、虚函数
- 1. 定义
- 2. 实现
- 3. 注意
- 四、纯虚函数
- 1. 定义
- 2. 作用
- 五、虚析构函数
- 1. 定义
- 2. 作用
- 六、 抽象类
- 七、实现多态的注意事项
- 1. 基类虚函数必须使用 virtual 关键字声明
- 2. 子类重写基类的虚函数时必须保持函数签名的一致性
- 3. 在析构函数中使用 virtual 关键字声明
- 4. 在使用虚继承时,需要注意继承的正确性
- 5. 在使用抽象类时,需要让子类去实现纯虚函数
- 八、 小结
一、概念
在面向对象编程中多态(Polymorphism)是一种非常重要的概念。
可以被定义为“同一种类型的变量,在不同情况下表现出不同的行为”。
多态性是实现灵活的编程方式的一种方式它有以下好处:
- 增强程序的可扩展性:由于多态性允许开发人员在运行时选择使用哪个子类对象来调用函数,因此可以更轻松地在需要时添加新的子类。
- 提高程序的可维护性:程序的不同部分可以互相独立地编写和维护,而不需要知道具体的实现细节。
- 代码的可读性得到改善:由于多态性是在整个程序中通过使用相同的基类来调用函数来实现的,因此程序的结构更加清晰简单。
在C++ 中可以使用虚函数实现多态性。
下面是一个简单的示例:
#include <iostream>
using namespace std;// 定义形状基类
class Shape {public:// 定义一个纯虚函数,没有具体的实现virtual int area() = 0;
};// 定义矩形类
class Rectangle : public Shape {public:// 实现 Shape 类中的纯虚函数int area () { cout << "Rectangle 类的面积是:" <<endl;return (width * height); }private:int width;int height;
};// 定义三角形类
class Triangle : public Shape{public:// 实现 Shape 类中的纯虚函数int area () { cout << "Triangle 类的面积是:" <<endl;return (width * height / 2); }private:int width;int height;
};// 程序的主函数
int main( ) {Shape *shape;Rectangle rec;Triangle tri;// 存储矩形的地址shape = &rec;// 调用矩形的 area 函数shape->area();// 存储三角形的地址shape = &tri;// 调用三角形的 area 函数shape->area();return 0;
}
在上面的示例代码中定义了一个基类 Shape,其中包含一个纯虚函数 area它没有具体的实现。定义了两个子类 Rectangle 和 Triangle并在这两个子类中重新定义了 area 函数,并给出了具体的实现。最后在主函数中我们声明了一个指向 Shape 类对象的指针,然后将它分别指向 Rectangle 和 Triangle 对象,并通过指针调用了各自的 area 函数,这就实现了多态。
二、实现
多态是面向对象编程的一个重要概念,在C++中多态可以通过静态多态和动态多态两种方式来实现。
1. 静态多态
静态多态是在编译期间就确定的多态性,主要有两种形式:函数重载和运算符重载。
1.1 函数重载
函数重载是指在同一作用域内定义多个同名函数,但它们的参数列表不同,从而让这些函数可以根据传入的参数类型和数量进行区分。
下面是一个函数重载的例子,定义了两个同名的函数 add()
,但是一个参数是整型,另一个参数是浮点型:
#include <iostream>
using namespace std;int add(int a, int b) {return a + b;
}double add(double a, double b) {return a + b;
}int main() {cout << add(1, 2) << endl; // 输出 3cout << add(1.2, 2.3) << endl; // 输出 3.5return 0;
}
1.2 运算符重载
运算符重载是指在类中重载运算符,使它们能够作用于该类的对象。在重载运算符时,需要使用关键字 operator
来声明。
下面是一个重载加号运算符的例子,定义了一个 Box
类并在其中重载了加号运算符 +
:
#include <iostream>
using namespace std;class Box {public:double getVolume(void) {return length * breadth * height;}void setLength(double len) {length = len;}void setBreadth(double bre) {breadth = bre;}void setHeight(double hei) {height = hei;}// 重载加号运算符Box operator+(const Box& b) {Box box;box.length = this->length + b.length;box.breadth = this->breadth + b.breadth;box.height = this->height + b.height;return box;}private:double length; // 长double breadth; // 宽double height; // 高
};int main() {Box Box1; // 声明 Box1,类型为 BoxBox Box2; // 声明 Box2,类型为 BoxBox Box3; // 声明 Box3,类型为 Boxdouble volume = 0.0; // 把体积存储在该变量中// Box1 的详述Box1.setLength(6.0); Box1.setBreadth(7.0); Box1.setHeight(5.0);// Box2 的详述Box2.setLength(12.0); Box2.setBreadth(13.0); Box2.setHeight(10.0);// 计算 Box1 的体积volume = Box1.getVolume();cout << "Box1 的体积:" << volume << endl;// 计算 Box2 的体积volume = Box2.getVolume();cout << "Box2 的体积:" << volume << endl;// 把两个对象相加,得到 Box3Box3 = Box1 + Box2;// 计算 Box3 的体积volume = Box3.getVolume();cout << "Box3 的体积:" << volume << endl;return 0;
}
2. 动态多态
动态多态是在运行期间通过虚函数实现的多态性,让同名的虚函数在不同的子类中有不同的实现。动态多态需要使用关键字 virtual
来声明虚函数。
2.1 虚函数
虚函数是在基类中定义的一个函数,子类可以通过重写这个函数实现多态。当基类的指针或引用指向某个子类的对象时,调用这个对象的同名虚函数,实际上是调用子类中的虚函数。
下面是一个虚函数的例子,先定义了一个 Shape 基类并在其中声明了一个虚函数 area,然后分别定义了 Rectangle 和 Circle 两个子类,并在这两个子类中重新定义了 area 函数:
#include <iostream>
using namespace std;class Shape {public:// 声明虚函数 areavirtual int area() {cout << "Shape 的 area 函数" << endl;}
};// 矩形子类
class Rectangle: public Shape {public:int area() { cout << "Rectangle 的 area 函数" << endl;return (width * height); }private:int width;int height;
};// 圆形子类
class Circle: public Shape {public:int area() { cout << "Circle 的 area 函数" << endl;return (radius * radius * 3.1415926); }private:int radius;
};int main() {Shape *shape; // 声明一个指向基类对象的指针Rectangle rec; // 声明矩形对象Circle cir; // 声明圆形对象shape = &rec; // 给指针赋值,指向矩形对象shape->area(); // 调用矩形类的 area 函数shape = ○ // 给指针赋值,指向圆形对象shape->area(); // 调用圆形类的 area 函数return 0;
}
2.2 纯虚函数
纯虚函数是指在基类中定义一个虚函数,但不为它提供具体实现,而要求子类必须重写这个函数。在定义纯虚函数时需要在函数声明中加上 =0
。
下面是一个纯虚函数的例子定义了一个 Shape 基类,并在其中定义了一个纯虚函数 print。
#include <iostream>
using namespace std;class Shape {public:// 声明纯虚函数 printvirtual void print() = 0;
};// Circle 子类,继承 Shape 基类
class Circle: public Shape {public:// 重写Shape类中的 print 函数void print() {cout << "这是一个圆形" << endl;}
};// Rectangle 子类,继承 Shape 基类
class Rectangle: public Shape {public:// 重写Shape类中的 print 函数void print() {cout << "这是一个矩形" << endl;}
};int main() {Circle cir; // 声明圆形对象Rectangle rec; // 声明矩形对象cir.print(); // 调用 Circle 类的 print 函数rec.print(); // 调用 Rectangle 类的 print 函数return 0;
}
以上就是C++中实现多态的两种方式,分别是静态多态和动态多态。无论是哪种方式都可以让我们的代码更加灵活易于维护和扩展提高开发效率。
三、虚函数
接上文继续来看虚函数,它允许在基类中定义一个函数而在派生类中对该函数进行重写。下面介绍虚函数的定义、实现方式和需要注意的事项。
1. 定义
虚函数是在基类中通过 virtual
关键字声明的函数,它可以被子类重写,实现不同行为。虚函数的作用是允许派生类根据自身的需要对基类中的函数进行扩展,以实现多态性。
class BaseClass {
public:virtual void virtual_fun() {std::cout << "BaseClass 的虚函数" << std::endl;}
};class DerivedClass : public BaseClass {
public:void virtual_fun() {std::cout << "DerivedClass 的虚函数" << std::endl;}
};
在代码中先声明了一个基类 BaseClass
,其中有一个名为 virtual_fun
的虚函数。定义了一个派生类 DerivedClass
,也有一个同名的虚函数 virtual_fun
,但实现方式不同。这样就可以直接在派生类中对基类的虚函数进行重写,随时根据需要进行调用。
2. 实现
使用虚函数时,可以通过基类的指针或者引用调用实际派生类中的函数版本实现不同的行为。基类指针或引用调用虚函数时,会根据实际对象类型决定调用的函数版本,这被称为动态绑定(dynamic binding)。使用动态绑定可以实现 C++ 中的多态性。
BaseClass *base_pointer;
DerivedClass derived_object;
base_pointer = &derived_object;
base_pointer->virtual_fun();
在这段代码中定义了一个基类指针 base_pointer
,指向一个派生类对象 derived_object
。接着通过指针调用了派生类中的虚函数 virtual_fun
。由于 base_pointer
实际指向的是派生类对象,在运行时会根据实际对象类型执行派生类中的函数版本,输出 “DerivedClass 的虚函数”。
3. 注意
子类重写虚函数时,需要保证函数签名一致性。这包括参数列表、返回类型和函数名必须与基类中的虚函数一致。如果派生类中的函数与基类中的虚函数签名不一致,将无法实现动态绑定。
此外还要注意虚函数的效率问题。虚函数的调用需要在运行时动态确认函数版本,因此它的效率可能会较低。如果需要进行高性能的程序开发应该尽可能减少虚函数的使用。
四、纯虚函数
继续来看纯虚函数,它是基类中通过virtual
和= 0
关键字声明的函数没有具体的实现。必须由子类实现之后才能使用。
1. 定义
定义纯虚函数需要在基类中使用virtual
和= 0
关键字,如下所示:
class BaseClass {
public:virtual void pure_virtual_func() = 0; // 声明纯虚函数
};class DerivedClass : public BaseClass {
public:void pure_virtual_func() override {// 实现基类纯虚函数}
};
在代码中在 BaseClass
中声明了一个纯虚函数 pure_virtual_func
,并且在 DerivedClass
中重写了该函数。
2. 作用
纯虚函数广泛应用于接口编程。它定义了一组必须要实现的接口由不同的派生类来实现具体的行为逻辑,以达到最大的代码重用。
同时纯虚函数也可作为基类中的抽象方法,在基类中被调用,以保证派生类在调用的时候已经实现了该纯虚函数。
class BaseClass {
public:virtual void pure_virtual_func() = 0; // 声明纯虚函数void another_func() {// 使用纯虚函数pure_virtual_func();}
};class DerivedClass : public BaseClass {
public:void pure_virtual_func() override {// 实现基类纯虚函数}
};
在代码中在 BaseClass
中声明了一个普通函数 another_func
,其中调用了纯虚函数 pure_virtual_func
。在派生类中实现 pure_virtual_func
后,another_func
就可以被正常的调用。
五、虚析构函数
虚析构函数是通过 virtual
关键字在基类中声明的析构函数。虚析构函数的作用是在释放派生类时,先调用派生类的析构函数,再调用基类的析构函数,保证程序的正常运行。
1. 定义
可以通过在基类的析构函数前加上 virtual
关键字来定义虚析构函数,如下所示:
class BaseClass {
public:virtual ~BaseClass() {// 基类析构函数};
};class DerivedClass : public BaseClass {
public:~DerivedClass() override {// 派生类析构函数};
};
在代码中通过 virtual
关键字在基类中定义了虚析构函数 ~BaseClass()
。在派生类 DerivedClass
中,我们重写了析构函数 ~DerivedClass()
,保证在释放 DerivedClass
对象时,先调用派生类的析构函数,再调用基类的析构函数。
2. 作用
虚析构函数的作用是在释放派生类时,先调用派生类的析构函数再调用基类的析构函数避免程序崩溃。
如果不使用虚析构函数,当我们在基类中没有定义虚析构函数再释放派生类对象时,只会调用基类的析构函数,不会调用派生类的析构函数,这可能会导致一些意外错误的发生。
代码示例:
#include <iostream>class BaseClass {
public:~BaseClass() {std::cout << "In BaseClass Destructor" << std::endl;}
};class DerivedClass : public BaseClass {
public:~DerivedClass() {std::cout << "In DerivedClass Destructor" << std::endl;}
};int main() {BaseClass *ptr = new DerivedClass();delete ptr;return 0;
}
在代码中声明了一个指向 DerivedClass
对象的基类指针 ptr
,在释放 ptr
所指向的对象时,只会调用基类 BaseClass
的析构函数,而不会调用派生类 DerivedClass
的析构函数。这可能会导致一些内存资源泄漏和程序错误的发生。所以使用虚析构函数也是保证程序正常运行的一种良好的编程习惯。
六、 抽象类
C++抽象类是一种特殊的类,拥有至少一个纯虚函数的类。抽象类不能被实例化只能用作接口,并让子类去实现。接下来将更加详细地讨论抽象类。
抽象类是一个包含了至少一个纯虚函数的类。纯虚函数是一个在类中定义但没有实现的虚函数,仅用于设定接口规格。换句话说,抽象类是一个不能被实例化的基类,只有当它的派生类实现了所规定的接口时,程序才能正常运行。
以下是一个简单的抽象类示例代码:
#include <iostream>// 抽象类
class Shape {
public:// 纯虚函数virtual double getArea() const = 0;// 普通函数void printName() {std::cout << "Shape" << std::endl;}
};// 派生类
class Rectangle : public Shape {
public:// 构造函数Rectangle(double width, double height) : m_width(width), m_height(height) {}// 重写基类中的纯虚函数double getArea() const override {return m_width * m_height;}private:double m_width;double m_height;
};// 主函数
int main() {// 使用指向基类对象的指针Shape *shape = new Rectangle(3, 4);// 调用基类的普通函数shape->printName();// 调用派生类中重写的纯虚函数std::cout << "The area of the rectangle is: " << shape->getArea() << std::endl;// 释放动态分配的内存delete shape;return 0;
}
在代码中定义了一个抽象基类 Shape
,包含一个纯虚函数 getArea()
和一个普通函数 printName()
定义一个派生类 Rectangle
,重写了基类中的纯虚函数并通过构造函数初始化了 m_width
和 m_height
在 main()
函数中,使用基类指针创建了一个派生类对象,并调用了基类的普通函数和派生类的重写函数实现了多态的效果。最终释放了动态分配的内存。
七、实现多态的注意事项
在C++ 中实现多态很常见,这也是 OOP(面向对象编程)的核心之一。但是在实现多态时往往需要我们注意一些事项。接下来,我们将详细介绍这些事项
1. 基类虚函数必须使用 virtual 关键字声明
想要实现多态必须使用虚函数。同时在定义基类中的虚函数时必须使用 virtual 关键字声明
class Shape {
public:virtual double getArea() const {return 0.0;}
};
2. 子类重写基类的虚函数时必须保持函数签名的一致性
当子类需要重写基类的虚函数时,必须保持函数签名的一致性。也就是说参数列表和返回类型必须与基类中的虚函数一致。
例如有一个派生类 Rectangle
,通过重写基类中的虚函数 getArea()
来计算矩形的面积
class Rectangle : public Shape {
public:double getArea() const override {return m_width * m_height;}private:double m_width;double m_height;
};
需要注意的是使用了 override
关键字来显式地告知编译器我们正在重写基类中的虚函数
3. 在析构函数中使用 virtual 关键字声明
在使用多态时如果用基类指针指向派生类对象,并在析构时忘记使用 virtual 关键字,则可能导致派生类对象的内存得不到释放,最终导致内存泄漏和崩溃等问题
class Shape {
public:virtual double getArea() const {return 0.0;}virtual ~Shape() {}
};
需要注意在虚析构函数中添加了 virtual 关键字。这样,在我们释放一个使用基类指针指向的对象时,将会自动调用派生类的析构函数,即使它是在基类中定义的
4. 在使用虚继承时,需要注意继承的正确性
虚继承(virtual inheritance)是一种用于处理多重继承的机制,可以避免引入二义性。在使用虚继承时,需要注意内存对齐和字节对齐等问题,以保证继承的正确性
class Shape {
public:virtual double getArea() const = 0;
};class Solid : virtual public Shape {
public:virtual double getVolume() const = 0;
};
需要注意的是使用了 virtual 关键字来声明虚继承。这里Solid
类继承了 Shape
类,同时也成为了一个抽象类
5. 在使用抽象类时,需要让子类去实现纯虚函数
抽象类是指具有纯虚函数的类,不能被实例化。如果一个派生类没有实现从基类继承而来的纯虚函数,则该派生类也将成为一个抽象类。
class Shape {
public:virtual double getArea() const = 0;
};
这样我们就将 Shape
类变成了一个抽象类。从这个抽象类中派生出来的类必须实现 getArea()
函数,否则它们也将成为抽象类。
八、 小结
继承的概念讲到这里,之后在项目中的实际体现还需要大家在实际项目中不断总结积累,加油!
相关文章:

C++面向对象设计:深入理解多态与抽象类实现技巧
面向对象的多态 一、概念二、实现1. 静态多态1.1 函数重载1.2 运算符重载 2. 动态多态2.1 虚函数2.2 纯虚函数 三、虚函数1. 定义2. 实现3. 注意 四、纯虚函数1. 定义2. 作用 五、虚析构函数1. 定义2. 作用 六、 抽象类七、实现多态的注意事项1. 基类虚函数必须使用 virtual 关…...

长三角生物医药产业加速跑,飞桨螺旋桨为创新药企、医药技术伙伴装上AI大模型引擎...
生物医药是国家“十四五”规划中明确的战略性新兴产业之一。长三角地区是中国生物医药产业的排头兵,也是《“十四五”生物经济发展规划》的“生物经济先导区”之一。据《上海市生物医药产业投资指南》显示,2022 年上海市生物医药产业在 I 类国产创新药数…...

orin Ubuntu 20.04 配置 Realsense-ROS
librealsense安装 sudo apt-get install libudev-dev pkg-config libgtk-3-dev sudo apt-get install libusb-1.0-0-dev pkg-config sudo apt-get install libglfw3-dev sudo apt-get install libssl-dev sudo apt-get install ros-noetic-ddynamic-reconfigure二进制安装libr…...

MyBatis基础知识点总结
MyBatis了解 MyBatis 是什么? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架 MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集 MyBatis 可以使用简单的XML或注解用于配置和原始映射,将接口和Java的 POJO&#x…...

校园企业车辆维修报修管理系统设计与开发
本研究课题重点主要包括了下面几大模块:在本基于.net平台的车辆系统中分为管理员和用户2个模块,主要功能包括管理员信息管理,车辆信息管理,驾驶员信息管理,事故信息管理,维修信息管理,维修点管理…...

【企业信息化】第1集 免费开源ERP: Odoo 16 CRM客户关系管理系统
文章目录 前言一、概览二、使用功能1.加快销售速度2.销售线索3.机会4.客户5.高效沟通6.报告7.集成 三、总结 前言 世界排名第一的免费开源ERP: Odoo 16 CRM客户关系管理系统。真正以客户为中心的CRM。 一、概览 获得准确预测 使用可操作数据,以做出更好的决定。 获…...

Flink创建Hudi的Sink动态表
工厂类 HoodieTableFactory 提供的创建动态表接口 createDynamicTableSource 和 createDynamicTableSink,对应的源码文件为:https://github.com/apache/hudi/blob/master/hudi-flink-datasource/hudi-flink/src/main/java/org/apache/hudi/table/HoodieT…...

人脸识别技术的安全性及其应用探讨
随着科技的不断发展,人脸识别技术已经成为了一个热门话题。人脸识别系统的出现,给人们的生活带来了极大的便利,同时也为一些犯罪分子提供了方便。因此,人脸识别技术的安全性和可靠性一直备受关注。 一、人脸识别技术的原理 人脸识…...

老域名查询工具- 在线域名批量查询工具
域名批量查询工具 域名批量查询工具是一种帮助用户快速查询多个域名信息的工具,通常能够自动扫描一组域名的WHOIS信息、DNS、IP地址、服务器等各种信息,并提供快速的结果反馈。 以下是域名批量查询工具主要的优点: 提高工作效率:…...

JimuReport - 积木报表(一款免费Web报表工具)
一款免费的数据可视化报表,含报表和大屏设计,像搭建积木一样在线设计报表!功能涵盖,数据报表、打印设计、图表报表、大屏设计等! Web 版报表设计器,类似于excel操作风格,通过拖拽完成报表设计。…...

01-数据操作+数据预处理
1.n维数组,也称为张量(tensor):tensor和ndarray没有本质区别。tensor是有数学上的严格定义,ndarray是计算机描述的;张量表示一个由数值组成的数组,这个数组可能有多个维度; 无论使用…...

macOS本地python环境/vscode/导入python包/设置python解释器
查看macbook本地是否有python环境 输入python或者python3,退出python环境使用exit(),别忘了括号 没有的话去官网安装https://www.python.org/ 2. 安装vscode 官网https://code.visualstudio.com/ 3. 安装插件 点击左边的“插件”按钮,安装…...

【转存】Go语言设计模式
导语| 设计模式是针对软件设计中常见问题的工具箱,其中的工具就是各种经过实践验证的解决方案。即使你从未遇到过这些问题,了解模式仍然非常有用,因为它能指导你如何使用面向对象的设计原则来解决各种问题,提高开发效率࿰…...

第十一章 升级与定制
第十一章 升级与定制 一、 RPM 包安装操作 RPM(Redhat Packet Manager)。 ①安装 rpm –i rpm 文件名 (注:⑴常见用法:-ivh 参数显示安装过程和 hash 符#; ⑵覆盖安装:使用- -force 选项。…...

代码随想录算法训练营第二十二天|235. 二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点
目录 235. 二叉搜索树的最近公共祖先 1、递归实现 2、迭代法实现 701.二叉搜索树中的插入操作(递归实现) 450.删除二叉搜索树中的节点(递归实现) 235. 二叉搜索树的最近公共祖先 相对于 二叉树的最近公共祖先 本题就简单一些了…...

hbase表出现RIT删除方案
1.删除zookeeper中对应表注册信息 cd /opt/cloudera/parcels/CDH/lib/zookeeper/bin ./zkCli.sh -server node2:2181 --node2为仿真节点,生产需改 deleteall /hbase/table/表名 2.删除hdfs对应表数据 hadoop dfs -rm -r /hbase/data/default/表名 3.删除hbase:met…...

SQL学习(3)
SELECT 语句用于从表中选取数据。 SELECT 列名称 FROM 表名称 SELECT * FROM 表名称关键词 DISTINCT 用于返回唯一不同的值 SELECT DISTINCT 列名称 FROM 表名称WHERE 子句用于规定选择的标准 如需有条件地从表中选取数据,可将 WHERE 子句添加到 SELECT 语句。 S…...

连接型CRM助力医疗企业把“成本中心”变成“利润中心”
在市场竞争日益加剧的情形下,企业获客成本大幅上涨,存量客户的维护和开发开始被重视,售后服务部门的职责在企业中发挥的价值越来越大。因为企业售后服务不仅能帮助客户解决问题的部门,还是客户与企业沟通的桥梁,将客户…...

《Vue.js 设计与实现》—— 03 Vue.js 3 的设计思路
1. 声明式地描述 UI Vue.js 3 是一个声明式的 UI 框架,即用户在使用 Vue.js 3 开发页面时是声明式地描述 UI 的。 编写前端页面涉及的内容如下: DOM 元素:例如是 div 标签还是 a 标签属性:如 a 标签的 href 属性,再…...

2023年湖北省建设厅特种作业操作证报名条件是什么?
建筑施工特种作业人员是指在房屋建筑和市政工程施工活动中,从事可能对本人、他人及周围设备设施的安全造成重大危害作业的人员。建筑施工特种作业人员必须经建设主管部门考核合格,取得建筑施工特种作业人员操作资格证书(以下简称“资格证书”…...

Redis 进阶
🥲 🥸 🤌 🫀 🫁 🥷 🐻❄️🦤 🪶 🦭 🪲 🪳 🪰 🪱 🪴 🫐 🫒 🫑…...

伙伴匹配系统笔记---02
Java 8特性 1. stream / parallelStream 流失处理 2. Optional 可选类 一. 前端整合路由 1. 路由:vue 路由组件库地址:安装 | Vue Router (vuejs.org) 安装:yarn add vue-router@4 2. 整合路由: // 1. 定义路由组件. // 也可以从其他文件导入 const Home = { templ…...

Redis学习——单机版安装
目录 1.解压 2.安装gcc 3.执行make命令 4.复制redis的配置文件到默认安装目录下 5.修改redis.conf文件 6.启动redis服务与客户端 7.查看redis进行是否启动 8.关闭redis服务 9.redis性能测试 注意:安装redis前要安装jdk。 1.解压 [rootlxm148 install]# t…...

第三十一章 React中路由组件和一般组件
在React中,组件是应用程序的构建块。它们是可重用的,可以用于创建复杂的UI。React中有两种类型的组件:路由组件和一般组件。 一般组件 一般组件是React应用程序的基本构建块。它们是可重用的,可以用于创建复杂的UI。它们不知道U…...

怎么把pdf中的某一页分出来?
怎么把pdf中的某一页分出来?PDF格式的文档在日常生活中是非常常见的,相信大家都对其有所了解,并且经常使用。它的主要特点是不允许用户随意编辑其中的内容,当我们仅需要阅读时,PDF文档无疑是十分方便的,尤其…...

MongoDB 聚合操作Map-Reduce
这此之前已经对MongoDB中的一些聚合操作进行了详细的介绍,主要介绍了聚合方法和聚合管道;如果您想对聚合方法和聚合管道进行了解,可以参考: MongoDB 数据库操作汇总https://blog.csdn.net/m1729339749/article/details/130086022…...

shiro CVE-2016-4437 漏洞复现
shiro Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序漏洞原理 在Apache shiro的框架中,执行身份验证时提供了…...

Seqkit-2.2.0 移植指南(openEuler 20.03 LTS SP3)
1.软件介绍 seqkit是一种跨平台的、极快的,全面的fasta/q处理工具。seqkit为所有的主流操作系统提供了一种可执行的双元文件,包括Windows,Linux,MacOS X,并且不依赖于任何的配置或预先配置就可以直接使用。 关于seqk…...

Java版本企业电子招投标采购系统源码——功能模块功能描述+数字化采购管理 采购招投标
功能模块: 待办消息,招标公告,中标公告,信息发布 描述: 全过程数字化采购管理,打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力,为外部供…...

二十三种设计模式第五篇--原型模式
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建…...