C++类和对象——第二关
目录
类的默认成员函数:
(一)构造函数
(二)析构函数
(三)拷贝构造函数
类的默认成员函数:
类里面有6个特殊的成员函数分别包揽不同的功能;
(一)构造函数
说明:C++把类型分成内置类型(基本类型)和⾃定义类型。内置类型就是语⾔提供的原⽣数据类型,如:int/char/double/指针等,⾃定义类型就是我们使⽤class/struct等关键字⾃⼰定义的类型。
构造函数的特点:
(1)自动调用,在类实例化对象的时候会自动的调用构造函数。
(2)构造函数没有返回值(啥都不写,而不是说写void),名字和当前类的名字相同。
(3)构造函数可以分为三种,1.没有形参的构造,2.全缺省参数的构造,3.自动生成的构造,编译器默认生成的是无参构造。他们三个只能存在一个。如果类中没有显式定义构造函数,则C++编译器会⾃动⽣成⼀个⽆参的默认构造函数,⼀旦⽤⼾显式定义编译器将不再⽣成。
因为在调用的时候不需要传递任何的参数,所以构造函数总结下来可以称之为0实参构造函数。
自己写了构造函数,(编译器不再生成)。
class Date {
private:int _year;int _month;int _day;public:Date(int year = 1999, int month = 01, int day = 01) // 自己定义的全缺省构造函数{_year = year;_month = month;_day = day;}void Print(){cout << this->_year << "/" << this->_month << "/" << this->_day << endl;}};int main()
{Date d1(2024, 9, 23);Date d2;cout << "传参了:" << endl;d1.Print();cout << "没有传参:" << endl;d2.Print();return 0;
}
去掉自己写的构造函数的时候(使用的是编译器的默认构造):
class Date {
private:int _year;int _month;int _day;public://Date(int year = 1999, int month = 01, int day = 01) // 自己定义的全缺省构造函数//{// _year = year;// _month = month;// _day = day;//}void Print(){cout << this->_year << "/" << this->_month << "/" << this->_day << endl;}};int main()
{//Date d1(2024, 9, 23);Date d1; Date d2;cout << "传参了:" << endl;d1.Print();cout << "没有传参:" << endl;d2.Print();return 0;
}
这里可以看到,编译器初始化成员变量是随机值。
因为c++没有明确规定构造函数的初始化规则,所以不同的编译器会有不同的初始化规则,在vs上可能会初始化为随机值,但是在其他编译器上可能就不一样,构造函数中编译器对内置类型是没有确定处理的。
同样一段代码,我们放到devc++中执行的结果:编译器的初始化结果和vs是不一样的。
tips:正因为默认的构造函数初始化打击不确定的,所以大多数构造函数都是需要自己写的。
ps:想要redpanda dev编译器的可以私我给发。
(4)构造函数支持函数重载
我们可以写着两个构造函数,无参构造和全缺省构造函数,但是会产生调用歧义。
class Date {
private:int _year;int _month;int _day;public:Date(int year = 1999, int month = 01, int day = 01) // 自己定义的全缺省构造函数{_year = year;_month = month;_day = day;}// 自己定义的无参数的默认构造函数//Date() //{// _year = 1999;// _month = 07;// _day = 12;//}// 自己定义的带参默认构造//Date(int year, int month, int day)//{// _year = year;// _month = month;// _day = day;//}void Print(){cout << this->_year << "/" << this->_month << "/" << this->_day << endl;}};int main()
{Date d1; Date d2(2024,2,3);cout << "传参了:" << endl;cout << "没有传参:" << endl;d2.Print();return 0;
}
还有就是:在创建对象调用的时候,是无参构造就不需要给对象传参了,是有参数构造的必须要传参,不然编译器会报错的。
(5)为了更深层次的理解构造函数,我们使用C++来实现一个栈的初始化和压栈操作:
#include <stdlib.h>
#include <iostream>
using namespace std;
class stack {
private:int _top;// 栈顶int _capacity; // 数组空间的大小int* _arr; // 使用动态数组来实现栈public:stack(int n = 4) // 实现构造函数,和init函数差不多{_top = 0;_capacity = 4;_arr = (int*)malloc(sizeof(int) * _capacity);//先预开辟4*4 = 16个字节的空间}// 压栈入数据void push(int x){// 判断栈是否满了if (_top == _capacity) // 如果栈满了,就重新开空间{int newcapacity = _capacity * 2;int* tmp = (int*)realloc(_arr, sizeof(int) * newcapacity);if (tmp == nullptr){cout << "realloc fail!" << endl;return;}_capacity = newcapacity;_arr = tmp;}_arr[_top] = x;_top++;}
};int main()
{stack st;st.push(1);st.push(2);st.push(3);st.push(4);st.push(5);return 0;
}
可以看到我们写的栈的初始化函数就是构造函数我们没有手动调用,它在程序执行过程中自动调用了。
(二)析构函数
和构造函数相反对应的是析构函数,它们可以说是相辅相成。
C++规定对象在销毁时会⾃动调⽤析构函数,完成对象中资源的清理释放⼯作。
析构函数的特性:
(1)函数名和对象名一样,没有返回值,没有参数,定义时在函数名前面加~:
(2)同构造函数一样,一个类只能存在一个析构函数,构造函数在创建对象时调用,析构函数在对象生命周期结束的时候调用。
class Date {
private:int _year;int _month;int _day;public:Date(int year = 1999, int month = 01, int day = 01) // 自己定义的全缺省构造函数{_year = year;_month = month;_day = day;}// 自己写的析构函数~Date(){cout << "这里调用了析构函数:~Date()" << endl;}void Print(){cout << this->_year << "/" << this->_month << "/" << this->_day << endl;}};int main()
{Date d1;// 这里定义的两个对象没有显示的调用析构函数如:d1.Date().Date d2;return 0;
}
step1:d1和d2两个对象当代码执行到return 0;这句代码的时候生命周期结束,我们在这句代码处打一个断点进行调试。
step2:我们接下来对代码进行逐步调试,发现代码直接跳到了我们刚自己实现的析构函数的位置
step3:程序继续执行,执行完析构函数内的程序代码之后打印结束,程序结束。
在调用析构函数的时候,有几个对象就析构几次,可以看到我们创建了两个析构函数,打印了两次。因为在main的函数栈帧中,执行规则和数据结构的栈的执行规则差不多,都是后进先出,所以在析构多个对象的时候,遵循先定义的后析构,也可以理解为生命周期先结束的最后析构。
(3)跟构造函数类似,编译器默认⽣成的析构函数对内置类型成员不做处理,自定义类型成员会调⽤他的析构函数。
(4)还需要注意的是我们显⽰写析构函数,对于⾃定义类型成员也会调⽤他的析构,也就是说⾃定义类型成员⽆论什么情况都会⾃动调⽤析构函数
比如说:我们定义了一个类,里面存在另外一个类实例化的对象,我们在另一个类中实现了析构函数,在定义这个类实例化的对象的时候,这个实例化的对象生命周期结束的时候会去调用另一个类的析构函数。
(5)没有申请资源时,析构函数可以不写,有资源申请时,⼀定要⾃⼰写析构,否则会造成资源泄漏。
在上面我面我们定义了一个栈的类做构造函数的例子,我们在写的时候申请了空间,但是我们没有将空间释放掉,也没有写析构函数,而编译器自己默认生成的析构函数只会清理内置类型的空间,所以其实已经造成了内存泄漏了,最终泄露的这块内存由操作系统回收。
我们给它加上析构函数将开辟在堆上的空间释放掉。
#include <cstdlib>
#include <stdlib.h>
#include <iostream>using namespace std;class stack {
private:int _top;// 栈顶int _capacity; // 数组空间的大小int* _arr; // 使用动态数组来实现栈public:stack(int n = 4) // 实现构造函数,和init函数差不多{_top = 0;_capacity = 4;_arr = (int*)malloc(sizeof(int) * _capacity);//先预开辟4*4 = 16个字节的空间}// 压栈入数据void push(int x){// 判断栈是否满了if (_top == _capacity) // 如果栈满了,就重新开空间{int newcapacity = _capacity * 2;int* tmp = (int*)realloc(_arr, sizeof(int) * newcapacity);if (tmp == nullptr){cout << "realloc fail!" << endl;return;}_capacity = newcapacity;_arr = tmp;}_arr[_top] = x;_top++;}// 自己写的析构函数~stack(){free(_arr);_arr = nullptr;_capacity = _top = 0;}
};int main()
{stack st;return 0;}
当然,如果可以也可以在析构函数里面申请空间,除非你有病。
(三)拷贝构造函数
需要理解的几个点:
(1)拷贝构造是构造函数的重载,他和构造函数一样,都是为了初始化一个对象。构造函数是初始化当前对象,拷贝构造是使用另一个函数来初始化当前对象。
(2)拷⻉构造函数的第⼀个参数必须是类类型对象的引⽤,使⽤传值⽅式编译器直接报错,因为语法逻辑上会引发⽆穷递归调⽤。拷⻉构造函数也可以多个参数,但是第⼀个参数必须是类类型对象的引⽤,后⾯的参数必须有缺省值。
假设不是类类型的对象引用——>引发无穷递归:
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;} // 编译报错:error C2652 : “Date”: ⾮法的复制构造函数: 第⼀个参数不应是“Date”//Date(Date d)Date(const Date & d){_year = d._year;_month = d._month;_day = d._day;} Date(Date d) // 这里语法上是不允许的,只是为了举例。{_year = d._year;_month = d._month;_day = d._day;} void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2(d1);return 0;
}
tips:为了避免发生被拷贝对象成员被修改的情况,在拷贝构造函数的参数前面加一个const限定。如在上面的日期类的拷贝构造函数中:
Date(const Date& d) //这里加一个const修饰能够避免源对象(d1)被修改
{_year = d._year;_month = d._month;_day = d._day;
}int main()
{Date d1;Date d2(d1);return 0;
}
(3)C++规定⾃定义类型对象进⾏拷⻉⾏为必须调⽤拷⻉构造,⾃定义类型传值传参和传值返回都会调⽤拷⻉构造完成
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;} Date(const Date& d) //这里加一个const修饰能够避免源对象{_year = d._year;_month = d._month;_day = d._day;} void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};void func(Date d)
{d.Print();
}int main()
{Date d1;Date d2(d1);func(d1); // 这里传值传参会调用拷贝构造return 0;
}
对代码进行调试运行过程如图:
(4)若未显式定义拷⻉构造,编译器会⽣成⾃动⽣成拷⻉构造函数。⾃动⽣成的拷⻉构造对内置类型成员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉)类似于memcpy函数,对⾃定义类型成员变量会调⽤他的拷⻉构造
(5)如果在定义对象(类)的时候产生了资源的申请,就需要自己写拷贝构造函数,同析构函数一样,是否有资源的申请决定是否需要自己写拷贝构造函数,一般需要自己写析构函数的话就需要自己写拷贝构造函数。
(4)(5)两点且看下面代码:
class stack {
private:int _top;// 栈顶int _capacity; // 数组空间的大小int* _arr; // 使用动态数组来实现栈public:stack(int n = 4) // 实现构造函数,和init函数差不多{_top = 0;_capacity = 4;_arr = (int*)malloc(sizeof(int) * _capacity);//先预开辟4*4 = 16个字节的空间}// 压栈入数据void push(int x){// 判断栈是否满了if (_top == _capacity) // 如果栈满了,就重新开空间{int newcapacity = _capacity * 2;int* tmp = (int*)realloc(_arr, sizeof(int) * newcapacity);if (tmp == nullptr){cout << "realloc fail!" << endl;return;}_capacity = newcapacity;_arr = tmp;}_arr[_top] = x;_top++;}// 自己写的析构函数~stack(){free(_arr);_arr = nullptr;_capacity = _top = 0;}
};int main()
{stack st1;stack st2(st1);//使用st1来初始化st2return 0;}
当我们执行这段代码的时候会发生下列情况:
程序挂掉了,为什么?
我们来调试看一下:
对于这种情况我们就需要自己写一个拷贝构造函数了。
class stack {
private:int _top;// 栈顶int _capacity; // 数组空间的大小int* _arr; // 使用动态数组来实现栈public:stack(int n = 4) // 实现构造函数,和init函数差不多{_top = 0;_capacity = 4;_arr = (int*)malloc(sizeof(int) * _capacity);//先预开辟4*4 = 16个字节的空间}// 压栈入数据void push(int x){// 判断栈是否满了if (_top == _capacity) // 如果栈满了,就重新开空间{int newcapacity = _capacity * 2;int* tmp = (int*)realloc(_arr, sizeof(int) * newcapacity);if (tmp == nullptr){cout << "realloc fail!" << endl;return;}_capacity = newcapacity;_arr = tmp;}_arr[_top] = x;_top++;}// 自己写的析构函数~stack(){free(_arr);_arr = nullptr;_capacity = _top = 0;}// 自己写的拷贝构造函数stack(const stack& st){_capacity = st._capacity;_top = st._top;int new_capacity = st._capacity;int* tmp = (int*)malloc(sizeof(int) * new_capacity);//重新申请一片空间if (tmp == nullptr){perror("malloc fail!");return;}_arr = tmp;}};
执行代码重新调试看一下:
地址不一样了,我们重新申请了空间。
在上面的代码调试过程中,我们发现使用编译器默认生成的拷贝构造函数不会申请空间,它会一个个字节的拷贝,拷贝动态数组的时候它拷贝的值动态数组指针变量的地址,并没有申请空间这一操作,我们将这种拷贝方式称为浅拷贝。而我们自己实现的拷贝构造函数自己申请了空间,我们将这种拷贝称为深拷贝。
也可以使用等号的方式调用拷贝构造函数初始化对象,在承接上面的代码,我们定义一个新的对象,如:
int main()
{stack st1;stack st2(st1);//使用st1来初始化st2// 也可以使用等号的方式调用拷贝构造函数初始化对象stack st3 = st1; return 0;}
这样写不会报错。
(6) 传值返回会产⽣⼀个临时对象调⽤拷⻉构造,产生拷贝,传值引⽤返回,返回的是返回对象的别名(引⽤),没有产⽣拷⻉。但是如果返回对象是⼀个当前函数局部域的局部对象,函数结束就销毁了,那么使⽤引⽤返回是有问题的,这时的引⽤相当于⼀个野引⽤,类似⼀个野指针⼀样。传引⽤返回可以减少拷⻉,但是⼀定要确保返回对象,在当前函数结束后还在,才能⽤引⽤返回。
不能返回临时对象,返回临时对象是会销毁的,里面的各种指针就成了野指针,返回的是一个被销毁了的空间,所以引用这时候是这块被销毁的空间的别名。
相关文章:

C++类和对象——第二关
目录 类的默认成员函数: (一)构造函数 (二)析构函数 (三)拷贝构造函数 类的默认成员函数: 类里面有6个特殊的成员函数分别包揽不同的功能; (一)构造函数…...

服务器数据恢复—raid5阵列热备盘上线失败导致阵列崩溃的数据恢复案例
服务器磁盘阵列数据恢复环境: 服务器中有两组分别由4块SAS硬盘组建的raid5磁盘阵列,两组raid5阵列划分LUN,组成LVM结构,格式化为EXT3文件系统。 服务器磁盘阵列故障: 服务器中一组raid5阵列中有一块硬盘离线ÿ…...

Python与SQL Server数据库结合导出Excel并做部分修改
Python与SQL Server数据库结合导出Excel并做部分修改 需求:在数据库中提取需要的字段内容;并根据字段内容来提取与拆分数据做为新的列最后导出到Excel文件 # -*- coding: utf-8 -*- import pandas as pd import re import pymssql import timestart_ti…...

常见的TTL,RS232,RS485,IIC,SPI,UART之间的联系和区别
简单总结 图片来源 RS232,RS485可参考,IIC,SPI,UART可参考 烧录程序中常听到的一句话就是USB转TTL,但严格来说算是USB传输数据的协议转换成TTL(Transistor-Transistor Logic)协议传输数据。首先,usb是常见…...

【数据结构】栈和队列(Stack Queue)
引言 在对顺序表,链表有了充分的理解之后,现在让我们学习栈和队列!!! 【链表】 👈链表 【顺序表】👈顺序表 目录 💯栈 1.栈的概念及结构 2.栈的实现 ⭐初始化栈 ⭐入栈 ⭐…...

Vue.js基础
Vue.js https://v2.cn.vuejs.org/https://cn.vuejs.org/初识Vue 官网:Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层…...

罐区紧急切断阀安装位置规范
在化工生产与储存的复杂环境中,罐区紧急切断阀的安装位置规范不仅是保障生产安全的关键一环,更是预防重大事故、减少损失的有效手段。在深入理解了罐区布局、物料特性及潜在风险后,对于紧急切断阀的安装位置,我们应遵循以下更为细…...

JavaScript 中的事件模型
JavaScript 中的事件模型是浏览器如何处理用户交互(如点击、键盘输入、鼠标移动等)或其他事件(如加载完成、定时器等)的机制。理解事件模型有助于我们处理这些事件并响应它们。JavaScript 的事件模型主要包括以下几个部分…...

理解Java引用数据类型(数组、String)传参机制的一个例子
目录 理解Java引用数据类型(数组、String)传参机制的一个例子理解样例代码输出 参考资料 理解Java引用数据类型(数组、String)传参机制的一个例子 理解 引用数据类型传递的是地址。用引用类型A给引用类型B赋值,相当于…...

【计算机组成原理】实验一:运算器输入锁存器数据写实验
目录 实验要求 实验目的 主要集成电路芯片及其逻辑功能 实验原理 实验内容及步骤 实验内容 思考题 实验要求 利用CP226实验箱上的K16~K23二进制拨动开关作为DBUS数据输入端,其它开关作为控制信号的输入端,将通过K16~K23设定…...

LSI SAS 9361-8i和SAS3008 12 gb / s PCIe 3.0 RAID 阵列卡配置
LSI SAS 9361-8i和SAS3008 12 gb / s PCIe 3.0 RAID 阵列卡配置 开机,BIOS自检,可以看到设备硬盘信息,以及提示CtrlR进入Raid卡配置界面。 按CtrlR进入Raid卡配置界面,一般来说使用CtrlR进入Raid卡配置界面的Raid卡配置都通用。 …...

node js版本低导致冲突WARN EBADENGINE package: required: { node: ‘>=18‘ }
重新安装依赖包 1、删除旧的 node_modules 目录和 package-lock.json 文件: rm -rf node_modules rm package-lock.json2、升级node版本 wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bashexport NVM_DIR"$([ -z "${…...

828华为云征文|使用Flexus X实例安装宝塔面板教学
目录 一、Flexus X实例简介 1.1 概述 1.2 产品规格 二、切换操作系统 2.1 Huawei Cloud EulerOS 2.0 标准版 2.2 切换镜像 三、部署宝塔面板 3.1 安装宝塔面板 3.2 放通安全组规则 3.3 登录宝塔面板 四、使用感受 4.1 柔性算力随心配 4.2 一直加速一直快 4.3 越用…...

1.量化第一步,搭建属于自己的金融数据库!
数据是一切量化研究的前提。 做量化没有数据,就相当于做饭时没有食材。 很多时候,我们需要从大量的数据中寻找规律,并从中开发出策略。如果我们每次使用的时候,都从网上去找数据,一方面效率低下,另一方面短…...

git-repo系列教程(6) 在自己服务器上搭建git-repo仓库
为什么要在自己的服务器上搭建git-repo仓库呢? 因为 清华大学开源软件镜像站 有时会更新同步git repo,导致不能使用.可能在局域网不能访问外网,无法下载镜像站上的git-repo仓库完全版. 操作步骤 1.获取git-repo仓库 需要先下载完全的仓库 cd .repo/repo/ #获取镜像站上的…...

微服务——服务保护(Sentinel)(一)
1.雪崩问题 级联失败或雪崩问题指的是在微服务架构中,由于服务间的相互依赖和调用,当一个服务出现故障时,会引起调用它的服务也出现故障,进而引发整个调用链路的多个服务都出现故障,最终导致整个系统崩溃的现象。 产生…...

jenkins声明式流水线语法详解
最基本的语法包含 pipeline:所有有效的声明式流水线必须包含在一个 pipeline 块中stages:包含一系列一个或多个stage指令stage:stage包含在stages中进行,比如某个阶段steps:在阶段中具体得执行操作,一个或…...

mini-lsm通关笔记Week2Overview
Week 2 Overview: Compaction and Persistence 在上周,您已经实现了LSM存储引擎的所有必要结构,并且您的存储引擎已经支持读写接口。在本周中,我们将深入探讨SST文件的磁盘组织,并研究在系统中实现性能和成本效益的最佳方法。我们…...

基于SpringBoot的在线点餐系统【附源码】
基于SpringBoot的高校社团管理系统(源码L文说明文档) 4 系统设计 4.1 系统概述 网上点餐系统的结构图4-1所示: 图4-1 系统结构 模块包括主界面,首页、个人中心、用户管理、美食店管理、美食分类管理、美食…...

生成式语言模型底层技术面试
在准备生成式语言模型的底层技术面试时,可以关注以下几个关键领域: 1. 模型架构 Transformer架构:了解自注意力机制、编码器-解码器结构,以及如何处理序列数据。预训练与微调:解释预训练和微调的过程,如何…...

HTML开发指南
目录 一、HTML基础1. HTML简介(1)标记语言(2)结构化文档(3)标签与属性(4)注释(5)版本演变 2. HTML文档结构(1)文档类型声明࿰…...

共筑数据安全防线!YashanDB与SPU完成兼容性互认证
近日,深圳计算科学研究院崖山数据库系统YashanDB与深圳市机密计算科技有限公司SPU机密计算协处理器顺利完成兼容性互认证。测试结果表明,双方产品完全兼容,稳定运行,能为用户提供全链路的数据安全管理解决方案,助力央国…...

【FastAPI】使用FastAPI和Redis实现实时通知(SSE)
在当今快速发展的Web应用程序中,实时通知已成为用户体验的重要组成部分。无论是社交媒体更新、消息通知,还是系统状态提醒,实时数据推送可以极大地提升用户互动性。本文将详细介绍如何使用FastAPI和Redis实现Server-Sent Events (SSE) 来推送…...

Keyence_PL_MC_HslCommunication import MelsecMcNet
import tkinter as tk from tkinter import messagebox from datetime import datetime from HslCommunication import MelsecMcNet, OperateResult def 创建_plc_应用程序(): class 应用程序(tk.Tk): def __init__(self): super().__init__() …...

软件架构的演变与趋势(软件架构演变的阶段、综合案例分析:在线电商平台架构演变、开发补充)
随着软件开发技术的不断进步,软件架构从最初的简单结构演变为如今的复杂系统,架构设计不再是简单的代码组合,而是战略性的系统设计,确保系统具备可扩展性、可靠性、安全性和可维护性。 文章目录 1. 软件架构演变的阶段1.1 单体架…...

Shopify独立站运营必知必会:选品与防封技巧
独立站和第三方平台是目前最常见的跨境电商销售模式,相比于第三方平台,独立站的商家可以自己建站,自行决定运营模式和营销手段等策略,尤其是在准入门槛上,难度会更低,这些特点吸引了不少商家选择独立站开店…...

Unity开发绘画板——03.简单的实现绘制功能
从本篇文章开始,将带着大家一起写代码,我不会直接贴出成品代码,而是会把写代码的历程以及遇到的问题、如何解决这些问题都记录在文章里面,当然,同一个问题的解决方案可能会有很多,甚至有更好更高效的方式是…...

R语言的基础知识R语言函数总结
R语言与数据挖掘:公式;数据;方法 R语言特征 对大小写敏感通常,数字,字母,. 和 _都是允许的(在一些国家还包括重音字母)。不过,一个命名必须以 . 或者字母开头,并且如果以 . 开头&…...

龙年国庆专属姓氏头像
关注▲洋洋科创星球▲一起成长! 2024年,我们迎来了龙年,龙年国庆姓氏头像! 慢慢找! 你的和你朋友的都有。 01赵 02 钱 03 孙 04 李 05 周 06 吴 07 郑 08 王 09 冯 010 陈 011 褚 012 卫 013 蒋 014 沈 015 韩 姓氏…...

基于Es和智普AI实现的语义检索
1、什么是语义检索 语义检索是一种利用自然语言处理(NLP)和人工智能(AI)技术来理解搜索查询的语义,以提供更准确和相关搜索结果的搜索技术,语义检索是一项突破性的技术,旨在通过深入理解单词和…...