【C++ 第二十一章】特殊类的设计(学习思路)

1.请设计一个类,不能被拷贝
设计思路
拷贝只会使用在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。
C++98 的做法
将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可。(不定义:则拷贝操作无法实际的实现;设置成私有:避免公有被调用出来实现)
class A
{
private:A(const A&);A& operator=(const A&);
};
原因:
- 设置成私有:如果只声明没有设置成private,用户自己如果在类外定义了,就可以不
能禁止拷贝了 - 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。
C++11 的做法
C++11 扩展 delete 的用法,delete 除了释放 new 申请的资源外,如果在默认成员函数后加上 =delete,表示让编译器删除掉该默认成员函数。
class A
{A(const A&) = delete;A& operator=(const A&) = delete;
};
2.请设计一个类,只能在堆上创建对象
方法一:构造函数私有化
- 构造、拷贝和赋值私有化:将类的构造函数私有,拷贝构造和赋值声明成私有。防止别人调用拷贝在栈上生成对象。或者将构造私有化,将拷贝和赋值 delete 禁用
- 同一提供对外接口:提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
这个有点封装的味道了,将一些功能封装起来,自己提供对外接口,就可以控制外界可以使用的功能(控制权限)
为什么要设置成静态函数:
关于为什么对外功能接口要设置成静态函数?
思路:
1、首先,我们将构造函数私有化,拷贝构造和赋值 delete 禁用掉,外界就不可以调用这几个函数在栈上构造一个对象
2、其次,该对外功能接口函数 也是成员函数,调用一个成员函数需要一个对象来调用,但是我们这里都没有创建对象,正等着该功能函数来创建对象呢?何来一个对象?
3、这里就产生:先有鸡,还是先有蛋的问题
4、因此就需要避免使用通过对象调用的方式
:可以设置成 静态成员,在外部通过类域指定调用(这时静态成员的特性,就无需通过对象调用)
class HeapOnly
{
public:// 设置成静态函数:static HeapOnly* CreateObj() {return new HeapOnly;}// 将拷贝与赋值重载都使用 delete 禁用掉HeapOnly(const HeapOnly&) = delete;HeapOnly& operator=(const HeapOnly&) = delete;
private:// 将构造函数设置成私有:避免外部调用,在栈上构造对象HeapOnly() {};
};int main() {HeapOnly* p = HeapOnly::CreateObj(); // 通过类域调用类的静态成员return 0;
}
方法二:析构函数私有化
注释都解释清楚了
// 析构函数私有化
class HeapOnly
{
public:void Destroy() {delete this;}
private:// 将析构函数设置成私有~HeapOnly() {};
};int main() {HeapOnly obj; // 报错:创建一个类对象,销毁时会自动调用析构,但是这里调用不了(因为析构函数被"禁用"了),因此也不允许这个对象被创建出来HeapOnly* p = new HeapOnly(); // 不报错:new 出来的对象,不会自动调用析构,需要手动 deletedelete p; //报错:调用不了析构 p->Destroy(); // 通过类中的功能接口销毁对象return 0;
}
3.请设计一个类,只能在栈上创建对象
这个比限制只能在堆上,还要麻烦一些些
实现第一步:构造函数私有化
class StackOnly
{
public:// 对外功能接口:该函数可以调用私有成员,构造函数,创建对象,返回匿名对象static StackOnly CreateObj() {return StackOnly();}private:// 将构造函数设置成私有:避免外部通过 new,在堆上创建对象StackOnly() {};
};int main() {StackOnly obj1 = StackOnly::CreateObj();StackOnly* p_obj2 = new StackOnly(obj1); return 0;
}
禁掉了 构造函数,还可以走拷贝构造的路:通过CreateObj() 函数,先创建一个对象出来,再 拷贝+new 生成一个新对象
因此,还要完善
实现第二步:拷贝与赋值用 delete 禁用掉
class StackOnly
{
public:// 对外功能接口:该函数可以调用私有成员,构造函数,创建对象,返回匿名对象static StackOnly CreateObj() {return StackOnly();}// 将拷贝与赋值重载都使用 delete 禁用掉StackOnly(const StackOnly&) = delete;
private:// 将构造函数设置成私有:避免外部通过 new,在堆上创建对象StackOnly() {};
};int main() {StackOnly obj1 = StackOnly::CreateObj();//StackOnly* p_obj2 = new StackOnly(obj1); return 0;
}
但是!
将 拷贝构造禁用掉:会导致 CreateObj 函数失效,因为该成员函数返回的是局部对象,需要拷贝生成临时对象,而拷贝构造失效,导致生成失败
因此,还要完善
实现第三步:operator new 用 delete 禁用掉
可以尝试从 new 的本质入手:new = 全局函数 operator new(malloc+抛异常)+ 构造
我们若自己显式实现 operator new ,则 new 优先使用我们自己的
因此可以在这里将 new 的 operator new 禁掉,使得 new 无法调用
// 只能在栈上创建对象
class StackOnly
{
public:// 该函数可以调用私有成员:构造函数,创建对象,返回匿名对象static StackOnly CreateObj() {return StackOnly();}// 可以使用/*void* operator new(size_t size) {return malloc(size*sizeof(StackOnly));}*/void* operator new(size_t size) = delete;void operator delete(void* p) = delete;
private:// 将构造函数设置成私有:避免外部通过 new,在堆上创建对象StackOnly() {};
};int main() {StackOnly obj1 = StackOnly::CreateObj();StackOnly* p_obj2 = new StackOnly(obj1); // 报错return 0;
}
但是问题又回来了:
只要没有将 拷贝构造禁用掉,还是可以通过拷贝构造创建一个在静态区的对象
StackOnly obj1 = StackOnly::CreateObj();static StackOnly obj3(obj1); // 不报错
同时,还可以通过 移动构造 创建静态区的对象
StackOnly obj1 = StackOnly::CreateObj();static StackOnly obj4(move(obj1));
这里为什么创建静态区的对象? 仅仅是将栈区对象区别开
实现最终大法:直接使用返回对象进行操作
既然我们的目的是设计一个只能在栈上对象的类,
我们直接从这里思考,我们先将拷贝、赋值、移动构造私有化 或 delete 禁用。
既然直接将 CreateObj() 函数返回的匿名对象拷贝给新对象会触发拷贝或移动构造
StackOnly obj1 = StackOnly::CreateObj(); // 这里会触发拷贝或移动构造
干脆别拷贝给新对象,而是直接使用这个 匿名对象进行操作
(其实这个方法有点取巧,但是不也是达到了题目要求吗?😎)
int main() {StackOnly::CreateObj().Print(); // 直接使用该返回对象进行操作//StackOnly obj1 = StackOnly::CreateObj(); // 会触发拷贝或移动构造//StackOnly* p_obj2 = new StackOnly(obj1); // 报错:operator new 和 拷贝构造 不能用了//StackOnly obj3(obj1); // 报错:拷贝构造 不能用了//static StackOnly obj4(move(*obj1)); // 报错:拷贝构造 和 移动构造 不能用了//static StackOnly obj2(obj1);return 0;
}
4.请设计一个类,不能被继承
C++98 方式
C++98 中构造函数私有化,派生类中调不到基类的构造函数,则无法继承
class A
{
private:A() {};
};
C++11 方式
使用 final 关键字
final 关键字,final修饰类,表示该类不能被继承。
class A final
{
private:A() {};
};
5.请设计一个类,只能创建一个对象(单例模式)
5.1 设计模式:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。为什么会产生设计模式这样的东西呢?就像人类历史发展会产生兵法。最开始部落之间打仗时都是人拼人的对砍。后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后来孙子就总结出了《孙子兵法》。孙子兵法也是类似。
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
我们之前其实已经接触过一些设计模式了,比如迭代器模式、适配器/配接器模式
下面我们要学习的是设计模式中的 单例模式
5.2 单例模式:
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
单例模式有两种实现模式:饿汉模式 和 懒汉模式
5.3 饿汉模式
就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。(即程序一开始就实例化一个该类对象给你了)
为什么叫做饿汉?:饿汉就好比你放学饿着肚子回家,在你回家前妈妈就已经准备好饭菜给你了
设计思路:
1、构造函数私有化。
2、将 拷贝构造、移动构造、赋值重载 封死:确保我们只有 GetInstance() 可以放出去唯一一个实例化对象。
3、创建一个自己这个类的静态成员对象:一个类的静态成员只能创建一个,而且static数据会在程序启动时创建好(刚好符合 饿汉模式 的理念)
// 单例模式:一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
class InfoMgr
{
public:// 只有这个函数可以向外提供唯一一个实例化对象static InfoMgr& GetInstance() {return _ins;}void Print() {cout << _ip << '\n';cout << _port << '\n';cout << _buffSize << '\n';}// 将 拷贝构造、移动构造、赋值重载 封死:确保我们只有 GetInstance() 可以放出去唯一一个实例化对象InfoMgr(const InfoMgr&) = delete;InfoMgr(InfoMgr&&) = delete;InfoMgr& operator=(const InfoMgr&) = delete;
private:// 将构造函数私有化:外部无法直接构造该类对象InfoMgr() {cout << "InfoMgr()" << '\n';}private:string _ip = "127.0.0.1";int _port = 80;size_t _buffSize = 1024 * 1024;// 这不能说是在类中创建一个自己,否则就套娃乱透了// 静态成员不存储在一个类对象里面static InfoMgr _ins;
};
InfoMgr InfoMgr::_ins;int main() {// 调试程序可以发现:调试还没有开始走就已经打印 "InfoMgr()" ,说明 在main函数程序执行前,对象就已经构造好了(这是因为该对象是 static,全局域)InfoMgr::GetInstance().Print();return 0;
}
饿汉模式的缺陷
如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好。
由于饿汉模式的对象在 main 函数前就被创建,所以它不存在线程安全问题,但是它也存在一些缺点:
1、多个饿汉模式的单例,某个对象初始化内容较多(读文件),会导致程序启动慢
2、A 和 B 两个饿汉,对象初始化存在依赖关系,要求A先初始化,B再初始化,饿汉无法保证其初始化顺序
5.4 懒汉模式
如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢,
这些就是 饿汉模式的缺陷。 所以这种情况使用懒汉模式(延迟加载)更好。
饿汉模式的特点就是先创建好对象,这也容易引发一些问题
懒汉模式 可以解决这个问题:不先创建对象,而是需要时再创建对象
这样就可以按需创建,即你要吃的东西,我不提前给你准备好,只会在你需要吃时再做,这就是懒汉
懒汉模式写法一:定义类对象指针
在 main 函数中,程序一般都会按顺序执行(不像懒汉模式中全局变量执行顺序不定),而且按需调用即可,这样也可以解决 懒汉模式中的 依赖关系的先后问题
// 懒汉模式
class InfoMgr
{
public:// 若对象指针为 nullptr,就给你 new 一个对象// 若不为空,就返回该对象给你static InfoMgr& GetInstance() {if (_pIns == nullptr) {_pIns = new InfoMgr();}return *_pIns;}void Print() {cout << _ip << '\n';cout << _port << '\n';cout << _buffSize << '\n';}// 将 拷贝构造、移动构造、赋值重载 封死:确保我们只有 GetInstance() 可以放出去唯一一个实例化对象InfoMgr(const InfoMgr&) = delete;InfoMgr(InfoMgr&&) = delete;InfoMgr& operator=(const InfoMgr&) = delete;
private:// 将构造函数私有化:外部无法直接构造该类对象InfoMgr() {cout << "InfoMgr()" << '\n';}private:string _ip = "127.0.0.1";int _port = 80;size_t _buffSize = 1024 * 1024;// 这不能说是在类中创建一个自己,否则就套娃乱透了// 静态成员不存储在一个类对象里面static InfoMgr* _pIns;
};
InfoMgr* InfoMgr::_pIns;int main() {// 调试程序可以发现:类里面的那个对象是在 GetInstance() 函数调用时创建的InfoMgr::GetInstance().Print();return 0;
}
有没有发现 懒汉模式存在一个问题:该模式中的对象是 new 出来的,就需要手动 delete 释放
而我们上面的类中,默认的析构只会将 _pIns 这个指针置空,而不会 delete 指向的资源,相当于 ”浅析构“,会造成内存泄漏
实际上,只有单例对象内存泄漏问题并没有这么严重
如果想要delete,这里有个很好的方法:定义内部类对象,当本项目程序结束后,该对象销毁会调用自己的析构函数,我们就可以在析构函数里面设置 delete 相关程序
这其实是一种解决问题的 思想:自己类无法做到的事,可以定义内部类,利用类的特性间接完成一些功能
// 定义一个内部类:用于析构单例对象
class DestroyIns
{public:~DestroyIns() {if (InfoMgr::_pIns != nullptr) {delete InfoMgr::_pIns;cout << "delete InfoMgr::_pIns;" << '\n';}}
};InfoMgr::DestroyIns desIns; // 全局对象:程序结束后会销毁,自动调用析构函数,则会执行析构函数里面 delete 的程序
应用进去
// 懒汉模式
class InfoMgr
{
public:// 若对象指针为 nullptr,就给你 new 一个对象// 若不为空,就返回该对象给你static InfoMgr& GetInstance() {if (_pIns == nullptr) {_pIns = new InfoMgr();}return *_pIns;}void Print() {cout << _ip << '\n';cout << _port << '\n';cout << _buffSize << '\n';}// 将 拷贝构造、移动构造、赋值重载 封死:确保我们只有 GetInstance() 可以放出去唯一一个实例化对象InfoMgr(const InfoMgr&) = delete;InfoMgr(InfoMgr&&) = delete;InfoMgr& operator=(const InfoMgr&) = delete;// 定义一个内部类:用于析构单例对象class DestroyIns{public:~DestroyIns() {if (InfoMgr::_pIns != nullptr) {delete InfoMgr::_pIns;cout << "delete InfoMgr::_pIns;" << '\n';}}};private:// 将构造函数私有化:外部无法直接构造该类对象InfoMgr() {cout << "InfoMgr()" << '\n';}private:string _ip = "127.0.0.1";int _port = 80;size_t _buffSize = 1024 * 1024;// 这不能说是在类中创建一个自己,否则就套娃乱透了// 静态成员不存储在一个类对象里面static InfoMgr* _pIns;
};
InfoMgr* InfoMgr::_pIns;
InfoMgr::DestroyIns desIns;int main() {// 调试程序可以发现:类里面的那个对象是在 GetInstance() 函数调用时创建的InfoMgr::GetInstance().Print();return 0;
}
懒汉模式二:利用 局部静态变量(推荐写这个)
局部静态变量
函数内的静态变量也称为局部静态变量,其作用域只限于函数内部,别的函数不能访问。
局部静态变量存储在全局数据区,只允许初始化一次,但它的生命周期和全局变量一样,自它们被定义时就一直存在,直到程序结束时才会被销毁。不会随着函数的结束而被销毁,会一直存在
特性:只允许初始化一次
作用域:在函数内部
存储区:全局静态区
生命周期:全局,不会随着函数的结束而被销毁,程序结束时才会被销毁
由于局部静态变量的特性,也可以达到 第一次调用 GetInstance() 函数,就定义一个类对象,其他时候调用不会重新定义,只允许定义一次 的目的
同时,程序结束时会该对象也会自动销毁,不用再定义内部类对齐处理了!!
这个写法简单明了,相比前一种写法更加巧妙
// 懒汉模式二:利用 局部静态变量
class InfoMgr
{
public:// 若对象指针为 nullptr,就给你 new 一个对象// 若不为空,就返回该对象给你static InfoMgr& GetInstance() {static InfoMgr pIns;return pIns;}void Print() {cout << _ip << '\n';cout << _port << '\n';cout << _buffSize << '\n';}// 将 拷贝构造、移动构造、赋值重载 封死:确保我们只有 GetInstance() 可以放出去唯一一个实例化对象InfoMgr(const InfoMgr&) = delete;InfoMgr(InfoMgr&&) = delete;InfoMgr& operator=(const InfoMgr&) = delete;private:// 将构造函数私有化:外部无法直接构造该类对象InfoMgr() {cout << "InfoMgr()" << '\n';}private:string _ip = "127.0.0.1";int _port = 80;size_t _buffSize = 1024 * 1024;
};int main() {// 调试程序可以发现:类里面的那个对象是在 GetInstance() 函数调用时创建的InfoMgr::GetInstance().Print();return 0;
}
相关文章:
【C++ 第二十一章】特殊类的设计(学习思路)
1.请设计一个类,不能被拷贝 设计思路 拷贝只会使用在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。 C98 的做法 将拷贝构造函数与赋值运算符…...
Java设计模式【命令模式】-行为型
1. 介绍 命令模式(Command Pattern) 是一种行为型设计模式,它将一个请求封装为一个对象,从而使我们可以用不同的请求对客户端进行参数化,并且支持请求的排队、记录日志以及撤销、重做等功能。命令模式将请求的发送者与…...
【HarmonyOS】一键扫码功能
【HarmonyOS】一键扫码功能 前言 鸿蒙在api10之后,对系统api的基础上,封装了较为复杂功能的开发工具包,统一称之为Kit。这些Kit根据功能定义的不同,划分为不同的种类Kit。如下图所示: 其实可以理解为集成在系统中的…...
Spring Boot应用中集成与使用多数据源
Spring Boot应用中集成与使用多数据源 1. 前言 通过定义和使用多个数据源,能在Spring Boot应用中实现更复杂的数据管理场景,比如读写分离、数据冗余等。 2. 准备工作 环境准备:确保已经准备好Spring Boot的开发环境。数据库准备ÿ…...
探索 JavaScript 中的 instanceof 关键字
在 JavaScript 这门灵活而强大的编程语言中,instanceof 是一个非常重要的操作符,它用于检测一个对象是否在其原型链的原型构造函数的 prototype 属性中出现。简而言之,instanceof 用于测试一个对象是否是其父类或者其原型链上某个构造函数的实…...
Python爬虫02
xml 和html 区别 jsonpath模块 场景 多层嵌套的复杂字典直接提取数据 安装 pip install jsonpath使用 from jsonpath import jsonpathret jsonpath(dict, jaonpath语法规则字符串)语法规则 eg: lxml模块&xpath语法 谷歌浏览器 xpath helper 插件 作用对当前页面…...
HTTP/3
http相关知识点 HTTP/3是超文本传输协议(HTTP)的最新版本,旨在进一步提高Web性能和安全性。HTTP/3的显著变化是它基于QUIC(Quick UDP Internet Connections)协议,而不是之前版本中使用的TCP协议。QUIC是由…...
MySQL 字符串操作详解和案例示范
MySQL 字符串操作详解 MySQL 提供了丰富的字符串操作函数,能够对这些字符串进行截取、定位、替换等操作。本文将详细讲解 MySQL 中的字符串操作函数,包括 SUBSTRING()、SUBSTR()、LEFT()、RIGHT()、LOCATE()、POSITION()、FIND_IN_SET()、ELT()、INSERT…...
全双工语音交互
文章目录 微软小冰全双工字节大模型语音交互[Language Model Can Listen While Speaking](https://arxiv.org/html/2408.02622v1) 微软小冰全双工 全双工的定义:一路持续的听,upload audio;一路持续的输出,download audio…...
nginx中如何设置gzip
前言 Nginx通过配置gzip压缩可以提升网站整体速度 Nginx的gzip功能是用于压缩HTTP响应内容的功能。当启用gzip时,在发送给客户端之前,Nginx会将响应内容压缩以减小其大小。这样可以减少数据传输的带宽消耗和响应时间,提高网站的性能和速度。…...
借老系统重构机会我写了个groovy规则引擎
公司老系统的重构计划早就有了,为了对Java硬编码的各种校验规则进行重构,特地参考了相关技术,最终选择了groovy进行了系统的学习,并编写了一个即插即用的轻量级规则引擎。 文章目录 项目背景技术选型groovy的性能groovy脚本执行线…...
C#利用ffmpeg借助NVIDIA GPU实现实时RTSP硬解码+硬编码录制MP4
目录 说明 效果 项目 代码 下载 说明 利用周杰的开源项目 Sdcb.FFmpeg 项目地址:https://github.com/sdcb/Sdcb.FFmpeg/ 代码实现参考:https://github.com/sdcb/ffmpeg-muxing-video-demo 效果 C#利用ffmpeg借助NVIDIA GPU实现实时RTSP硬解码硬…...
第4章 汇编语言和汇编软件
第4章 汇编语言和汇编软件 该章主要介绍了汇编语言和汇编语言编译器的安装和使用。 汇编语言程序 该小节主要介绍了为什么要有汇编语言和汇编语言程序的一些基础写法。 书中有提到CPU有不同的架构,汇编语言有不同的风格,那么不同的CPU架构和不同的汇…...
网络安全在2024好入行吗?
前言 024年的今天,慎重进入网安行业吧,目前来说信息安全方向的就业对于学历的容忍度比软件开发要大得多,还有很多高中被挖过来的大佬。 理由很简单,目前来说,信息安全的圈子人少,985、211院校很多都才建立…...
C++练习
要求 1. 函数命名清晰 使用描述性的命名,准确反映函数的功能。例如,使用 CalculateSum() 而不是 sum()。避免使用缩写或模糊不清的名字,确保变量和函数名有明确的含义。 2. 参数传递 根据需要选择按值传递、按引用传递或按指针传递。如果…...
3. GIS后端工程师岗位职责、技术要求和常见面试题
本系列文章目录: 1. GIS开发工程师岗位职责、技术要求和常见面试题 2. GIS数据工程师岗位职责、技术要求和常见面试题 3. GIS后端工程师岗位职责、技术要求和常见面试题 4. GIS前端工程师岗位职责、技术要求和常见面试题 5. GIS工程师岗位职责、技术要求和常见面试…...
Linux学习笔记(4)----Debian压力测试方法
使用命令行终端压力测试需要两个实用工具:s-tui和stress sudo apt install s-tui stress 安装完成后,在终端中启动 s-tui实用工具: s-tui 执行后如下图: 你可以使用鼠标或键盘箭头键浏览菜单,然后点击“压力选项(Str…...
xml详解
一、XML是什么 XML(可扩展标记语言)是一种非常常用的数据存储和交换格式。 二、XML 的基本结构 声明 XML 文件通常以 XML 声明开始,例如:<?xml version"1.0" encoding"UTF-8"?>。它指定了 XML 的版…...
C140 杨辉三角
C140 杨辉三角 题目题解(94)讨论(102)排行面经 new 简单 通过率:29.57% 时间限制:1秒 空间限制:256M 知识点C工程师牛客 校招时部分企业笔试将禁止编程题跳出页面,为提前适应,练习时请使用在线自测,…...
C++字符串操作中的陷阱
休对故人思故国,且将新火试新茶。诗酒趁年华。 ——《望江南超然台作》【宋】苏轼 目录 正文: 首先我们要明白出现问题的原因: 1. 缓冲区溢出 2. 错误的字符串声明方式 3. 缺乏对NULL指针的检查 解决方案: 下期预告:C字符串…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
论文阅读:Matting by Generation
今天介绍一篇关于 matting 抠图的文章,抠图也算是计算机视觉里面非常经典的一个任务了。从早期的经典算法到如今的深度学习算法,已经有很多的工作和这个任务相关。这两年 diffusion 模型很火,大家又开始用 diffusion 模型做各种 CV 任务了&am…...
