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

C++ 多态

1.多态的概念

多态(polymorphism)通俗来说就是多种形态。多态分为编译时多态(静态多态)和运行时多态(动态多态),这里我们重点是运行时多态,编译时多态主要就是我们前面的函数重载和函数模版,他们传不同类型的参数就可以调用不同的函数,通过参数不同达到多种形态,之所以叫编译时多态,是因为他们实参传给形参的参数匹配是在编译时完成的,我们把编译时一般归为静态,运行时归为动态。

运行时多态,具体点就是去完成某个行为(函数),可以传不同的对象就会完成不同的行为,就达到多种形态。比如买票这个行为,当普通人买票时,是全价买票;学生买票就是优惠买票;军人买票是优先买票。

2.多态的定义及实现

2.1多态的构成条件

多态是一个继承关系下的类对象,去调用同一函数,产生了不同的行为。比如Student继承了Person。Person对象全价买票。Student对象优惠买票。

2.1.1实现多态还有两个必须重要条件

  • 必须是基类的指针或者引用调用虚函数。
  • 被调用的函数必须是虚函数,并且完成了虚函数重写/覆盖。

说明:要实现多态效果,第一:必须是基类的指针或引用,因为只有基类的指针或引用才能既指向基类对象又指向派生类对象;第二:派生类必须对基类的虚函数完成重写/覆盖,重写或者覆盖了,基类和派生类之间才能有不同的函数,多态的不同形态效果才能达到。

2.1.2虚函数

类成员函数前面加virtual修饰,那么这个成员函数就被称为虚函数。注意非成员函数不能加virtual修饰。

class Person
{
public:virtual void Func(){cout << "买票—全价" << endl;}
};

2.1.3虚函数的重写/覆盖

虚函数的重写/覆盖:派生类中有一个跟基类完全相同的虚函数(既派生类虚函数与基类虚函数的返回值类型、函数名称、参数列表完全相同),称派生类的虚函数重写了基类的虚函数。

注意:在重写基类虚函数时,派生类的虚函数在不加virual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用(可能在考试选择题中,经常会故意埋这个坑,判断是否构成多态)。

class Person
{
public:virtual void BuyTicket(){cout << "买票—全价" << endl;}
};class Student : public Person
{
public:virtual void BuyTicket(){cout << "买票—半价" << endl;}
};//void Func(Person& ptr)//引用也可以
//void Func(Person ptr)//直接调用不行,不能构成多态
void Func(Person* ptr)
{//这里可以看到虽然Person指针Ptr在调用BuyTicket但是跟ptr没有关系,//而是由ptr指向的对象决定的ptr->BuyTicket();
}int main()
{Person p;Student s;Func(&p);Func(&s);return 0;
}

2.2多态场景的一个选择题

class A
{
public:virtual void func(int val = 1) { std::cout << "A->" << val << std::endl; }virtual void test() { func(); }
};class B : public A
{
public:void func(int val = 0) { std::cout << "B->" << val << std::endl; }
};int main(int argc, char* argv[])
{B* p = new B;p->test();return 0;
}

运行出来的结果是B->1,为什么会是这个结果呢?

这个p是子类的指针,但是子类中没有重写test(),所以此时的指针指向的是父类的test,调用父类的func,构成了多态,子类的func完成了重写。

重写的本质是重新写虚函数的实现。B中的func重写A中的func时并没有走B的func函数,而是在原A函数的基础上用B的fuhc函数体覆盖A的func函数体。(多态生效时,函数体使用B::func,但默认参数仍取自A::func

如果A中的func有默认参数val=1,B中的func有默认参数val=0,但B没有重写test(),那么当通过B对象调用test()(继承自A的test),test()内部调用func(),此时func()的默认参数来自A的声明,即val=1,但实际调用的函数体是B的func,所以输出B->1。

2.3虚函数重写的一些其他问题

  • 协变

派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变

class A
{};class B : public A
{};class Person
{
public:virtual A* BuyTicket(){cout << "买票—全价" << endl;return nullptr;}
};class Student : public Person
{
public:virtual B* BuyTicket(){cout << "买票—半价" << endl;return nullptr;}
};void Func(Person* ptr)
{ptr->BuyTicket();
}int main()
{Person ps;Student st;Func(&ps);Func(&st);return 0;
}
  • 析构函数的重写

基类的析构函数为虚函数,此时派生类析构函数只有定义,无论是否加virtual关键字,都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同看起来不符合重写的规则,实际上编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor,所以基类的析构函数加了virtual修饰,派生类的析构函数就构成重写。

class A
{
public:virtual ~A(){cout << "~A()" << endl;}
};class B : public A
{
public:virtual ~B(){cout << "~B() -> delete:" << _p << endl;delete [] _p;}protected:int* _p = new int[10];
};int main()
{A* p1 = new A;A* p2 = new B;delete p1;delete p2;return 0;
}

为什么基类中的析构函数建议设计为虚函数

上面代码可以看到,如果~A(),不加virtual,那么delete p2时只调用的A的析构函数,没有调用B的析构函数,就会导致内存泄漏问题,因为~B()中有资源释放

2.4 override和final关键字

从上面可以看出,C++对虚函数重写的要求比较严格,但是有些情况下由于疏忽,比如函数名写错参数写错等导致无法构成重写,而这种错误在编译期间是不会报出的,只有在程序运行时没有得到预期结果才来debug会得不偿失,因此C++11提供了override,可以帮助用户检测是否重写。如果我们不想让派生类重写这个虚函数,那么可以用final去修饰。

class Car
{
public:virtual void Drive(){}
};class Benz : public Car
{
public:virtual void func() override{cout << "Benz:舒适" << endl;}
};

error C3668: “Benz::func”: 包含重写说明符“override”的方法没有重写任何基类方法。

但如果不写override则不会检测出来

class Car
{
public:virtual void Drive() final{}
};class Benz : public Car
{
public:virtual void Drive() {cout << "Benz:舒适" << endl;}
};

在基类的成员函数加上final则不会被重写。

2.5 重载/重写/隐藏的对比

3. 纯虚函数和抽象类

在虚函数的后面写上=0,则这个函数为纯虚函数,纯虚函数不需要定义实现(实现没啥意义因为要被派生类重写,但是语法上可以实现),只要声明即可。包含纯虚函数的类叫做抽象类,抽象类不能实例化出对象,如果派生类继承后不重写纯虚函数,那么派生类也是抽象类。纯虚函数某种程度上强制了派生类重写虚函数,因为不重写实例化不出对象。

class Car
{
public:virtual void Drive() = 0;
};class Benz : public Car
{
public:virtual void Drive(){cout << "Benz-舒适" << endl;}
};class BMW : public Car
{
public:virtual void Drive(){cout << "BMW-操控" << endl;} 
};int main()
{//Car car;//“Car”: 无法实例化抽象类Car* pBenz = new Benz;pBenz->Drive();Car* pBMW = new BMW;pBMW->Drive();return 0;return 0;
}

4.多态的原理

4.1 虚函数表指针

class Base
{
public:virtual void Func1(){cout << "Func1()" << endl;}
protected:int _b = 1;char _ch = 'x';
};
int main()
{Base b;cout << sizeof(b) << endl;return 0;
}

这个运行结果是12bytes,除了_b和_ch成员,还多一个_vfptr放在对象的前面(注意:有些平台可能会放到对象的最后面,这个跟平台有关),对象中的这个指针我们叫做虚函数表指针(v代表virtual,f代表function)。一个含有虚函数的类中都至少都有一个虚函数表指针,因为一个类所以虚函数的地址要被放到这个类对象的虚函数表中,虚函数表也简称虚表。

4.2多态的原理

4.2.1 多态是如何实现的

从底层的角度Func函数中ptr->BuyTicket(),是如何作为ptr指向Person对象调用Person::BuyTicket,ptr指向Student对象调用Student::BuyTicket的呢?通过下图我们可以看到,满足多态条件后,底层不再是编译时通过调用对象确定函数的地址,而是运行时到指向的对象的虚表中确定对应的虚函数地址,这样就实现了指针或引用指向基类就调用基类的虚函数,指向派生类就调用派生类对应的虚函数。第二张图,ptr指向的Person对象,调用的是Person的虚函数;第三张图,ptr指向的Student对象,调用的是Student的虚函数。

class Person 
{
public:virtual void BuyTicket() { cout << "买票-全价" << endl; }
private:string _name;
};class Student : public Person 
{
public:virtual void BuyTicket() { cout << "买票-打折" << endl; }
private:string _id;
};class Soldier : public Person 
{
public:virtual void BuyTicket() { cout << "买票-优先" << endl; }
private:string _codename;
};void Func(Person* ptr)
{// 这⾥可以看到虽然都是Person指针Ptr在调⽤BuyTicket// 但是跟ptr没关系,⽽是由ptr指向的对象决定的。ptr->BuyTicket();
}
int main()
{// 其次多态不仅仅发⽣在派⽣类对象之间,多个派⽣类继承基类,重写虚函数后// 多态也会发⽣在多个派⽣类之间。Person ps;Student st;Soldier sr;Func(&ps);Func(&st);Func(&sr);return 0;
}


4.2.2 动态绑定与静态绑定

  • 对不满足多态条件(指针或者引用+调用虚函数)的函数调用是在编译时绑定,也就是编译时确定调用函数的地址,叫做静态绑定。
  • 满足多态条件的函数调用是在运行时绑定的,也就是在运行时到指向对象的虚函数表中找到函数的地址,叫做动态绑定。

4.3虚函数表

  • 基类对象的虚函数表中存放基类所以虚函数的地址。同类型的对象共用同一张虚表,不同类型的对象各自有独立的虚表,所以基类和派生类有各自独立的虚表。

  • 派生类由两部分构成,继承下来的基类和自己的成员,一般情况下,继承下来的基类中有虚函数表指针,自己就不会再生成虚函数表指针。但是要注意的是这里继承下来的基类部分虚函数指针和基类对象的虚函数指针不是同一个。就像基类对象的成员和派生类对象中的基类对象成员也独立的。
  • 派生类中重写的基类的虚函数,派生类的虚函数表中对应的虚函数就会被覆盖成派生类重写的虚函数的地址。
  • 派生类的虚函数表中包含:(1)基类的虚函数的地址;(2)派生类重写的虚函数地址完成覆盖,派生类自己的虚函数地址三部分。
  • 虚函数表本质是一个存虚函数指针的指针数组,一般情况下这个数组后面放一个0x00000000标记。(这个C++并没有规定,各个编译器自行定义,vs系列编译器会在后面放个0x00000000标记,g++系列编译器不会放)
  • 虚函数存在哪里呢?虚函数和普通函数一样,编译好后是一段指令,都是存在代码段,只是虚函数的地址又存到了虚表中。
  • 虚函数表存在哪里?这个问题严格说没有标准答案C++标准并没有规定,我们写下面代码可以对比验证一下。vs下是存在代码段(常量区)。
#include<iostream>
using namespace std;class Base
{
public:virtual void Func1(){cout << "Base::Func1" << endl;}virtual void Func2(){cout << "Base::Func2" << endl;}void func3(){cout << "Base::Func3" << endl;}
protected:int a = 1;
};class Derive : public Base
{
public:virtual void Func1(){cout << "Base::Func1" << endl;}virtual void Func4(){cout << "Base::Func4" << endl;}void Func5(){cout << "Base::Func5" << endl;}protected:int b = 2;
};int main()
{Base b;Base c;Derive d;return 0;
}

int main()
{int i = 0;static int j = 1;int* p1 = new int;const char* p2 = "xxxxxxxx";printf("栈:%p\n", &i);printf("静态区:%p\n", &j);printf("堆:%p\n", p1);printf("常量区:%p\n", p2);Base b;Derive d;Base* p3 = &b;Derive* p4 = &d;printf("Person虚表地址:%p\n", *(int*)p3);printf("Student虚表地址:%p\n", *(int*)p4);printf("虚函数地址:%p\n", &Base::Func1);printf("普通函数地址:%p\n", &Base::Func3);return 0;
}

5.虚函数的面试题

正确选B,A选项被virtual修饰的成员函数才能称为虚函数;C选项虚函数virtual关键字只有在声明时加上,在类外实现时不能加;D选项静态虚拟成员函数static和virtual是不能同时使用的


正确选项是D,选项A友元函数不属于成员函数,不能成为虚函数;选项B静态成员函数不能设置为虚函数;选项C静态成员函数不能设置为虚函数,是因为静态成员函数与具体对象无关,属于整个类,核心关键是没有this指针,可以通过 类名::成员函数名 直接调用,此时没有this无法拿到虚表,就无法实现多态,因此不能设置为虚函数。


答案是B,选项A抽象类不能实例化对象,所以以对象返回是错误的;选项B抽象类可以定义指针,其目的就是用父类指针指向子类从而实现多态;选项C参数为对象,所以错误;选项D直接实例化对象是不允许的。


答案是D,选项A在多继承的时候就可能会有多张虚表;选项B父类对象的虚表与子类对象的虚表没有任何关系,这是两个不同的对象;选项C虚表是在编译期间生成的。


答案选择A,B选项,虽然子类函数是私有的,但多态仅仅是用子类函数的地址覆盖虚表,最终调用的位置不变,只是执行函数发生变化;C选项,不强制也可以直接赋值,因为赋值兼容规则做出了保证;D选项,如果基类中的虚函数是public,即使派生类中的覆盖版本是private,通过基类指针调用仍然是允许的,因为编译器在编译时检查的是基类的访问权限,而不是派生类的。


答案是C,new B时先调用父类A的构造函数,执行test()函数,再调用func()函数,由于此时还处于对象构造阶段,多态机制还没有生效,所以此时执行func函数为父类的func函数,打印0,构造完父类后又执行子类构造函数,又调用test函数,然后执行func(),由于父类已经构造完毕,虚表已经生成,func满足多态的条件,所以调用子类的func函数,对成员m_iVal加1,进行打印,所以打印1,最后通过父类指针p->test(),也是执行子类的func,所以还是m_iVal加1,最后打印2,所以答案是C。


答案是B。A选项,D类中有几个父类(父类中有虚函数),就会有几张虚表,自身子类不会产生多余的虚表,所以只有2张虚表;C选项,子类自己的虚函数只会放到第一个父类的虚表后面,其他父类的虚表不需要存储,因为存储了也不能调用。

相关文章:

C++ 多态

1.多态的概念 多态&#xff08;polymorphism&#xff09;通俗来说就是多种形态。多态分为编译时多态&#xff08;静态多态&#xff09;和运行时多态&#xff08;动态多态&#xff09;&#xff0c;这里我们重点是运行时多态&#xff0c;编译时多态主要就是我们前面的函数重载和…...

【matlab|python】矢量棍棒图应用场景和代码

【matlab|python】矢量棍棒图应用场景和代码 矢量棍棒图的介绍和作用 矢量棍棒图&#xff08;stick plot&#xff09;是一种用于可视化 方向性时间序列数据 的图形工具。它常用于大气科学和海洋科学中&#xff0c;以直观地展示 风场、海流 或 其他矢量变量 随时间的变化情况。 …...

Matlab 五相电机仿真

1、内容简介 Matlab 208-五相电机仿真 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略...

计算机视觉cv2入门之视频处理

在我们进行计算机视觉任务时&#xff0c;经常会对视频中的图像进行操作&#xff0c;这里我来给大家分享一下&#xff0c;如何cv2中视频文件的操作方法。这里我们主要介绍cv2.VideoCapture函数的基本使用方法。 cv2.VideoCapture函数...

力扣每日一题781题解-算法:贪心,数学公式 - 数据结构:哈希

https://leetcode.cn/problems/rabbits-in-forest/description/?envTypedaily-question&envId2025-04-20 781.推测兔子数 算法&#xff1a;贪心&#xff0c;数学公式 数据结构&#xff1a;哈希 用哈希存每个兔子报告的同色数量&#xff0c;作为key&#xff0c;同个key…...

MAC-QueryWrapper中用的exists,是不是用join效果更好

在使用MyBatis-Plus的QueryWrapper中的exists方法时,是否改为使用join效果会更好,以及如何 修改。这涉及到SQL优化和MyBatis-Plus的用法。 首先,需要理解exists和join在SQL中的区别。exists用于检查子查询是否返回结果,而join则是将 两个表连接起来,根据某些条件合并行…...

使用 Visual Studio 2022 中的 .http 文件

转自微软技术文档&#xff1a; https://learn.microsoft.com/zh-cn/aspnet/core/test/http-files?viewaspnetcore-9.0 Visual Studio 2022.http 文件编辑器提供了一种便捷的方式来测试 ASP.NET Core项目&#xff0c;尤其是 API 应用。 编辑器提供一个 UI&#xff0c;用于&am…...

相得益彰 — 基于 GraphRAG 事理图谱驱动的实时金融行情新闻资讯洞察

*本文为亚马逊云科技博客文章&#xff0c;仅用于技术分享&#xff0c;不构成投资建议或金融决策支持。文中涉及的公司名称仅用于技术示例&#xff0c;不代表亚马逊云科技观点或与这些公司的商业合作关系。 背景介绍 在当今这个信息爆炸的时代&#xff0c;金融市场每天都在产生…...

为什么this与super不能出现在同一构造器的原因

在 Java 中&#xff0c;this() 和 super() 不能同时出现在同一个构造器中&#xff0c;因为它们都必须作为构造器的第一条语句&#xff0c;而一个构造器的第一条语句只能有一个。以下是详细解释和示例&#xff1a; ⚠️ 核心规则 只能二选一&#xff1a; 每个构造器的第一条语句…...

Linux:网络基础

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《Linux&#xff1a;网络基础》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 如果本篇文章对你有帮助&#xff0c;还请各位点点赞&#xff01;&#xf…...

C++入门篇(下)

目录 1、引用 1.1 引用概念 1.2 引用特性 1.3 常引用 1.4 使用场景 1.4.1 引用做参数 1.4.2 引用做返回值 1.5 引用和指针的区别 2、内联函数 2.1 概念 2.2 特性 3、auto关键字 4、基于范围的for循环 5、指针空值nullptr 5.1 C98 中的指针空值处理 5.2 C11 …...

QCustomPlot中自定义QCPAbstractPlottable绘图元素

QCPAbstractPlottable 是 QCustomPlot 中所有可绘制图形(如曲线、柱状图等)的基类。要创建自定义的绘图元素&#xff0c;通常需要继承这个类并实现其纯虚函数。 基本步骤 继承 QCPAbstractPlottable 实现必要的纯虚函数 添加自定义属性和方法 注册到 QCustomPlot 系统 完…...

【Bluedroid】蓝牙 HID 设备信息加载与注册机制及配置缓存系统源码解析

本篇解析Android蓝牙子系统加载配对HID设备的核心流程&#xff0c;通过btif_storage_load_bonded_hid_info实现从NVRAM读取设备属性、验证绑定状态、构造描述符并注册到BTA_HH模块。重点剖析基于ConfigCache的三层存储架构&#xff08;全局配置/持久设备/临时设备&#xff09;&…...

【计算机视觉】CV实战项目 - PCC-Net 人群计数

PCC-Net 人群计数项目 项目特点项目运行方式与步骤1. 环境准备2. 数据准备3. 模型训练4. 实验结果 常见问题及解决方法 PCC-Net&#xff08;Perspective Crowd Counting via Spatial Convolutional Network&#xff09;是一个用于人群计数的深度学习项目&#xff0c;旨在通过空…...

Towards Transferable Targeted 3D Adversarial Attack in the Physical World--阅读笔记

目录 简介&#xff1a; 背景&#xff1a; 挑战&#xff1a; 目的&#xff1a; 技术细节&#xff1a; 贡献&#xff1a; ​​1. NeRF的核心作用&#xff1a;3D重建与参数化表示​​ ​​2. 对抗优化的创新&#xff1a;NeRF参数空间的双优化​​ ​​2.1 传统方法的局限…...

​opencv图像库编程

一、下载安装 opencv 1.1 下载安装包 1.2 解压缩 unzip opencv-3.4.11.zip 解压缩以后主目录文件夹如下&#xff1a; 1.3 进入到解压后的文件夹中 cd opencv-3.4.11 二、使用 cmake安装opencv 2.1 进入 root 用户&#xff0c;并更新一下 sudo su sudo apt-get update …...

星拍相机APP:时尚与科技的完美融合,打造你的专属美

在数字时代&#xff0c;手机相机不仅是记录生活的工具&#xff0c;更是表达个性和创意的平台。今天&#xff0c;我们要介绍的 星拍相机APP&#xff0c;就是这样一款匠心制作的手机相机应用。它融合了时尚与科技&#xff0c;提供了多样化的魔法美颜功能&#xff0c;让每一次拍摄…...

puzzle(0531)脑力航迹

目录 脑力航迹 规则 解法 简单模式 中等模式 困难模式 专家模式 脑力航迹 规则 2条航迹会产生一个相对航迹&#xff1a; 根据相对航迹和其中一个航迹推导另外一个航迹。 解法 没有任何需要推理的地方&#xff0c;就是纯粹的2个矢量相加。 简单模式 中等模式 困难模…...

【英语语法】词法---形容词

目录 形容词1. 形容词的核心功能2. 形容词的位置(1) 前置定语&#xff08;最常见&#xff09;(2) 后置定语&#xff08;特殊情况&#xff09;(3) 表语位置&#xff08;系动词后&#xff09; 3. 形容词的比较级与最高级(1) 规则变化(2) 不规则变化(3) 用法对比 4. 多个形容词修饰…...

理解 React 的 useEffect

文章目录 React 的 useEffect一、什么是副作用&#xff08;Side Effects&#xff09;&#xff1f;二、useEffect 的基本用法三、依赖数组的三种情况1. 无依赖数组&#xff08;每次渲染后都执行, 不推荐&#xff09;2. 空依赖数组&#xff08;仅在挂载时执行一次&#xff09;3. …...

2.1 基于委托的异步编程方法

基于委托的异步编程模型是 .NET 早期版本中实现异步操作的一种方式,主要通过 BeginInvoke 和 EndInvoke 方法来实现。这种基于委托的异步模式已被 Task 和 async/await 模式取代,但在维护旧代码时仍可能遇到这种模式。 委托的方法中:Invoke用于同步调用; 而BeginInvoke与E…...

对于在线教育或知识付费类网站视频处理方案

一、视频格式&#xff1a; 1. 推荐格式&#xff1a;HLS&#xff08;HTTP Live Streaming&#xff09; 优势‌&#xff1a; ‌自适应码率‌&#xff1a;根据用户网络状况自动切换清晰度&#xff0c;避免卡顿。‌广泛兼容性‌&#xff1a;iOS/macOS 原生支持&#xff0c;Android…...

Gen - CDPT举例说明:动态上下文前缀(输入先和标签结合,输出结果会更贴近标签内容)

Gen - CDPT举例说明:动态上下文前缀(输入先和标签结合,输出结果会更贴近标签内容) 目录 Gen - CDPT举例说明:动态上下文前缀(输入先和标签结合,输出结果会更贴近标签内容)输入文本示例Gen - CDPT模型处理过程示例什么是:提示次优动态前缀提示方法生成与这条评论上下文…...

UCSC CTF 2025|MISC

1、USB flag{ebdfea9b-3469-41c7-9070-d7833ecc6102} 2、three part1是图片隐水印 part1&#xff1a;8f02d3e7 part2是2进制变换 -ce89-4d6b-830e- Part3先从pass.pcapng得到密码字典 解压缩密码&#xff1a;thinkbell 3个部分合并得到flag{8f02d3e7-ce89-4d6b-830e-5d0cb5…...

FTP客户端实现(文件传输)

文章目录 &#x1f9f1; 一、FTP 基础架构回顾&#x1f680; 二、FTP 客户端的核心结构&#x1f517; 三、连接与登录过程&#x1f4cc; 1. ftp_create()&#x1f4cc; 2. ftp_connect()&#x1f4cc; 3. ftp_login() &#x1f4c1; 四、上传文件实现&#xff08;ftp_upload_fi…...

状态管理最佳实践:Bloc架构实践

状态管理最佳实践&#xff1a;Bloc架构实践 引言 Bloc (Business Logic Component) 是Flutter中一种强大的状态管理解决方案&#xff0c;它基于响应式编程思想&#xff0c;通过分离业务逻辑和UI表现层来实现清晰的代码架构。本文将深入探讨Bloc的核心概念、实现原理和最佳实践…...

嵌入式人工智能应用-第三章 opencv操作 5 二值化、图像缩放

嵌入式人工智能应用 嵌入式人工智能应用-第三章 opencv操作 5 二值化 嵌入式人工智能应用1 二值化1.1 概念介绍1.2 函数介绍1.2 基本应用1.3 参考案例 2 图像缩放2.1 基本概念2.2 函数介绍2.3 基本参考代码2.4 pyrUp 和 pyrDown 函数2.5 函数介绍2.6 参考代码2.7 总结 1 二值化…...

[OS_7] 访问操作系统对象 | offset | FHS | Handle

实验代码可以看去年暑假的这篇文章&#xff1a;【Linux】进程间通信&#xff1a;详解 VSCode使用 | 匿名管道 我们已经知道&#xff0c;进程从 execve 后的初始状态开始&#xff0c;可以通过 mmap 改变自己的地址空间&#xff0c;通过 fork 创建新的进程&#xff0c;再通过 exe…...

【Vulkan 入门系列】创建帧缓冲、命令池、命令缓存,和获取图片(六)

这一节主要介绍创建帧缓冲&#xff08;Framebuffer&#xff09;&#xff0c;创建命令池&#xff0c;创建命令缓存&#xff0c;和从文件加载 PNG 图像数据&#xff0c;解码为 RGBA 格式&#xff0c;并将像素数据暂存到 Vulkan 的 暂存缓冲区中。 一、创建帧缓冲 createFramebu…...

Linux 进程控制(自用)

非阻塞调用waitpid 这样父进程就不会阻塞&#xff0c;此时循环使用我们可以让父进程执行其他任务而不是阻塞等待 进程程序替换 进程PCB加载到内存中的代码和数据 替换就是完全替换当前进程的代码段、数据段、堆和栈&#xff0c;保存当前的PCB 代码指的是二进制代码不是源码&a…...

FreeSWITCH 简单图形化界面41 - 批量SIP视频呼叫测试

FreeSWITCH 简单图形化界面41 - 批量视频测试 0、界面预览00、安装测试工具1、注册分机2、设置接听选项2.1 上传媒体文件2.2 设置接听设置 3、呼叫测试 0、界面预览 http://myfs.f3322.net:8020/ 用户名&#xff1a;admin&#xff0c;密码&#xff1a;admin FreeSWITCH界面安…...

通过爬虫方式实现头条号发布视频(2025年4月)

1、将真实的cookie贴到代码目录中toutiaohao_cookie.txt文件里,修改python代码里的user_agent和video_path, cover_path等变量的值,最后运行python脚本即可; 2、运行之前根据import提示安装一些常见依赖,比如requests等; 3、2025年4月份最新版; 代码如下: import js…...

《AI大模型应知应会100篇》第28篇:大模型在文本创作中的应用技巧

第28篇&#xff1a;大模型在文本创作中的应用技巧 &#x1f9e0; 摘要 在内容为王的时代&#xff0c;AI大模型正在重塑文本创作的每一个环节。从创意构思到风格润色&#xff0c;从论文报告到小说脚本&#xff0c;AI不仅是创作者的助手&#xff0c;更是灵感的激发器。本文将带你…...

字节跳动发布UI-TARS-1.5,入门AI就来近屿智能

近日&#xff0c;字节跳动在 Hugging Face 平台正式开源了其最新多模态代理模型——UI-TARS-1.5。作为 UI-TARS 系列的革新之作&#xff0c;该模型以视觉语言模型为基础&#xff0c;突破性实现跨平台 GUI 自动化交互&#xff0c;为自动化与智能交互领域注入了强劲动能。无论是开…...

大数据学习栈记——MapReduce技术

本文介绍hadoop中的MapReduce技术的应用&#xff0c;使用java API。操作系统&#xff1a;Ubuntu24.04。 MapReduce概述 MapReduce概念 MapReduce是一个分布式运算程序的编程框架&#xff0c;核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序…...

GO语言入门:常用数学函数2

14.6 大型数值 math/big 包中公开了一些实用 API&#xff0c;用于表示大型整数值和浮点数值。当基础类型无法容纳要使用的数值时&#xff0c;应改用 big 包中提供的新类型。例如 Int、Float 等。 14.6.1 大型整数值之间的运算 若希望让下面两个整数值完成加、减法运算&#…...

Django 使用教程

Django 使用教程 Django 是一个高级的 Python Web 框架&#xff0c;采用了 MTV&#xff08;Model-Template-View&#xff09;设计模式&#xff0c;旨在帮助开发者快速构建高效、可维护的 Web 应用。它有着非常丰富的功能&#xff0c;包括 ORM、用户认证、表单处理、管理后台等…...

deepseek + kimi制作PPT

目录 一、kimi简介二、deepseek生成内容三、生成PPT四、编辑PPT 一、kimi简介 kimi是一款只能ppt生成器&#xff0c;擅长将文本内容生成PPT。 在这里&#xff0c;​​DeepSeek 负责内容生成与逻辑梳理​​&#xff0c;​​Kimi 优化表达与提供设计建议​​。 二、deepseek生…...

C++学习:六个月从基础到就业——内存管理:RAII原则

C学习&#xff1a;六个月从基础到就业——内存管理&#xff1a;RAII原则 本文是我C学习之旅系列的第十九篇技术文章&#xff0c;也是第二阶段"C进阶特性"的第四篇&#xff0c;主要介绍C中的RAII原则及其在资源管理中的应用。查看完整系列目录了解更多内容。 引言 在…...

量子计算与经典计算融合:开启计算新时代

一、引言 随着科技的飞速发展&#xff0c;计算技术正迎来一场前所未有的变革。量子计算作为前沿技术&#xff0c;以其强大的并行计算能力和对复杂问题的高效处理能力&#xff0c;吸引了全球科技界的关注。然而&#xff0c;量子计算并非要完全取代经典计算&#xff0c;而是与经典…...

RV1126网络环境TFTPNFS搭建(二)

二、RV1126 开发板TFTP环境搭建 2.1、Ubuntu下安装和配置 xinetd 执行以下指令&#xff0c;安装 xinetd sudo apt-get install xinetd 执行以下指令创建一个 xinetd.conf 文件 sudo vi /etc/xinetd.conf 修改 xinetd.conf 文件内容如下&#xff1a; # Simple configurat…...

计算机视觉7——齐次坐标与相机内外参

一、透视投影 透视投影&#xff08;Perspective Projection&#xff09;是计算机视觉和图形学中描述三维物体在二维平面成像的基础模型&#xff0c;其核心思想是模拟人类视觉系统的成像原理——中心投影。具体而言&#xff0c;三维空间中的点通过一个固定的投影中心&#xff0…...

学习笔记—C++—string(一)

目录 string 为什么学习string的类 string类的常用接口 string类对象的常见构造 string类对象的访问及遍历操作 operator[] 迭代器 范围for auto 迭代器&#xff08;二&#xff09; string类对象的容量操作 size,length,max_size,capacity,clear基本用法 reserve 提…...

Linux命令-Shell编程

Shell是一个命令行解释器&#xff0c;它接收应用程序/用户命令&#xff0c;然后调用操作系统内核。 写一个hello.sh脚本&#xff1a; 1.mkdir scripts 2.cd scripts 3.touch hello.sh 4.vim hello.sh #!/bin/bash echo "hello,world" 5.bash hello.sh&#xff08…...

基于Django的AI客服租车分析系统

基于Django的AI客服租车分析系统 【包含内容】 【一】项目提供完整源代码及详细注释 【二】系统设计思路与实现说明 【三】AI智能客服与用户交互指导手册 【技术栈】 ①&#xff1a;系统环境&#xff1a;Python 3.8&#xff0c;Django 4.2框架 ②&#xff1a;开发环境&a…...

计算机组成与体系结构:计算机结构的分类(classifications of computer architecture)

目录 Von Neumann Architecture&#xff08;冯诺依曼结构&#xff09; Harvard Architecture&#xff08;哈佛结构&#xff09; Modified Harvard Architecture&#xff08;改进哈佛结构&#xff09; 三种结构对比总结表 &#x1f4a1; 从“内存访问结构”角度分类&#x…...

在阿里云和树莓派上编写一个守护进程程序

目录 一、阿里云邮件守护进程 1. 安装必要库 2. 创建邮件发送脚本 mail_daemon.py 3. 设置后台运行 二、树莓派串口守护进程 1. 启用树莓派串口 2. 安装依赖库 3. 创建串口输出脚本 serial_daemon.py 4. 设置开机自启 5. 使用串口助手接收 一、阿里云邮件守护进程 1.…...

Redis 的几种数据类型

Redis 提供了多种数据类型&#xff0c;以支持不同的应用场景。每种数据类型都有其特定的操作方式&#xff0c;并且在内部实现上也有所优化&#xff0c;能够满足不同的业务需求。以下是 Redis 支持的几种常见数据类型&#xff1a; 1. 字符串&#xff08;String&#xff09; 描…...

Spring之我见 - Spring Boot Starter 自动装配原理

欢迎光临小站&#xff1a;致橡树 Spring Boot Starter 的核心设计理念是 约定优于配置&#xff0c;其核心实现基于 自动配置&#xff08;Auto-Configuration&#xff09; 和 条件化注册&#xff08;Conditional Registration&#xff09;。以下是其生效原理&#xff1a; 约定…...

LeRobot 项目部署运行逻辑(二)—— Mobile Aloha 真机部署

LeRobot 在开源项目中详细说明了部署流程&#xff0c;所以首先看一下开源的内容&#xff0c;然后再逐步拆解 首先&#xff0c;LeRobot 开源的硬件是配全部在 examples 文件夹中 包括了 Stretch 3、Aloha and Aloha 2 stationary、SO-100、LeKiwi、Moss v1 等机器人 恰好实验…...