当前位置: 首页 > article >正文

【C++ 多态】虚函数 · 虚表 · 重写,一篇彻底弄明白!

C 多态详解C多态是面向对象的核心灵魂本文将由浅入深带你循序渐进地掌握多态的方方面面全程干货坐稳发车~ ദ്ദി˶̀֊́ )✧文章目录C 多态详解1. 什么是多态2. 运行时多态的实现前提3. 虚函数与虚函数的重写3.1 虚函数3.2 虚函数的重写覆盖3.3 一个小小的选择题测一下你是否真正理解4. 重写中的特殊情况4.1 协变4.2 析构函数的重写5. override 和 final5.1 override5.2 final6. 重载/重写/隐藏对比7. 纯虚函数与抽象类8. 多态的核心原理虚函数表vtable8.1 对象中隐藏的指针__vfptr8.2 多态到底是怎么实现的8.3 深入虚函数表重要细节一览8.4 虚函数和虚表存放在内存的哪个区结语1. 什么是多态“多态”这个词字面上就是“多种形态”。现实中这种例子很多同样是“买票”这件事普通人买是全价学生可能打五折军人则享受优先服务。同样是“动物叫”猫发出“喵喵”狗发出“汪汪”。不同对象对同一个消息给出不同的响应这就是多态。在 C 中多态可以分为两类编译时多态静态多态在编译阶段就确定调用哪个函数。典型代表是函数重载和函数模板。你传一个int编译器匹配f(int)传一个double匹配f(double)。这个过程在编译时就已经搞定了。运行时多态动态多态直到程序运行时才根据实际指向的对象来决定调用哪个函数。这也是本文的重点。它依赖于继承、虚函数、基类指针或引用。我们可以通过一个简单的例子感受一下// 买票的例子classPerson{public:virtualvoidBuyTicket(){cout买票-全价endl;}};classStudent:publicPerson{public:virtualvoidBuyTicket(){cout买票-打折endl;}};voidFunc(Personptr){ptr.BuyTicket();// 到底调用哪个BuyTicket运行时才知道}intmain(){Person ps;Student st;Func(ps);// 输出买票-全价Func(st);// 输出买票-打折}同样一个ptr.BuyTicket()当ptr引用的是Person对象时就执行全价逻辑引用的是Student对象时就执行打折逻辑。这就是运行时多态的效果。2. 运行时多态的实现前提要触发运行时多态必须同时满足两个条件必须通过基类的指针或引用来调用虚函数。被调用的函数必须是虚函数且派生类完成了对该虚函数的重写覆盖。为什么必须是指针或引用因为只有指针或引用才能既指向基类对象又指向派生类对象。如果是普通对象值传递就会发生“对象切片”只保留基类部分永远调用的都是基类的函数。3. 虚函数与虚函数的重写3.1 虚函数在类的成员函数前加上virtual关键字这个函数就是虚函数。例如virtualvoidBuyTicket(){...}注意只有类的非静态成员函数才可以声明为虚函数全局函数、静态成员函数、构造函数都不能是虚函数。3.2 虚函数的重写覆盖重写要求派生类中提供一个与基类完全相同的虚函数返回值类型相同函数名相同参数列表完全相同参数个数、类型、顺序三者都一致派生类的这个虚函数就重写了基类的虚函数。一个细节在派生类中重写时可以省略virtual关键字因为函数从基类继承下来时已经保持虚函数属性了即使你不写virtual它依然是虚函数并构成重写。但在实际开发中强烈建议还是写上virtual可读性更好。面试选择题里偶尔会出现故意不写virtual来考察你是否理解重写的条件务必当心!3.3 一个小小的选择题测一下你是否真正理解看这段代码你认为输出是什么A: A-0 B : B-1 C : A-1 D : B-0 E : 编译出错 F : 以上都不正确classA{public:virtualvoidfunc(intval1){std::coutA-valstd::endl;}virtualvoidtest(){func();}};classB:publicA{public:voidfunc(intval0){std::coutB-valstd::endl;}};intmain(){B*pnewB;p-test();return0;}公布答案——这题选B分析B重写了func没有写virtual但依然构成重写。注意重写与参数名、缺省值无关。A::func和B::func满足重写条件函数名都是 func参数类型都是 int都是虚函数A里的是virtualB里的自动继承virtual属性哪怕它们的默认值一个是1、一个是0也不影响重写关系。test是继承下来的内部调用func()。此时this指向的是B对象而test是基类的成员函数它在基类中调用了func()这里发生多态调用由于this是A*类型指向了B对象最终调用的是B::func。关键点来了 函数的默认值是在编译阶段就确定好的不是运行时动态决定的。A::test()里写的是func();编译器在编译这行代码时会根据A::func的声明把它直接替换成func(1)因为A::func的默认值是1。哪怕运行时实际调用的是B::func它拿到的参数也已经是 1 了和它自己定义的默认值 0 没有关系。所以 B::func 最终拿到的参数是 1 输出就是B-1而不是很多人误以为的 B-0 。如果直接通过p-func()调用呢这时p的静态类型是B*默认参数绑定的就是B中定义的val 0输出B-0。4. 重写中的特殊情况4.1 协变有时基类和派生类的返回值并不完全相同但依然能构成重写这就是协变。协变要求基类虚函数返回基类类型的指针或引用派生类的重写函数返回派生类类型的指针或引用。示例classPerson{public:virtualPerson*BuyTicket(){cout买票-全价endl;returnnullptr;}};classStudent:publicPerson{public:virtualStudent*BuyTicket(){cout买票-打折endl;returnnullptr;}};这里虽然返回值类型不一样Person*vsStudent*但它们是具有继承关系的指针编译器允许这种重写。协变在实际项目中用得不多了解即可。4.2 析构函数的重写如果类中定义了虚函数那么它的析构函数最好也声明为虚函数。这不是可选项而是防止内存泄漏的重要原则。看看为什么不加virtual会出问题classA{public:~A(){cout~Aendl;}};classB:publicA{public:~B(){cout~B-delete:_pendl;delete_p;}protected:int*_pnewint[10];};intmain(){A*p2newB;deletep2;// 只调用了~A没有调用~B_p泄漏return0;}当使用基类指针delete派生类对象时如果析构函数不是虚函数编译器只根据指针的静态类型A*调用A的析构函数不会执行B的析构函数导致B里申请的资源无法释放。解决办法把A的析构函数加上virtualclassA{public:virtual~A(){cout~Aendl;}};这时B的析构函数无论是否写virtual都会自动和A的析构函数构成重写因为编译器底层把析构函数统一命名为destructor。释放时就会走正常的析构流程先调~B()再调~A()(析构完子类后会自动调用基类的析构)资源安全释放。~A()是虚函数delete p2时会先找到真实类型 B 调用B::~B()。B::~B()执行清理B自己的资源。B::~B()执行完编译器自动帮你调用A::~A()清理套在里面的A的资源。这里还要注意一下派生类析构完自动调用基类析构是因为派生类对象里嵌套了一个基类子对象必须先析构外层再析构内层而我们自己没法手动调用基类析构所以编译器会自动调用基类析构的代码。总结只要一个类可能被继承或者其中已有虚函数就把它的析构函数声明为虚的。面试时也经常问到“为什么基类的析构函数要写成虚函数”答案就是这个内存泄漏的风险。5. override 和 final虚函数重写要求非常严格参数列表差一个const、函数名拼错一个字母都不会构成重写编译的时候也不会报错只有在程序运行时没有得到预期结果才来debug会得不偿失。因此C11 引入了两个关键字来帮我们5.1 override在派生类虚函数后面加上override告诉编译器“这个函数是用来重写基类虚函数的如果没构成重写请直接报错。”classCar{public:virtualvoidDrive(){}};classBenz:publicCar{public:virtualvoidDrive()override{coutBen-舒适endl;}// 拼写错误立即报错};如果你把Drive写成了Dirve编译器会立刻指出你并没有重写任何基类虚函数。这大大减少了调试时间。5.2 finalfinal修饰虚函数表示该虚函数不能被后续的派生类再次重写。classCar{public:virtualvoidDrive()final{}};classBenz:publicCar{public:virtualvoidDrive(){}// 编译错误Drive被final禁止重写};此外final也可以修饰类表示这个类不能被继承。6. 重载/重写/隐藏对比现象作用域函数名参数列表返回值virtual发生时期重载同一作用域相同不同可同可不同不要求编译时重写基类与派生类相同相同相同协变除外基类必须 virtual运行时隐藏基类与派生类相同不同或基类非虚任意非虚或参数不同编译时7. 纯虚函数与抽象类在虚函数后面加上 0这个函数就变成了纯虚函数。含有纯虚函数的类叫做抽象类。classCar{public:virtualvoidDrive()0;// 纯虚函数};抽象类不能实例化对象。这很合理——一个“车”的概念太抽象了你不知道它是怎么开的只有具体到“奔驰”、“宝马”才能理解驾驶行为。Car car;// 编译错误无法实例化抽象类派生类继承了抽象类后必须重写所有纯虚函数否则它自己也还是一个抽象类无法实例化。这实际上是在强制派生类实现某些接口。classBenz:publicCar{public:virtualvoidDrive(){coutBenz-舒适endl;}};classBMW:publicCar{public:virtualvoidDrive(){coutBMW-操控endl;}};父类对象不能实例化但是可以作为指针类型来使用intmain(){Car*pBenznewBenz;pBenz-Drive();Car*pBMWnewBMW;pBMW-Drive();return0;}虽然纯虚函数通常不需要实现因为会被重写但语法上你依然可以给它一个定义不过必须在类外定义。8. 多态的核心原理虚函数表vtable8.1 对象中隐藏的指针__vfptr先来看一个题下面编译为32位程序的运行结果是什么A.编译报错 B.运行报错 C.8 D.12classBase{public:virtualvoidFunc1(){coutFunc1()endl;}protected:int_b1;char_chx;};intmain(){Base b;coutsizeof(b)endl;return0;}直观来看int占 4 字节char占 1 字节还有内存对齐可能是 8。但实际结果是12多出来的 4 字节就是一个指针——虚函数表指针__vfptrv 代表 virtualf 代表 functionptr 代表 pointer。这个指针比较特殊它通常放在对象的最前面有些编译器可能放在末尾但主流放在前面指向一个虚函数表。只要一个类含有虚函数那么该类的每个对象中都至少有一个虚函数表指针从基类继承下来的也算。基类对象的虚函数表中存放基类所有虚函数的地址。同类型的对象共用同一张虚表不同类型的对象各自有独立的虚表所以基类和派生类有各自独立的虚表。。8.2 多态到底是怎么实现的我们把多态的例子用更完整的版本来演示classPerson{public:virtualvoidBuyTicket(){cout买票-全价endl;}protected:string _name;};classStudent:publicPerson{public:virtualvoidBuyTicket(){cout买票-打折endl;}protected:int_id;};classSoldier:publicPerson{public:virtualvoidBuyTicket(){cout买票-优先endl;}protected:string _codename;};voidFunc(Person*ptr){ptr-BuyTicket();// 这里发生了什么}当我们这样调用时Person ps;Student st;Soldier sr;Func(ps);// 买票-全价Func(st);// 买票-打折Func(sr);// 买票-优先即使Func内部是通过同一个Person*指针调用BuyTicket最终还是产生了不同的行为。这个过程编译器帮我们做了什么呢在满足多态条件指针虚函数的情况下函数调用不再像普通函数那样在编译时直接确定地址而是在运行时到对象的虚表中去查找应该调用哪个函数。具体来说当ptr指向Person对象时ptr-BuyTicket()会根据该对象的虚表找到Person::BuyTicket的地址并调用。当ptr指向Student对象时就会调用派生类的版本。这就是动态绑定。静态绑定编译时就能确定函数地址比如普通函数调用、非虚函数的对象调用。动态绑定编译时不确定运行时查虚表确定调用函数的地址虚函数 指针/引用。8.3 深入虚函数表我们再用一个包含多个虚函数的例子详细剖析虚表的内部结构。classBase{public:virtualvoidfunc1(){coutBase::func1endl;}virtualvoidfunc2(){coutBase::func2endl;}voidfunc5(){coutBase::func5endl;}protected:inta1;};classDerive:publicBase{public:virtualvoidfunc1(){coutDerive::func1endl;}virtualvoidfunc3(){coutDerive::func3endl;}voidfunc4(){coutDerive::func4endl;}protected:intb2;};这个继承关系中的虚函数表是什么样子的基类Base的虚表存储Base::func1的地址存储Base::func2的地址。派生类Derive的虚表首先它也有一个虚表。因为Derive继承了Base基类部分中的虚函数表指针不再指向基类的虚表而是指向Derive自己的虚表。Derive的虚表包含重写的Base::func1被替换成了Derive::func1的地址覆盖。未重写的Base::func2依然保留基类的地址。派生类独有的虚函数Derive::func3的地址被追加到表中。VS 编译器下虚表最后通常有一个0x00000000作为结束标记但这不是标准规定g 就没有。所以虚函数表本质就是一个函数指针数组存放着该类所有需要动态调用的虚函数地址。重要细节一览普通函数如func5、func4不在虚表中它们直接由类型决定编译时绑定。派生类的虚表与基类的虚表是完全不同的两个表。派生类对象中并不会额外生成一个新的虚函数表指针而是沿用从基类继承下来的那个指针只不过现在它指向的是派生类自己的虚表。通过 VS 的内存窗口可以直观地看到这些函数地址有些在监视窗口看不到的虚函数如func3在内存中却是真实存在的。8.4 虚函数和虚表存放在内存的哪个区这是一个开放性问题因为 C 标准没有硬性规定。但我们可以通过打印不同区域的地址来进行对比验证。intmain(){inti0;staticintj1;int*p1newint;constchar*p2xxxxxxxx;printf(栈:%p\n,i);printf(静态区:%p\n,j);printf(堆:%p\n,p1);printf(常量区:%p\n,p2);Base b;Derive d;Base*p3b;Derive*p4d;printf(Base虚表地址:%p\n,*(int**)p3);// 解引用对象首地址得到虚表指针printf(Derive虚表地址:%p\n,*(int**)p4);printf(虚函数地址:%p\n,Base::func1);printf(普通函数地址:%p\n,Base::func5);}输出中你会发现虚表地址通常与常量区的地址比较接近在 VS 中甚至就在代码段而普通函数地址也在代码段。虚函数存在哪虚函数本身是代码存储在代码段只是虚函数的地址又存到了虚表中虚函数表存在哪 虚表是一个存放这些函数地址的数组通常也放在代码段常量区C标准并没有规定到底应该存在哪不过VS下是存在代码段的结语今天的内容到这里就结束了希望你能有所收获~干货整理到手抖觉得有用的话赏个三连回回血__(:ᗤ」ㄥ)_ _

相关文章:

【C++ 多态】虚函数 · 虚表 · 重写,一篇彻底弄明白!

C 多态详解 C多态是面向对象的核心灵魂,本文将由浅入深,带你循序渐进地掌握多态的方方面面,全程干货,坐稳发车~ ദ്ദി˶ー̀֊ー́ )✧ 文章目录C 多态详解1. 什么是多态?2. 运行时多态的实现前…...

从数据模型到领域驱动设计:数据库抽象与微服务实践的演进

在软件开发的漫长历史中,如何有效地对现实世界进行建模,始终是核心挑战之一。从早期的层次数据库到当今的微服务架构,数据模型作为连接业务需求与技术实现的桥梁,经历了深刻的演变。本文基于对概念数据模型、基本数据模型和面向对象模型的系统探讨,进一步延伸到领域驱动设…...

Claw-ED:基于教学风格学习的AI助教,一键生成个性化教学包

1. 项目概述:一个为教师而生的AI教学助手 如果你是一位一线教师,每天被备课、写教案、做课件、设计学生活动、准备分层材料这些繁琐工作压得喘不过气,同时又对市面上那些“通用”的AI工具生成的、充满“AI腔”的教案感到失望,那么…...

高性能ai编程工具zed配置deepseek 开启ai agent对话及代码补全

配置ai助手 进入设置页配置deepseek apikey配置代码补全 进入setting->edit pridic -> config.json文件。替换下面内容{"show_edit_predictions": true,// ✅ 代码补全核心配置(关键修改)"edit_predictions": {"provide…...

FaaS承载AI Agent的性能断崖真相,实测AWS Lambda vs Cloudflare Workers响应延迟对比(含17项压测数据)

更多请点击: https://intelliparadigm.com 第一章:FaaS承载AI Agent的性能断崖真相 当AI Agent被部署至函数即服务(FaaS)平台时,其推理延迟常出现非线性跃升——从本地毫秒级响应骤增至数秒甚至超时失败。这一“性能断…...

SPT-AKI存档编辑器完全手册:单机版塔科夫终极存档修改指南

SPT-AKI存档编辑器完全手册:单机版塔科夫终极存档修改指南 【免费下载链接】SPT-AKI-Profile-Editor Программа для редактирования профиля игрока на сервере SPT-AKI 项目地址: https://gitcode.com/gh_mirro…...

保姆级教程:用正点原子MFG_TOOL给I.MX6U开发板烧录出厂系统(附常见问题排查)

嵌入式Linux开发板系统烧录全流程指南:从零开始到成功启动 第一次拿到嵌入式开发板时的兴奋感,往往会被复杂的系统烧录过程冲淡不少。特别是对于刚接触嵌入式Linux的开发者来说,如何把系统镜像正确烧录到开发板上,常常成为第一个需…...

告别环境报错!保姆级教程:从JRE到STM32CubeMX 6.10.0的完整安装与配置

从零搭建STM32开发环境:CubeMX 6.10.0避坑全指南 刚拿到STM32开发板时的兴奋,往往在环境配置阶段就被各种报错消磨殆尽。作为过来人,我深刻理解那种看着红色错误提示却无从下手的挫败感。本文将带你用最稳妥的方式完成从Java环境到CubeMX的全…...

利用GPU指纹技术进行位置验证

大家读完觉得有帮助记得关注和点赞!!!摘要对GPU芯片进行强有力的监管,对于防范先进AI模型被未经授权开发和滥用至关重要。目前的芯片位置监控方法,依赖于存储在芯片内部的加密密钥所支持的“基于ping的协议”。然而&am…...

综述篇 | 2015-2024,情绪识别(Emotion Recognition)技术演进与核心论文全景解读

1. 情绪识别技术演进全景图(2015-2024) 十年前,当研究人员试图通过摄像头分析人脸肌肉变化来判断情绪时,准确率还停留在60%左右。如今,结合多模态数据的情绪识别系统在特定场景下已突破90%准确率。这九年间的技术跃迁可…...

用OpenMV4 H7 PLUS做个智能分拣小车:颜色识别实战项目从硬件选型到代码集成

智能分拣小车实战:OpenMV4 H7 PLUS颜色识别与嵌入式系统集成 在创客竞赛和毕业设计中,智能分拣系统一直是热门选题。传统方案往往面临识别精度不足、响应延迟高或硬件兼容性差等问题。OpenMV4 H7 PLUS凭借其强大的图像处理能力和丰富的硬件接口&#xff…...

C++智能指针详解:原理、使用及避坑指南

文章目录 前言 一、智能指针核心原理:RAII机制 二、C常用智能指针详解(重点掌握后两种) 三、智能指针高频坑点(重中之重) 四、三大智能指针对比(选择指南) 五、实战案例:智能指…...

深入T100系统腹地:拆解标准区、测试区与客制开发的协作逻辑

深入T100系统腹地:拆解标准区、测试区与客制开发的协作逻辑 在企业管理系统的复杂生态中,T100以其独特的四区架构和多环境协作机制,为企业的数字化转型提供了稳健的技术支撑。这套架构不仅关乎代码的流转,更是企业业务流程标准化与…...

Arduino Uno R3 bootloader烧写避坑大全:从USBasp驱动签名到熔丝位设置(Win10/11实测)

Arduino Uno R3 bootloader烧写全流程避坑指南(Win10/11实战) 当你终于完成Arduino Uno R3开发板的硬件制作,准备烧写bootloader时,可能会发现这最后一步才是真正的"魔鬼关卡"。从驱动签名问题到熔丝位设置,…...

Yunzai-Bot阴天插件:免费集成百款AI大模型的QQ机器人全能助手

1. 项目概述与核心价值如果你正在寻找一个能让你在QQ机器人上免费、便捷地体验上百种主流AI大模型的解决方案,那么“阴天插件”(Y-Tian-Plugin)绝对值得你花时间深入了解。作为一名长期混迹于机器人开发社区的开发者,我见过太多要…...

全景视频会议核心技术解析:从200°视场角到实时图像拼接

1. 项目概述:全景视频会议如何从概念走向现实视频会议这玩意儿,我们搞通信和消费电子这行的,这些年见得多了。从最早模糊不清的像素块,到后来高清但视角固定的摄像头,大家总觉得少了点什么。没错,少的就是那…...

2025届最火的六大AI辅助写作网站解析与推荐

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 这些年,“论文一键生成”类工具可多了,吸引着有写作压力的学生&#…...

手把手教你用云GPU(极链AI云)零成本复现SlowFast视频动作识别,附完整配置文件与避坑指南

零成本云端复现SlowFast视频动作识别全攻略:极链AI云实战与参数精解 在计算机视觉领域,视频理解一直是个充满挑战的方向。不同于静态图像,视频数据包含丰富的时序信息,这对模型架构设计提出了更高要求。SlowFast作为Facebook AI R…...

[具身智能-653]:人的大脑神经网络就是天然的模拟电路,还是数字电路?

结论先给:人脑神经网络,本质是【天然模拟电路】,不是数字电路这和前面聊的模拟电路频域特性、硬件隐式频域滤波完全同逻辑。一、先分清:数字电路 vs 模拟电路 核心区别数字电路只有0、1两种离散电平,跳变是阶跃式&…...

免费在线PPT制作工具PPTist:浏览器中的专业演示文稿创作平台

免费在线PPT制作工具PPTist:浏览器中的专业演示文稿创作平台 【免费下载链接】PPTist PowerPoint-ist(/pauəpɔintist/), An online presentation application that replicates most of the commonly used features of MS PowerPoint, allow…...

百度网盘macOS下载限速破解:3步实现高速下载的完整指南

百度网盘macOS下载限速破解:3步实现高速下载的完整指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘在macOS上的龟速下载…...

Windows安装安卓APK的终极指南:APK Installer免费工具完整教程

Windows安装安卓APK的终极指南:APK Installer免费工具完整教程 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 还在为Windows电脑无法直接运行安卓应用而烦…...

从灰度图到粉彩叙事,全程可复现:5个精准Prompt模板+3类LUT预设,零基础速产美术馆级Pastel印相

更多请点击: https://intelliparadigm.com 第一章:从灰度图到粉彩叙事:Pastel印相的美学本质与技术边界 Pastel印相并非简单的色彩叠加,而是一种基于人眼感知非线性响应与胶片化学特性的数字模拟范式。其核心在于将灰度图像的亮度…...

从FPGA工程师的视角看AMBA总线:手把手教你用Verilog实现一个简易APB外设

从FPGA工程师的视角看AMBA总线:手把手教你用Verilog实现一个简易APB外设 在FPGA和数字IC设计领域,AMBA总线协议就像城市中的交通网络,负责协调各个功能模块之间的数据流动。而APB(Advanced Peripheral Bus)作为AMBA家族…...

游戏开发资源宝库:从计算机图形学到Unity生态的全栈知识索引

1. 项目概述:一份游戏开发者的“藏宝图”如果你是一名游戏开发者,无论是刚入行的新人,还是摸爬滚打多年的老兵,大概都经历过这样的时刻:为了实现一个特定的效果,或是解决一个棘手的技术难题,在搜…...

2026 AI大模型API加速网站推荐

在AI开发领域,一个现实问题始终困扰着开发者:如何接入模型厂商的官方API?在海外,注册、绑卡、调用这三个步骤就能轻松解决。然而,国内开发者面临着跨境网络波动、外币支付门槛、发票合规需求以及多厂商Key碎片化管理等…...

ArcGIS 10.2 保姆级安装与破解教程(含License Manager启动失败解决方案)

ArcGIS 10.2 完整安装指南:从零开始到完美运行 1. 准备工作与环境检查 在开始安装ArcGIS 10.2之前,确保你的系统满足以下基本要求: 操作系统:Windows 7/8/10(32位或64位)硬件配置:至少4GB RAM&a…...

别再用眼睛猜阈值了!Halcon threshold函数实战:5分钟搞定车牌字符分割

工业视觉实战:Halcon阈值分割在车牌识别中的精准应用 在机器视觉领域,车牌识别系统是典型的工业应用场景之一。而字符分割作为识别流程中的关键环节,直接影响最终识别准确率。许多初学者往往陷入一个误区——仅凭肉眼观察随意设置阈值参数&am…...

公交查询|智能公交|公交线路查询|基于SprinBoot+vue智能公交系统(源码+数据库+文档)

公交查询|智能公交|公交线路查询系统 目录 基于SprinBootvue智能公交系统 一、前言 二、系统设计 三、系统功能设计 1用户模块实现 2管理员服务端模块实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介…...

模拟真人手写软件,支持随机调节

软件介绍 前阵子公司要求我们签一份保密承诺书,还特别强调必须手写。这下可把不少同事难住了,平时都用电脑打字,手写都快生疏了。于是有同事让我帮忙找找能把手写字做出来的软件。我一开始找了几款手写字体,但写出来的效果太规整…...