C++11QT复习 (十)
基类与派生类之间的转换
- **Day7-4 基类与派生类之间的转换**
- **一、问题回顾**
- **二、基类与派生类间的转换**
- **1. 类型适应(Upcasting)**
- **2. 逆向转换(Downcasting)**
- **三、代码示例**
- **四、派生类间的复制控制**
- **五、总结**
- **1. `base = derived`(对象赋值,发生切片)**
- **特点:**
- **2. `Base& ref = derived`(引用绑定,无切片)**
- **特点:**
- **3. 推荐程度**
- **更推荐的替代方案:`Base*`(指针)**
- **4. 要点**
- **最佳实践**
Day7-4 基类与派生类之间的转换
一、问题回顾
- 继承的形式有哪些?
- 三种继承方式的特点?
- 派生类的生成过程?
- 继承的局限?
- 派生类对象的创建和销毁的特点是什么?
- 多继承的问题有哪些?如何解决?
二、基类与派生类间的转换
1. 类型适应(Upcasting)
派生类对象可以适用于基类对象,即一个派生类的实例可以用基类的引用或指针来操作。C++ 允许以下转换:
-
赋值转换:
Base base; Derived derived; base = derived; // 允许,但发生对象切片
注意:派生类特有的数据会被丢弃。
-
引用转换(推荐):
Base& ref = derived; // 允许,ref 绑定到 derived 的基类部分
-
指针转换(推荐):
Base* pBase = &derived; // 允许,pBase 指向 derived 的基类部分
2. 逆向转换(Downcasting)
基类对象不能直接转换为派生类对象,除非使用强制转换:
Derived* pDerived = static_cast<Derived*>(&base); // 不安全!
原因:基类对象可能不包含派生类的数据,强制转换可能导致非法访问。
使用 dynamic_cast
在多态类中更安全:
Derived* pDerived = dynamic_cast<Derived*>(&base);
if (pDerived) {// 转换成功,pDerived 可用于 Derived 类型的操作
}
三、代码示例
#include <iostream>
using namespace std;class Base {
public:Base(double base = 0.0) : _base(base) {cout << "Base(double base = 0.0)" << endl;}virtual ~Base() { cout << "~Base()" << endl; }void print() const { cout << "Base::_base = " << _base << endl; }
private:double _base;
};class Derived : public Base {
public:Derived(double base = 0.0, double derived = 0.0) : Base(base), _derived(derived) {cout << "Derived(double = 0.0, double = 0.0)" << endl;}~Derived() { cout << "~Derived()" << endl; }void show() const { cout << "Derived::_derived = " << _derived << endl; }
private:double _derived;
};int main()
{Base base(11.11);base.print();Derived derived(22.22, 33.33);derived.show();cout << "派生类向基类转换";base = derived;//1.可以将派生类对象赋值给基类对象base.print();/*与用基类对象直接初始化不同(这时会发生对象切片),引用绑定不会拷贝对象,只是为派生类对象的基类部分创建了一个别名。*/Base& ref = derived;//2.基类的引用可以绑定到派生类对象ref.print();Base* pbase = &derived;//3.基类的指针可以指向派生类对象(向上转型)pbase->print();cout << " 基类向派生类转化" << endl;Base base1(100);Derived derived1(200, 300);//derived1 = base1;//error! 1.不能将基类对象赋值给派生类对象//等价转换的形式如下:ERROR!!!//Derived& operator=(const Derived & rhs);//derived1.operator=(base1);//不存在用户定义的从 "Base" 到 "const Derived" 的适当转换//const Derived& rhs = base1;//Derived& dref = base1; //error! 2.派生类的引用不能绑定到基类对象//Derived* pref = &base1;//error! 3.派生类的指针不能指向基类对象,只指向Base基类的前8个字节,后面的指针操纵了非法内存,有内存越界的风险//语法层面不支持向下转型 基类-->派生类 ,使用强制转换(本质上是不安全的)Derived* pderived1 = static_cast<Derived*>(&base1) ;//间接的表明了pderived2指向pderived1(可以认为是安全的)Derived* pderived2 = static_cast<Derived*>(&base1);test();return 0;
}
输出示例:
Base(double base = 0.0)
Derived(double = 0.0, double = 0.0)
Base::_base = 22.22
Base::_base = 22.22
~Derived()
~Base()
四、派生类间的复制控制
在继承体系中,复制控制(拷贝构造、赋值运算符)需要正确处理基类部分,否则可能导致资源泄漏或未定义行为。
要点:
- 在拷贝构造和赋值运算符中,必须显式调用基类的对应函数,否则基类部分不会被正确复制。
- 避免 资源泄露,在赋值运算符中先删除旧数据,再分配新数据。
- 析构函数要释放动态分配的资源,否则会导致内存泄漏。
//DerivedCopyControl1.cpp
#include <iostream>
#include <string.h>using namespace std;class Base
{friend std::ostream& operator<<(std::ostream& os, const Base& rhs);
public:Base():_pbase(nullptr){cout << "Base()" << endl;}Base(const char* pbase):_pbase(new char[strlen(pbase) + 1]){cout << "Base(const char* pbase)" << endl;strcpy_s(_pbase, strlen(pbase) + 1, pbase);}Base(const Base& rhs):_pbase(new char[strlen(rhs._pbase) + 1]()){cout << "Base(const Base& rhs)" << endl;strcpy_s(_pbase, strlen(rhs._pbase) + 1, rhs._pbase);}Base& operator=(const Base& rhs){cout << "Base& operator=(const Base& rhs)" << endl;if (this != &rhs){delete[] _pbase;_pbase = nullptr;_pbase = new char[strlen(rhs._pbase) + 1]();strcpy_s(_pbase, strlen(rhs._pbase) + 1, rhs._pbase);}return *this;}~Base(){cout << "~Base()" << endl;if (_pbase){delete[] _pbase;_pbase = nullptr;}}private:char* _pbase;
};std::ostream& operator<<(std::ostream& os, const Base& rhs)
{if (rhs._pbase){os << rhs._pbase;}return os;
}class Derived : public Base
{friend std::ostream& operator<<(std::ostream& os, const Derived& rhs);
public:Derived(const char* pbase,const char* pDerived):Base(pbase),_pDerived(new char[strlen(pDerived) + 1]){cout << "Derived(const char* pbase,const char* pDerived)" << endl;strcpy_s(_pDerived, strlen(pDerived) + 1, pDerived);}Derived(const Derived& rhs):_pDerived(new char[strlen(rhs._pDerived) + 1]()){cout << "Derived(const Derived& rhs)" << endl;strcpy_s(_pDerived, strlen(rhs._pDerived) + 1, rhs._pDerived);}Derived& operator=(const Derived& rhs){cout << "Derived& operator=(const Derived& rhs)" << endl;if (this != &rhs){delete[] _pDerived;_pDerived = nullptr;_pDerived = new char[strlen(rhs._pDerived) + 1]();strcpy_s(_pDerived, strlen(rhs._pDerived) + 1, rhs._pDerived);}return *this;}~Derived(){cout << "~Derived()" << endl;if (_pDerived){delete[] _pDerived;_pDerived = nullptr;}}private:char* _pDerived;
};std::ostream& operator<<(std::ostream& os, const Derived& rhs)
{//Base& ref = rhs;//error!将 "Base &" 类型的引用绑定到 "const Derived" 类型的初始值设定项时,限定符被丢弃const Base& ref = rhs;//正确写法os << ref << "," << rhs._pDerived;return os;
}void test()
{Derived derived("hello","world");cout << "derived = " << derived << endl;cout << endl;//用一个已经存在的对象去初始化一个刚刚创建的对象Derived derived2(derived);cout << "derived = " << derived << endl;cout << "derived2 = " << derived2 << endl;cout << endl;Derived derived3("cpp", "difficult");cout << "derived3 = " << derived3 << endl;cout << endl;//两个派生类对象之间进行赋值derived3 = derived;cout << "derived = " << derived << endl;cout << "derived3 = " << derived3 << endl;
}int main()
{test();return 0;
}
DerivedCopyControl2.cpp
版本的cpp文件是为了解决上一个版本(DerivedCopyControl1.cpp
)的潜在问题,主要问题如下:
- Base的拷贝构造函数和赋值运算符未处理源对象的_pbase为nullptr的情况,导致潜在崩溃。
- Derived的拷贝构造函数未调用Base的拷贝构造函数,导致基类部分未被正确复制。
- Derived的赋值运算符未调用Base的赋值运算符,导致基类部分未被正确赋值。
//DerivedCopyControl2.cpp
#include <iostream>
#include <string.h>using namespace std;class Base
{friend std::ostream& operator<<(std::ostream& os, const Base& rhs);
public:Base():_pbase(nullptr){cout << "Base()" << endl;}Base(const char* pbase):_pbase(new char[strlen(pbase) + 1]){cout << "Base(const char* pbase)" << endl;strcpy_s(_pbase, strlen(pbase) + 1, pbase);}/*Base(const Base& rhs):_pbase(new char[strlen(rhs._pbase) + 1]()){cout << "Base(const Base& rhs)" << endl;strcpy_s(_pbase, strlen(rhs._pbase) + 1, rhs._pbase);}*/// 拷贝构造函数Base(const Base& rhs) : _pbase(nullptr) {cout << "Base(const Base& rhs)" << endl;if (rhs._pbase) {_pbase = new char[strlen(rhs._pbase) + 1];strcpy_s(_pbase, strlen(rhs._pbase) + 1, rhs._pbase);}}/*Base& operator=(const Base& rhs){cout << "Base& operator=(const Base& rhs)" << endl;if (this != &rhs){delete[] _pbase;_pbase = nullptr;_pbase = new char[strlen(rhs._pbase) + 1]();strcpy_s(_pbase, strlen(rhs._pbase) + 1, rhs._pbase);}return *this;}*/// 赋值运算符Base& operator=(const Base& rhs) {cout << "Base& operator=(const Base& rhs)" << endl;if (this != &rhs) {delete[] _pbase;_pbase = nullptr;if (rhs._pbase) {//base = new char[strlen(rhs._pbase) + 1]();//使用new char[size]()会进行零初始化,随后strcpy_s会覆盖这些零。此举虽无害但影响性能。_pbase = new char[strlen(rhs._pbase) + 1]; // 无需()strcpy_s(_pbase, strlen(rhs._pbase) + 1, rhs._pbase);}}return *this;}~Base(){cout << "~Base()" << endl;if (_pbase){delete[] _pbase;_pbase = nullptr;}}private:char* _pbase;
};std::ostream& operator<<(std::ostream& os, const Base& rhs)
{if (rhs._pbase){os << rhs._pbase;}return os;
}class Derived : public Base
{friend std::ostream& operator<<(std::ostream& os, const Derived& rhs);
public:Derived(const char* pbase, const char* pDerived):Base(pbase), _pDerived(new char[strlen(pDerived) + 1]){cout << "Derived(const char* pbase,const char* pDerived)" << endl;strcpy_s(_pDerived, strlen(pDerived) + 1, pDerived);}/*Derived(const Derived& rhs):_pDerived(new char[strlen(rhs._pDerived) + 1]()){cout << "Derived(const Derived& rhs)" << endl;strcpy_s(_pDerived, strlen(rhs._pDerived) + 1, rhs._pDerived);}*/// 拷贝构造函数Derived(const Derived& rhs): Base(rhs), // 调用基类拷贝构造_pDerived(new char[strlen(rhs._pDerived) + 1]) {cout << "Derived(const Derived& rhs)" << endl;strcpy_s(_pDerived, strlen(rhs._pDerived) + 1, rhs._pDerived);}/*Derived& operator=(const Derived& rhs){cout << "Derived& operator=(const Derived& rhs)" << endl;if (this != &rhs){delete[] _pDerived;_pDerived = nullptr;_pDerived = new char[strlen(rhs._pDerived) + 1]();strcpy_s(_pDerived, strlen(rhs._pDerived) + 1, rhs._pDerived);}return *this;}*/// 赋值运算符Derived& operator=(const Derived& rhs) {if (this != &rhs) {Base::operator=(rhs); // 调用基类赋值运算符delete[] _pDerived;_pDerived = new char[strlen(rhs._pDerived) + 1];strcpy_s(_pDerived, strlen(rhs._pDerived) + 1, rhs._pDerived);}return *this;}~Derived(){cout << "~Derived()" << endl;if (_pDerived){delete[] _pDerived;_pDerived = nullptr;}}private:char* _pDerived;
};std::ostream& operator<<(std::ostream& os, const Derived& rhs)
{//Base& ref = rhs;//error!将 "Base &" 类型的引用绑定到 "const Derived" 类型的初始值设定项时,限定符被丢弃const Base& ref = rhs;//正确写法os << ref << rhs._pDerived;return os;
}void test()
{Derived derived("hello", "world");cout << "derived = " << derived << endl;cout << endl;//用一个已经存在的对象去初始化一个刚刚创建的对象Derived derived2(derived);cout << "derived = " << derived << endl;cout << "derived2 = " << derived2 << endl;cout << endl;Derived derived3("cpp", "difficult");cout << "derived3 = " << derived3 << endl;cout << endl;//两个派生类对象之间进行赋值derived3 = derived;cout << "derived = " << derived << endl;cout << "derived3 = " << derived3 << endl;}int main()
{test();return 0;
}
总结:
1、如果基类实现了拷贝构造函数或赋值运算符函数,但是派生类没有实现拷贝构造函数或赋值运算符函数,那么在将一个已经存在的派生类对象初始化一个刚刚创建的派生类对象,或者将两个派生类对象进行赋值,那么派生部分会执行缺省行为,而基类部分会执行基类的拷贝构造函数或者赋值运算符函数。
2、如果基类实现了拷贝构造函数或赋值运算符函数,并且派生类也实现拷贝构造函数或赋值运算符函数,那么在将一个已经存在的派生类对象初始化一个刚刚创建的派生类对象,或者将两个派生类对象进行赋值,那么派生部分会执行派生类自己的拷贝构造函数或者赋值运算符函数,而基类部分不会自动执行基类的拷贝构造函数或者赋值运算符函数,除非显示在派生类中调用基类的拷贝与赋值。
五、总结
1. base = derived
(对象赋值,发生切片)
Base base = derived; // 对象赋值,发生切片(slicing)
base.print(); // 调用 Base::print()
特点:
- 对象切片(Object Slicing):
derived
的派生类部分被丢弃,只保留Base
部分,base
是一个全新的Base
对象。 - 不推荐:除非你明确只需要基类部分,否则通常应该避免这种写法,因为它丢失了派生类的信息。
2. Base& ref = derived
(引用绑定,无切片)
Base& ref = derived; // 引用绑定,无切片
ref.print(); // 如果 print() 是虚函数,调用 Derived::print()
特点:
✅ 优点:
- 无对象切片:
ref
只是derived
的基类部分的引用,不会复制数据,派生类信息仍然完整。 - 支持多态:如果
Base::print()
是virtual
的,调用ref.print()
会正确调用Derived::print()
(动态绑定)。 - 更高效:避免了不必要的拷贝(特别是当
Base
较大时)。
❌ 缺点:
- 只能访问基类成员:通过
ref
无法直接访问Derived
的特有方法(如derived.extra()
)。 - 必须确保
derived
的生命周期:如果derived
被销毁,ref
会变成悬空引用(dangling reference),导致未定义行为(UB)。
3. 推荐程度
写法 | 是否推荐 | 适用场景 |
---|---|---|
Base base = derived; (赋值) | ❌ 不推荐 | 除非明确只需要基类部分 |
Base& ref = derived; (引用) | ✅ 推荐 | 需要多态、避免切片时 |
Base* ptr = &derived; (指针) | ✅ 更推荐 | 更灵活,可以存储、传递 |
更推荐的替代方案:Base*
(指针)
Base* ptr = &derived; // 基类指针指向派生类对象
ptr->print(); // 多态调用 Derived::print()
优点:
- 比引用更灵活(可以设为
nullptr
,可以修改指向的对象)。 - 常用于运行时多态(如工厂模式、容器存储不同派生类对象)。
4. 要点
Base& ref = derived
是推荐的,因为它避免了切片并支持多态,但必须确保derived
的生命周期足够长。Base* ptr = &derived
更推荐,因为指针更灵活,适用于更多场景(如存储在不同容器中)。Base base = derived
不推荐,除非你明确只需要基类部分(但通常应该使用组合而非继承)。
最佳实践
// ✅ 推荐:指针方式(更灵活)
Base* ptr = &derived;
ptr->print();// ✅ 也可以:引用方式(适用于局部作用域)
Base& ref = derived;
ref.print();// ❌ 不推荐:赋值方式(切片问题)
Base base = derived;
base.print();
如果你需要在函数参数中传递派生类对象,通常使用 const Base&
(避免拷贝)或 Base*
(更灵活)。
相关文章:
C++11QT复习 (十)
基类与派生类之间的转换 **Day7-4 基类与派生类之间的转换****一、问题回顾****二、基类与派生类间的转换****1. 类型适应(Upcasting)****2. 逆向转换(Downcasting)** **三、代码示例****四、派生类间的复制控制****五、总结****1…...
Linux——冯 • 诺依曼体系结构操作系统初识
目录 1. 冯 • 诺依曼体系结构 1.1 冯•诺依曼体系结构推导 1.2 内存提高冯•诺依曼体系结构效率的方法 1.3 理解数据流动 2. 初步认识操作系统 2.1 操作系统的概念 2.2 设计OS的目的 3. 操作系统的管理精髓 1. 冯 • 诺依曼体系结构 1.1 冯•诺依曼体系结构推导 计算…...
JVM 学习计划表(2025 版)
JVM 学习计划表(2025 版) 📚 基础阶段(2 周) 1. JVM 核心概念 JVM 作用与体系结构 理解 JVM 在 Java 跨平台运行中的核心作用,掌握类加载子系统、运行时数据区、执行引擎的交互流程内存结构与数据存…...
arm_mat_init_f32用法 dsp库
arm_mat_init_f32 是 CMSIS DSP 库中的一个函数,用于初始化一个浮点矩阵结构体。以下是其使用方法: 函数原型 c复制 void arm_mat_init_f32(arm_matrix_instance_f32 * S,uint16_t nRows,uint16_t nColumns,float32_t * pData ); 参数说明 S…...
【蓝桥杯14天冲刺课题单】Day3
1. 题目链接:1025 答疑 贪心类型的题目做法很简单,只需要保证局部解最优即可保证整体解最优。 这里的思路就是第i个学生前面的人答疑所用的时间最短,那么他所发送短信的时间节点越小。这道题目有个需要注意的点是:要先将前i-1个…...
基于开源AI大模型与S2B2C模式的线下服务型门店增长策略研究——以AI智能名片与小程序源码技术为核心
摘要 在传统零售行业中,商品零售可通过无限流量实现销量增长,但服务型门店(如餐饮、医疗、美容等)因受限于地理位置、服务承载能力及非标化服务特性,需从“流量驱动”转向“复购驱动”增长模式。本研究以“开源AI大…...
批量修改图像命名
打开存放图片的文件 ctrA全选 找到功能栏上的三个点的位置,点击选择复制路径 打开一个Excel表格 将复制的图片路径复制到Excel表格中 选中刚复制的图片路径,点击选择数据->分列->分列 在打开的窗口中选中分隔符号,在点击下一步 选中…...
linux-- 0. C语言过、Java半静对、Python纯动和C++对+C
学习目标: java,CPYTHONC 学习内容: java,CPYTHONC 目录 学习目标: 学习内容: java 纯解释型语言(如 Python)的对比 C语言与Java的核心区别 java,C PYTHON C 学习时间: 学习产出…...
程序化广告行业(50/89):Cookie映射技术深度剖析
程序化广告行业(50/89):Cookie映射技术深度剖析 大家好!一直以来,我都希望能和大家一起深入探索程序化广告行业,共同学习进步。在之前的分享中,我们已经了解了程序化广告的很多关键内容&#x…...
大语言模型智体的综述:方法论、应用和挑战(下)
25年3月来自北京大学、UIC、广东大亚湾大学、中科院计算机网络信息中心、新加坡南阳理工、UCLA、西雅图华盛顿大学、北京外经贸大学、乔治亚理工和腾讯优图的论文“Large Language Model Agent: A Survey on Methodology, Applications and Challenges”。 智体时代已经到来&a…...
【操作系统】Linux进程管理和调试
在 Linux 中,可以通过以下方法查看 PID(进程ID)对应的进程名称和详细信息: 1. 使用 ps 命令(最直接) ps -p <PID> -o pid,comm,cmd示例: ps -p 1234 -o pid,comm,cmd输出: P…...
C++---RAII模式
一、RAII模式概述 1. 定义 RAII(Resource Acquisition Is Initialization)即资源获取即初始化,是C中用于管理资源生命周期的一种重要编程模式。其核心在于将资源的获取和释放操作与对象的生命周期紧密绑定。当对象被创建时,资源…...
Clion刷题攻略-配置Cmake
使用Clion刷题,在一个项目中创建多个main函数,每一个文件对应一道题目,将Clion作为题目管理系统使用,并且cpp文件允许使用中文名,exe文件统一输出到runtime目录,防止污染根目录,CmakeLists文件如…...
DEBUG:file命令
file 命令详解 file 是 Linux/Unix 系统中用于检测文件类型的实用工具。它通过检查文件的**魔数(magic number)**和内容结构来判断文件类型,而不是依赖文件扩展名。 1. 基本语法 file [选项] 文件名... 常用选项 选项说明-b (--brief)简洁…...
hackmyvn-casino
arp-scan -l nmap -sS -v 192.168.255.205 目录扫描 dirsearch -u http://192.168.255.205/ -e * gobuster dir -u http://192.168.255.205 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php -b 301,401,403,404 80端口 随便注册一个账号 玩游戏时的…...
Elasticsearch笔记
官网 https://www.elastic.co/docs 简介 Elasticsearch 是一个分布式、开源的搜索引擎,专门用于处理大规模的数据搜索和分析。它基于 Apache Lucene 构建,具有实时搜索、分布式计算和高可扩展性,广泛用于 全文检索、日志分析、监控数据分析…...
在Windows下使用Docker部署Nacos注册中心(基于MySQL容器)
需要两个容器Nacos容器和MySQL容器,MySQL容器专注数据存储,Nacos容器专注服务发现/配置管理 准备工作 确保已安装Docker Desktop for Windows确保已启用WSL 2(推荐)或Hyper-V确保Docker服务正在运行 部署步骤 1. 拉取所需镜像 # 拉取MySQL镜像(这里…...
去中心化自治组织(DAO):革新未来治理的下一站
去中心化自治组织(DAO):革新未来治理的下一站 引言 去中心化自治组织(DAO)的诞生,像是互联网时代的一道新曙光。它打破了传统组织的等级壁垒,以去中心化和智能合约为核心,让社区成员能够直接参与决策并共享收益。从NFT社区到投资基金,DAO的应用场景正以前所未有的速…...
ideal自动生成类图的方法
在 IntelliJ IDEA 中,“**在项目资源管理器中选择以下类**” 是指通过 **项目资源管理器(Project Tool Window)** 找到并选中你需要生成类图的类文件(如 .java 文件),然后通过右键菜单或快捷键操作生成类图…...
爬虫获取1688关键字搜索接口的实战指南
在当今电商行业竞争激烈的环境下,数据的重要性不言而喻。1688作为国内领先的B2B电商平台,拥有海量的商品信息,这些数据对于商家的市场分析、选品决策、价格策略制定等都有着重要的价值。本文将详细介绍如何通过爬虫技术获取1688关键字搜索接口…...
视频设备轨迹回放平台EasyCVR渡口码头智能监控系统方案,确保港口安全稳定运行
一、背景 近年来,随着水上交通运输业的快速发展,辖区内渡口码头数量持续增加,船舶运营规模不断扩大,各类船舶活动频繁,给水上交通安全监管带来了巨大挑战。近期发生的多起村民使用无证木船捕鱼导致的伤亡事故…...
使用 Sales_data 类实现交易合并(三十)
1. Sales_data 类定义 假设 Sales_data 类定义在头文件 Sales_data.h 中,其基本定义如下: // Sales_data.h #ifndef SALES_DATA_H #define SALES_DATA_H#include <string>struct Sales_data {std::string bookNo; // ISBN 编号unsigned uni…...
电力系统惯量及其作用解析
电力系统中的惯量是指由同步发电机的旋转质量提供的惯性,用于抵抗系统频率变化的能力。其核心作用及要点如下: 1. 物理基础 转动惯量:同步发电机的转子具有质量,其转动惯量()决定了转子抵抗转速变化的能力…...
HNSW(Hierarchical Navigable Small World,分层可导航小世界)用来高效搜索高维向量的最近邻
HNSW(Hierarchical Navigable Small World,分层可导航小世界)是一种用于 高效最近邻搜索(ANN, Approximate Nearest Neighbors) 的索引结构,专门用于在 高维向量(比如文本、图像、音频的嵌入向量…...
STM32 CAN学习(一)
CAN总线应用最多的是汽车领域。 CAN(Controller Area Network)控制器 局域 网 局域网:把几台电脑连接到一台路由器上,这几台电脑就可以进行通讯了。 控制器在汽车中的专业术语叫做ECU(Electronic Control Unit&…...
高效内存位操作:如何用C++实现数据块交换的性能飞跃?
「性能优化就像考古,每一层都有惊喜」—— 某匿名C工程师 文章目录 问题场景:当内存操作成为性能瓶颈性能深潜:揭开内存操作的面纱内存访问的三重代价原始方案的性能缺陷 性能突破:从编译器视角重构代码方案一:指针魔法…...
Spring Boot向Vue发送消息通过WebSocket实现通信
后端实现步骤 添加Spring Boot WebSocket依赖配置WebSocket端点和消息代理创建控制器,使用SimpMessagingTemplate发送消息 前端实现步骤 安装sockjs-client和stompjs库封装WebSocket连接工具类在Vue组件中建立连接,订阅主题 详细实现步骤 后端&…...
USB转串口数据抓包--Bus hound
Bus Hound是一款强大的总线分析工具。 Bus Hound 支持哪些设备 ? 所有的 IDE , SCSI , USB 和 1394 设备都得到支持,包括磁盘驱动器,鼠 标、扫描仪,网络摄像头,等等。只要是枚举成以上所列的总线类型的…...
Android 使用CameraX实现预览、拍照、录制视频(Java版)
Android 官方关于相机的介绍如下: https://developer.android.google.cn/media/camera/get-started-with-camera?hlzh_cn 一、开始使用 Android 相机 Android相机一般包含前置摄像头和后置摄像头,使用相机可以开发一系列激动人心的应用,例…...
【已解决】Javascript setMonth跨月问题;2025-03-31 setMonth后变成 2025-05-01
文章目录 bug重现解决方法:用第三方插件来实现(不推荐原生代码来实现)。项目中用的有dayjs。若要自己实现,参考 AI给出方案: bug重现 今天(2025-04-01)遇到的一个问题。原代码逻辑大概是这样的…...
DeepSeek技术架构解析:MLA多头潜在注意力
一、前言 我们上一篇已经讲了 DeepSeek技术架构解析:MoE混合专家模型 这一篇我们来说一说DeepSeek的创新之一:MLA多头潜在注意力。 MLA主要通过优化KV-cache来减少显存占用,从而提升推理性能。我们知道这个结论之前,老周带大家…...
02.02、返回倒数第 k 个节点
02.02、[简单] 返回倒数第 k 个节点 1、题目描述 实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。 2、题解思路 本题的关键在于使用双指针法,通过两个指针(fast 和 slow),让 fast 指针比 slow 指针…...
剑指Offer(数据结构与算法面试题精讲)C++版——day2
剑指Offer(数据结构与算法面试题精讲)C++版——day2 题目一:只出现一次的数据题目二:单词长度的最大乘积题目三:排序数组中的两个数字之和题目一:只出现一次的数据 一种很简单的思路是,使用数组存储出现过的元素,比如如果0出现过,那么arr[0]=1,但是有个问题,题目中没…...
nginx的自动跳转https
mkdir /usr/local/nginx/certs/ 创建一个目录 然后用openssl生成证书 编辑nginx的配置文件 自动跳转成功 做一个优化,如果访问的时候后面加了其他的uri也一起自动跳转了...
正则表达式(Regular Expression,简称 Regex)
一、5w2h(七问法)分析正则表达式 是的,5W2H 完全可以应用于研究 正则表达式(Regular Expressions)。通过回答 5W2H 的七个问题,我们可以全面理解正则表达式的定义、用途、使用方法、适用场景等,…...
Windows下在IntelliJ IDEA 使用 Git 拉取、提交脚本出现换行符问题
文章目录 背景问题拉取代码时提交代码时 问题原因解决方案1.全局配置 Git 的换行符处理策略2.在 IntelliJ IDEA 中配置换行符3.使用 .gitattributes 文件 背景 在 Windows 系统下使用 IntelliJ IDEA 进行 Git 操作(如拉取和提交脚本)时,经常…...
Python 实现的运筹优化系统代码详解(整数规划问题)
一、引言 在数学建模的广袤领域里,整数规划问题占据着极为重要的地位。它广泛应用于工业生产、资源分配、项目管理等诸多实际场景,旨在寻求在一系列约束条件下,使目标函数达到最优(最大或最小)且决策变量取整数值的解决…...
conda安装python 遇到 pip is configured with locations that require TLS/SSL问题本质解决方案
以前写了一篇文章,不过不是专门为了解决这个问题的,但是不能访问pip install 不能安装来自https 协议的包问题几乎每次都出现,之前解决方案只是治标不治本 https://blog.csdn.net/wangsenling/article/details/130194456https…...
嘿嘿,好久不见
2025年4月2日,6~22℃,一般 遇见的事:参加了曲靖的事业单位D类考试。 感受到的情绪:考场一半的人都没有到位,这路上你到了可能都会受到眷顾。 反思:这路上很难,总有人会提前放弃,不…...
virsh 的工作原理
virsh是用于管理虚拟化环境中的客户机和Hypervisor的命令行工具。它基于libvirt管理API构建,与virt-manager等工具类似,都是通过调用libvirt API来实现虚拟化的管理。virsh是完全在命令行文本模式下运行的用户态工具,因此它是系统管理员通过脚…...
Qt实现HTTP GET/POST/PUT/DELETE请求
引言 在现代应用程序开发中,HTTP请求是与服务器交互的核心方式。Qt作为跨平台的C框架,提供了强大的网络模块(QNetworkAccessManager),支持GET、POST、PUT、DELETE等HTTP方法。本文将手把手教你如何用Qt实现这些请求&a…...
(041)05-01-自考数据结构(20331)树与二叉树大题总结
实际考试中,计算题约占40%,推理题约占30%,算法设计题约占30%。建议重点练习遍历序列相关的递归分治解法, 知识拓扑 知识点介绍 一、计算题类型与解法 1. 结点数量计算 题型示例: 已知一棵完全二叉树的第6层有8个叶子结点,求该二叉树最多有多少个结点? 解法步骤: 完…...
WPS JS宏编程教程(从基础到进阶)-- 第三部分:JS宏编程语言开发基础
第三部分:JS宏编程语言开发基础 @[TOC](第三部分:JS宏编程语言开发基础)**第三部分:JS宏编程语言开发基础**1. 变量与数据类型**变量声明:三种方式****示例代码****数据类型判断****实战:动态处理单元格类型**2. 运算符全解析**算术运算符****易错点:字符串拼接 vs 数值相…...
迈向云原生:理想汽车 OLAP 引擎变革之路
在如今数据驱动的时代,高效的分析引擎对企业至关重要。理想汽车作为智能电动汽车的领军企业,面临着海量数据分析的挑战。本文将展开介绍理想汽车 OLAP 引擎从存算一体向云原生架构演进的变革历程,以及在此过程中面临的挑战,以及是…...
Spark,HDFS客户端操作
hadoop客户端环境准备 找到资料包路径下的Windows依赖文件夹,拷贝hadoop-3.1.0到非中文路径(比如d:\hadoop-3.1.0) ① 打开环境变量 ② 在下方系统变量中新建HADOOP_HOME环境变量,值就是保存hadoop的目录。 效果如下: ③ 配置Path…...
QuecPython 的 VScode 环境搭建和使用教程
为方便开发者使用 VSCode 开发 QuecPython,QuecPython 团队特推出了名为 QuecPython 的 VSCode 插件。 插件目前支持的功能有: 固件烧录REPL 命令交互代码补全文件传输文件系统目录树运行指定脚本文件 目前支持所有QUecPython系列模组。 插件安装 点…...
Linux Vim 编辑器的使用
Vim 编辑器的使用 一、安装及介绍二、基础操作三、高级功能四、配置与插件 一、安装及介绍 Vim是一款强大且高度可定制的文本编辑器,相当于 Windows 中的记事本。具备命令、插入、底行等多种模式。它可通过简单的键盘命令实现高效的文本编辑、查找替换、分屏操作等…...
Java 基础-28- 多态 — 多态下的类型转换问题
在 Java 中,多态(Polymorphism)是面向对象编程的核心概念之一。多态允许不同类型的对象通过相同的方法接口进行操作,而实际调用的行为取决于对象的实际类型。虽然多态提供了极大的灵活性,但在多态的使用过程中…...
机器学习中的自监督学习概述与实现过程
概述 机器学习中有四种主要学习方式: 监督式学习 (Supervised Learning):这种学习方式通过使用带有标签的数据集进行训练,目的是使机器能够学习到数据之间的关联性,并能够对新的、未见过的数据做出预测或分类。应用领域包括语音识…...
AI Agent开发大全第十四课-零售智能导购智能体的RAG开发理论部分
开篇 经过前面的一些课程,我们手上已经积累了各种LLM的API调用、向量库的建立和使用、embedding算法的意义和基本使用。 这已经为我们具备了开发一个基本的问答类RAG的开发必需要素了。下面我们会来讲一个基本问答类场景的RAG,零售中的“智能导购”场景。 智能导购 大家先…...