C++初阶:类和对象(二)

大家好,我是小卡皮巴拉

文章目录

目录

一.运算符重载

1.1 基本概念

定义

参数规则

特性

选择原则

重载要点

二.类的默认成员函数

2.1 构造函数 

构造函数的特点

2.2 析构函数

析构函数的特点

2.3 拷贝构造函数

拷贝构造的特点

2.4 拷贝赋值运算符重载函数(operator=)

基本概念

避免浅拷贝问题

与拷贝构造函数的区别

2.5 取地址运算符重载 

基本概念

普通对象的取地址运算符重载

常量对象的取地址运算符重载

使用场景

注意事项

兄弟们共勉 !!! 


每篇前言

博客主页:小卡皮巴拉

咱的口号:🌹小比特,大梦想🌹

作者请求:由于博主水平有限,难免会有错误和不准之处,我也非常渴望知道这些错误,恳请大佬们批评斧正。

一.运算符重载

1.1 基本概念

在 C++ 里,当运算符用于类类型对象时,能通过运算符重载赋予其新的含义。这是因为 C++ 规定类类型对象使用运算符时,必须转换为调用对应的运算符重载函数,若没有合适的重载函数,编译就会报错。

定义

  • 函数命名运算符重载函数有着特殊的名字,由 operator 加上要定义的运算符组成。例如,要重载 + 运算符,函数名就是 operator+

  • 函数结构和普通函数一样,运算符重载函数有返回类型、参数列表和函数体。返回类型取决于运算符重载后的功能需求,参数列表与运算符作用的运算对象数量相关。

参数规则

  • 参数数量与运算符类型:运算符的类型决定了重载函数的参数数量。一元运算符(如 ++--! 等)有一个参数,二元运算符(如 +-*/ 等)有两个参数。对于二元运算符,左侧运算对象会传给第一个参数,右侧运算对象传给第二个参数。

  • 成员函数的参数特点如果运算符重载函数是类的成员函数,第一个运算对象会默认传给隐式的 this 指针,所以成员函数形式的运算符重载参数比运算对象少一个。例如,重载 + 运算符作为成员函数时,只需要一个参数来表示另一个操作数。

特性

  • 优先级和结合性:运算符重载后,其优先级和结合性与对应的内置类型运算符保持一致。这保证了重载运算符在表达式中的运算顺序符合预期,不会因为重载而改变基本的运算规则。

  • 不能创建新运算符:不能通过连接语法中不存在的符号来创建新的运算符,例如 operator@ 是不被允许的。

  • 不可重载的运算符:有 5 个运算符不能被重载,分别是 .*::sizeof?: 和 .。在学习和考试的选择题中,这是常见的考点。

  • 类类型参数要求:运算符重载函数至少要有一个类类型参数,不能通过运算符重载改变内置类型对象的含义。例如,不能定义 int operator+(int x, int y) 来改变 int 类型加法的行为。

选择原则

一个类需要重载哪些运算符,要考虑重载后是否有实际意义。例如,Date 类重载 operator- 可以计算两个日期之间的天数差,是有意义的;但重载 operator+ 可能没有明确的实际意义,就不需要进行重载。

重载要点

  • 前置和后置 ++ 运算符:重载 ++ 运算符时,存在前置 ++ 和后置 ++ 的区别。它们的运算符重载函数名都是 operator++,为了区分,C++ 规定后置 ++ 重载时增加一个 int 形参,以此和前置 ++ 构成函数重载。

二.类的默认成员函数

默认成员函数就是用户没有显式实现,编译器会自动生成的成员函数称为默认成员函数。

C++ 中的类有六个默认成员函数,分别是默认构造函数、拷贝构造函数、析构函数、拷贝赋值运算符重载函数、后面的C++11中还有移动构造函数和移动赋值运算符重载函数,重点是前四个,后面两个我们在这里仅作简单了解。

2.1 构造函数 

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象(我们常使用的局部对象是栈帧创建时,空间就开好了),而是对象实例化时初始化对象。

构造函数的本质是要替代我们以前Stack和Date类中写的Init函数的功能,构造函数自动调用的特点就完美的替代的了Init。

构造函数的特点

  1. 函数名与类名相同:构造函数名称和所在类名称一致。

  2. 无返回类型:不允许有返回类型,也不能用void

  3. 可重载:一个类中能定义多个参数列表不同的构造函数。

  4. 自动调用:创建对象时自动调用,完成对象初始化。

  5. 可使用初始化列表:比在构造函数体内赋值更高效。

  6. 编译器提供默认构造函数:类中未定义任何构造函数时,编译器自动提供默认无参构造函数;自定义构造函数后则不再提供。

  7. 用于动态内存分配:使用new运算符动态分配内存创建对象时,构造函数会被调用。

需要注意的是:

  • 若未定义构造函数,编译器生成的默认构造函数:对内置类型成员变量的初始化无明确要求,其是否初始化取决于编译器对自定义类型成员变量,则会调用其默认构造函数完成初始化
  • 无参构造函数、全缺省构造函数以及编译器默认生成的构造函数都属于默认构造函数,这三者有且只能存在一个,不能同时共存。无参和全缺省构造函数虽能构成重载,调用时却会产生歧义。需注意,很多人误以为只有编译器默认生成的才是默认构造函数,实际上,只要无需传入实参就能调用的构造函数,都可称为默认构造函数。

下面的示例代码中展示了构造函数的一些常见特点:

#include <iostream>class Rectangle {
private:double length;double width;public:// 1. 函数名与类名相同,无返回类型// 2. 无参构造函数Rectangle() {length = 0;width = 0;std::cout << "无参构造函数被调用" << std::endl;}// 3. 带参数的构造函数,体现构造函数重载Rectangle(double l, double w) : length(l), width(w) {std::cout << "带参数的构造函数被调用" << std::endl;}// 计算矩形面积double area() {return length * width;}
};int main() {// 4. 创建对象时自动调用无参构造函数Rectangle rect1;std::cout << "rect1的面积: " << rect1.area() << std::endl;// 5. 创建对象时自动调用带参数的构造函数Rectangle rect2(5, 3);std::cout << "rect2的面积: " << rect2.area() << std::endl;// 6. 动态内存分配时调用构造函数Rectangle* rect3 = new Rectangle(7, 4);std::cout << "rect3的面积: " << rect3->area() << std::endl;delete rect3;return 0;
}

2.2 析构函数

析构函数与构造函数功能相反,C++规定对象在销毁时会自动调用析构函数,完成对象中资源的清理释放工作

析构函数的特点

  1. 函数名与类名相同且前加波浪号~析构函数的名称由类名前加波浪号~构成,以此来和构造函数区分开。

  2. 无返回类型和参数:析构函数没有返回类型,也不能有参数,这就意味着析构函数不能被重载,一个类只能有一个析构函数。

  3. 自动调用:当对象的生命周期结束时,比如对象离开其作用域或者使用delete运算符释放动态分配的对象时,析构函数会自动被调用。

  4. 完成资源清理:析构函数主要用于释放对象在其生命周期内所占用的资源,像动态分配的内存、打开的文件、网络连接等。

需要注意的是:

与构造函数类似,若未显式定义析构函数,编译器自动生成的析构函数不会处理内置类型成员,而会调用自定义类型成员自身的析构函数。并且,即便我们显式编写析构函数,自定义类型成员的析构函数仍会被自动调用,即自定义类型成员的析构调用不受影响

对于析构函数的编写,若类无需申请资源,如 Date 类,可直接使用编译器生成的默认析构函数若默认析构函数已能满足资源清理需求,像 MyQueue 类,也不必显式定义。然而,一旦类中涉及资源申请,如 Stack 类,就必须自行编写析构函数,以防资源泄漏。

下面的示例代码中展示了析构函数的一些常见特点

#include <iostream>
#include <cstring>class MyString {
private:char* data;size_t length;public:// 构造函数MyString(const char* str = "") {length = strlen(str);data = new char[length + 1];strcpy(data, str);std::cout << "构造函数被调用,创建字符串: " << data << std::endl;}// 析构函数~MyString() {std::cout << "析构函数被调用,释放字符串: " << data << std::endl;delete[] data;}// 打印字符串void print() {std::cout << data << std::endl;}
};int main() {{// 创建对象,调用构造函数MyString str("Hello, World!");str.print();} // 对象离开作用域,调用析构函数// 动态分配对象MyString* strPtr = new MyString("Dynamic String");strPtr->print();// 释放动态分配的对象,调用析构函数delete strPtr;return 0;
}

2.3 拷贝构造函数

在 C++ 中,拷贝构造函数是一种特殊的构造函数,用于创建一个新对象,该对象是另一个同类型对象的副本

拷贝构造的特点

  1. 重载构造函数:拷贝构造函数是构造函数的一种重载形式。

  2. 参数要求:第一个参数必须是类类型对象的引用,使用传值方式会导致无穷递归调用而编译报错。可以有多个参数,但后续参数需有缺省值。

  3. 拷贝行为调用:C++ 规定自定义类型对象进行拷贝时必须调用拷贝构造函数,传值传参和传值返回都会触发调用。

  4. 默认生成规则:若未显式定义,编译器会自动生成拷贝构造函数。对内置类型成员进行浅拷贝(逐字节复制),对自定义类型成员调用其拷贝构造函数。

  5. 显式定义判断:若类成员全为内置类型且无资源管理,编译器自动生成的拷贝构造通常足够;若类中有指向资源的指针,需显式实现深拷贝;若类内部主要是自定义类型成员,且这些成员已有合适的拷贝构造,可不显式定义。一般来说,若类显式实现了析构函数释放资源,则需要显式编写拷贝构造函数。

  6. 返回类型影响:传值返回会创建临时对象并调用拷贝构造函数;传引用返回返回对象的别名,不产生拷贝。但要确保返回对象在函数结束后仍然有效,否则会产生野引用。

下面的示例代码中展示了拷贝构造函数的一些常见特点

#include <iostream>
#include <cstring>// 简单的日期类,成员为内置类型,无需管理资源
class Date {
public:int year;int month;int day;// 构造函数,用于初始化日期Date(int y = 2000, int m = 1, int d = 1) : year(y), month(m), day(d) {std::cout << "Date 构造函数被调用" << std::endl;}// 未显式定义拷贝构造函数,编译器自动生成,可完成内置类型的浅拷贝void print() {std::cout << year << "-" << month << "-" << day << std::endl;}
};// 字符串类,包含动态分配的内存,需要管理资源
class MyString {
public:char* data;// 构造函数,接收字符串并动态分配内存存储MyString(const char* str = "") {if (str) {data = new char[strlen(str) + 1];strcpy(data, str);} else {data = new char[1];data[0] = '\0';}std::cout << "MyString 构造函数被调用" << std::endl;}// 拷贝构造函数,实现深拷贝MyString(const MyString& other) {std::cout << "MyString 拷贝构造函数被调用" << std::endl;data = new char[strlen(other.data) + 1];strcpy(data, other.data);}// 析构函数,释放动态分配的内存~MyString() {delete[] data;std::cout << "MyString 析构函数被调用" << std::endl;}void print() {std::cout << data << std::endl;}
};// 传值返回函数,返回时会调用拷贝构造函数
Date returnDate() {Date d(2025, 5, 20);return d;
}// 传引用返回函数,不调用拷贝构造函数
Date& returnDateRef(Date& d) {return d;
}int main() {// 1. 拷贝构造函数是构造函数的重载形式,第一个参数是类对象引用Date d1(2024, 10, 10);// 调用编译器自动生成的拷贝构造函数Date d2(d1); std::cout << "d2 日期: ";d2.print();MyString s1("Hello");// 调用显式定义的拷贝构造函数进行深拷贝MyString s2(s1); std::cout << "s2 字符串: ";s2.print();// 2. 传值返回会调用拷贝构造函数Date result = returnDate();std::cout << "传值返回的日期: ";result.print();// 3. 传引用返回不调用拷贝构造函数Date d3(2026, 1, 1);Date& ref = returnDateRef(d3);std::cout << "传引用返回的日期: ";ref.print();return 0;
}    

2.4 拷贝赋值运算符重载函数operator=

基本概念

赋值运算符重载用于实现对象之间的赋值操作。当使用=将一个对象赋值给另一个对象时,编译器会调用赋值运算符重载函数。默认情况下,编译器会为类生成一个浅拷贝的赋值运算符,但在类中包含动态分配的资源(如指针)时,浅拷贝可能会导致问题,因此需要自定义赋值运算符重载函数来实现深拷贝。

避免浅拷贝问题

在类中如果包含动态分配的资源(如动态数组、指针等),默认的赋值运算符执行的是浅拷贝。浅拷贝仅复制指针的值,而不复制指针所指向的内容,这会导致多个对象共享同一块内存当其中一个对象被销毁时,释放该内存会使其他对象的指针变为悬空指针,进而引发程序崩溃或产生未定义行为。

通过重载赋值运算符,可以实现深拷贝,即复制指针所指向的内容,为每个对象分配独立的内存空间,避免上述问题。以下是一个示例:

#include <iostream>
#include <cstring>class MyString {
private:char* data;size_t length;
public:// 构造函数MyString(const char* str = "") {length = strlen(str);data = new char[length + 1];strcpy(data, str);}// 析构函数~MyString() {delete[] data;}// 赋值运算符重载,实现深拷贝MyString& operator=(const MyString& other) {if (this != &other) {delete[] data;length = other.length;data = new char[length + 1];strcpy(data, other.data);}return *this;}void print() const {std::cout << data << std::endl;}
};int main() {MyString s1("Hello");MyString s2("World");s2 = s1;s2.print();return 0;
}

与拷贝构造函数的区别

拷贝构造函数用于在创建新对象时,使用已存在的对象来初始化它;而赋值运算符重载用于将一个已存在对象的值赋给另一个已存在的对象。虽然它们都涉及对象的复制,但应用场景不同。例如:

MyClass obj1;
MyClass obj2 = obj1;  // 调用拷贝构造函数
MyClass obj3;
obj3 = obj1;          // 调用赋值运算符重载函数

2.5 取地址运算符重载 

基本概念

取地址运算符 & 是一个一元运算符,在默认情况下,对对象使用 & 运算符会返回该对象的内存地址。但通过重载取地址运算符,你可以改变这个默认行为,返回一个自定义的地址或者其他类型的值。取地址运算符重载有两种形式:普通对象的取地址运算符重载和常量对象的取地址运算符重载。

普通对象的取地址运算符重载

返回类型 operator&();

这里的 返回类型 可以是任意合法的 C++ 类型,通常是指针类型,但也可以是其他类型。该函数没有参数,因为它是一元运算符。 

常量对象的取地址运算符重载

返回类型 operator&() const;

 此形式用于常量对象,函数声明后面的 const 关键字表明该函数不会修改对象的状态。

使用场景

  • 封装指针:在某些情况下,你可能不希望直接暴露对象的真实地址,而是返回一个封装后的指针或者代理对象。
  • 调试和日志记录:在重载函数中添加额外的逻辑,如记录对象被取地址的操作,方便调试。
  • 智能指针:智能指针类可以重载取地址运算符,返回内部管理的原始指针。

下面是一个简单的示例,展示了如何重载取地址运算符:

#include <iostream>class MyClass {
private:int data;
public:MyClass(int value) : data(value) {}// 普通对象的取地址运算符重载MyClass* operator&() {std::cout << "普通对象取地址操作" << std::endl;return this;}// 常量对象的取地址运算符重载const MyClass* operator&() const {std::cout << "常量对象取地址操作" << std::endl;return this;}void printData() const {std::cout << "Data: " << data << std::endl;}
};int main() {MyClass obj(42);MyClass* ptr = &obj;ptr->printData();const MyClass constObj(100);const MyClass* constPtr = &constObj;constPtr->printData();return 0;
}    
  • 普通对象的取地址运算符重载:在 MyClass 类中,MyClass* operator&() 函数被重载。当对普通的 MyClass 对象使用 & 运算符时,会调用该函数,函数内部输出一条信息并返回 this 指针。
  • 常量对象的取地址运算符重载const MyClass* operator&() const 函数用于常量对象。当对常量的 MyClass 对象使用 & 运算符时,会调用该函数,同样输出一条信息并返回 this 指针。

注意事项

  • 返回类型:虽然返回类型可以是任意合法的 C++ 类型,但通常建议返回指针类型,以保持与取地址操作的语义一致。
  • 常量性:要同时提供普通对象和常量对象的取地址运算符重载版本,以确保对常量对象的取地址操作也能正确处理。
  • 慎用重载取地址运算符是一个非常基础的运算符,重载它可能会让代码的行为变得复杂,增加理解和维护的难度。因此,只有在确实有必要的情况下才进行重载。

兄弟们共勉 !!! 

码字不易,求个三连

抱拳了兄弟们!

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

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

相关文章

【c++】【STL】priority_queue详解

目录 priority_queue的作用priority_queue的接口构造函数emptysizetoppushpopswap priority_queue的实现仿函数&#xff08;函数对象&#xff09;是什么&#xff1f;向上调整算法&#xff08;adjustup&#xff09;向下调整算法&#xff08;adjustdown&#xff09;迭代器构造pus…

测试——用例篇

目录 1. 测试用例 1.1 概念 2. 设计测试用例的万能公式 2.1 常规思考逆向思维发散性思维 2.2 万能公式 3. 设计测试用例例的方法 3.1 基于需求的设计方法 ​编辑 3.2 具体的设计方法 3.2.1 等价类 3.2.2 边界值 3.2.3 正交法 3.2.4 判定表法 3.2.5 场景法 3.2.6…

销售总监求职简历模板

模板信息 简历范文名称&#xff1a;销售总监求职简历模板&#xff0c;所属行业&#xff1a;其他 | 职位&#xff0c;模板编号&#xff1a;KREUNY 专业的个人简历模板&#xff0c;逻辑清晰&#xff0c;排版简洁美观&#xff0c;让你的个人简历显得更专业&#xff0c;找到好工作…

AE脚本 关键帧缓入缓出曲线调节工具 Flow v1.5.0 Win/Mac

Flow是一个非常好用的After Effects脚本,它可以让你更加轻松自如地调整关键帧的速度曲线,无需触碰老旧复杂的图形编辑器。 AE脚本介绍 Flow为After Effects带来了一个简洁的界面,使自定义动画曲线变得十分容易,无需深入研究速度和影响力这些让人困惑的概念 - 只需绘制一个曲线…

ACGRIME:用于全局优化和特征选择的自适应混沌高斯RIME优化器,附完整版免费代码

自然现象中&#xff0c;软冰的形成过程由 Set al. [42] 提出&#xff0c;软冰是空气中的过冷水滴在接触固体物体并冻结时形成的。这种现象发生在特定的气候条件下&#xff0c;当水蒸气尚未凝结时&#xff0c;导致冰覆盖的表面呈现出独特的树枝状和叶子状景观。它在软冰的生长和…

大模型开发学习笔记

文章目录 大模型基础大模型的使用大模型训练的阶段大模型的特点及分类大模型的工作流程分词化(tokenization)与词表映射 大模型的应用 进阶agent的组成和概念planning规划子任务分解ReAct框架 memory记忆Tools工具\工具集的使用langchain认知框架ReAct框架plan-and-Execute计划…

4.27-5.4学习周报

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 摘要Abstract一、方法介绍2.Rainbow Memory(RM)2.1多样性感知内存更新2.2通过数据增强增强样本多样性(DA) 二、使用步骤1.实验概况2.RM核心代码 总结 摘要 本博客概…

AI Rack架构高速互连的挑战:损耗设计与信号完整性的设计框架

在AI驱动的时代&#xff0c;系统设计已经从单一PCB的视角&#xff0c;逐步转向以整个rack为单位来考量。 对于信号完整性而言&#xff0c;焦点以不再局限于单一PCB上的损耗&#xff0c;而是扩展到芯片与芯片之间的端到端互连损耗&#xff08;end-to-end interconnect loss&…

杭电oj(1180、1181)题解

目录 1180 题目 思路 问题概述 代码思路分析 1. 数据结构与全局变量 2. BFS 函数 bfs 3. 主函数 main 总结 代码 1181 题目 思路 1. 全局变量的定义 2. 深度优先搜索函数 dfs 3. 主函数 main 总结 代码 1180 题目 思路 注&#xff1a;当走的方向和楼梯方向一…

软件测试概念

这里写目录标题 需求开发模型软件生命周期瀑布模型螺旋模型增量模型、迭代模型敏捷模型Scrum 测试模型V模型W模型&#xff08;双V模型&#xff09; 需求 用户需求&#xff1a;没有经过合理的评估&#xff0c;通常就是一句话 软件需求&#xff1a;是开发人员和测试人员执行工作…

数字基带信号和频带信号的区别解析

数字基带信号和数字频带信号是通信系统中两种不同的信号形式&#xff0c;它们的核心区别在于是否经过调制以及适用的传输场景。以下是两者的主要区别和分析&#xff1a; 1. 定义与核心区别 数字基带信号&#xff08;Digital Baseband Signal&#xff09; 未经调制的原始数字信号…

Linux52 运行百度网盘 解决故障无法访问repo nosandbox 未解决:疑似libstdc++版本低导致无法运行baidu网盘

昨日参考 哦 我是root Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64 没了 计划去手动下一个 还是不行 放弃 猜测是 centos7 过期了 一些依赖组件也没地方下载了 通过阿里云镜像站下载 之前安装的好像不是这个版本 还是计划用yum去下载依赖&#xff0c;先处…

2000-2022年上市公司数字经济专利申请数据

2000-2022年上市公司数字经济专利申请数据 1、时间&#xff1a;2000-2022年 2、来源&#xff1a;国家知识产权局 3、指标&#xff1a;年份、股票代码、股票简称、行业名称、行业代码、省份、城市、区县、行政区划代码、城市代码、区县代码、首次上市年份、上市状态、数字经济…

机器学习之五:基于解释的学习

正如人们有各种各样的学习方法一样&#xff0c;机器学习也有多种学习方法。若按学习时所用的方法进行分类&#xff0c;则机器学习可分为机械式学习、指导式学习、示例学习、类比学习、解释学习等。这是温斯顿在1977年提出的一种分类方法。 有关机器学习的基本概念&#xff0c;…

Chromium 134 编译指南 - Android 篇:安装构建依赖项(七)

1. 引言 欢迎来到《Chromium 134 编译指南》系列的第七篇文章&#xff01;在前面的章节中&#xff0c;我们已经成功获取了Chromium源代码&#xff0c;并将其配置为支持Android平台。这些步骤为我们的编译之旅奠定了坚实的基础&#xff0c;但在开始实际编译之前&#xff0c;我们…

java 进阶 1.0

静态方法 static 就是能直接用&#xff0c;不用再new一个对象了 一般java中Math等静态类就是可以直接使用其方法 main函数里面不能包含太多的逻辑性语句&#xff0c;全部写成模块 写好程序之后如何测试呢&#xff1f; 使用junit&#xff0c;不能在main函数里测试 测试本身就…

中小企业MES系统详细设计

版本&#xff1a;V1.1 日期&#xff1a;2025年5月2日 一、设备协议兼容性设计 1.1 设备接入框架 #mermaid-svg-PkwqEMRIIlIBPP58 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-PkwqEMRIIlIBPP58 .error-icon{fill…

Spring Security会话管理

用户认证通过后&#xff0c;为了避免用户的每次操作都进行认证&#xff0c;可以将用户的信息保存在会话中。会话就是系统为了保持当前用户的登录状态所提供的机制&#xff0c;常见的有基于Session方式、基于Token方式等。Spring Security提供会话管理功能&#xff0c;只需要配置…

PostgreSQL数据库操作基本命令

常用操作sql &#x1f510; 用户管理 -- 创建用户 CREATE USER username WITH PASSWORD password;-- 修改用户密码 ALTER USER username WITH PASSWORD newpassword;-- 删除用户 DROP USER username;&#x1f4e6; 数据库操作 -- 创建数据库 CREATE DATABASE dbname;-- 删除…

[吾爱出品] 网文提取精灵_4.0

网文提取精灵 链接&#xff1a;https://pan.xunlei.com/s/VOPDvKljcT3EWLjpt5LeDZvfA1?pwdw8kq# 易语言写的&#xff0c;介意的不要下载 相对网文提取工具_2.10.02版&#xff0c;因为是重写界面&#xff0c;目前版本限制最高5线程&#xff0c;暂时不支持批处理。 虽然不支…