特殊类的设计
目录
- 一、设计一个类,不能被拷贝
- 二、设计一个类,只能在堆上创建对象
- 三、设计一个类,只能从栈上创建对象
- 四、设计一个类,不能被继承
- 五、设计一个类,只能创建一个对象(单例模式)
- 5.1 饿汉模式
- 5.2 懒汉模式
一、设计一个类,不能被拷贝
//1、请设计一个类,不能被拷贝
//
// 拷贝一个类,要么调用拷贝构造函数,要么调用赋值重载函数,所以要令一个类不能
// 被拷贝,只需要让该类不能调用拷贝构造和赋值重载函数就可以了。
//
// 在C++98语法下,只需要把该类的拷贝构造函数和赋值重载函数声明为私有,
// 并且不定义即可
//
//原因:拷贝构造函数和赋值重载函数只要我们声明了,编译器就不会再默认生成,但是
//我们又不定义它,所以这两个函数就不能被调用,如果定义了,反而在类内部会被调用
// 拷贝构造函数和赋值重载函数,不符合题意;并且我们声明为私有函数,别人想要
//从类外面自己定义也是做不到的,所以这样的类是不能被拷贝的class A
{
public:
private:A(const A& a);A& operator=(const A& a);
};// C++11语法下:
//
// C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上 = delete,
// 表示让编译器删除掉该默认成员函数。
// 所以直接用关键字delete把拷贝构造函数和赋值重载函数删除掉即可
class A
{
private:A(const A& a) = delete;A& operator=(const A& a) = delete;
};
二、设计一个类,只能在堆上创建对象
//2、请设计一个类,只能在堆上创建对象
//
//方法一:要想设计一个类只能在堆上创建对象,只需要将析构函数私有即可//原因:因为只要定义出对象的,对象是自定义类型,必然需要调用构造
// 函数和析构函数,而现在把析构函数私有,则定义的对象在销毁的时候
// 无法调用析构函数,就一定会报错
//但是如果是在堆上创建对象,返回值是一个对象的指针,指针是内置类型,
//不会调用构造函数和析构函数,所以即使析构函数是私有的,也可以通过
//new在堆上创建对象
class HeapOnly
{
public:void func(){cout << "func" << endl;}void Destroy(){//这里delete掉this指针等于是释放了调用//该函数的类的指针,这种写法是正确的delete this;cout << "~HeapOnly()" << endl;}private://析构函数私有~HeapOnly(){}private:int _b;
};//方法二:把构造函数私有,然后提供一个CreateObj的函数,
// 这个函数内部用new创建一个对象,然后返回对象的指针即可,
// 但是要注意把拷贝构造和赋值重载函数delete掉,防止别人
// 在栈上构造对象
//
class HeapOnly
{
public:static HeapOnly* CreateObj(){HeapOnly* ptr = new HeapOnly;return ptr;}
private:HeapOnly(){}HeapOnly(const HeapOnly& ho) = delete;HeapOnly& operator=(const HeapOnly& ho) = delete;
};int main()
{//static B b;HeapOnly* pb = new HeapOnly;pb->func();//HeapOnly b(*pb);pb->Destroy();return 0;
}//int main()
//{
// HeapOnly* ho = HeapOnly::CreateObj();
//
// return 0;
//}
三、设计一个类,只能从栈上创建对象
//3、请设计一个类,只能在栈上创建对象
//不能完全设计出只在栈上创建对象的类;
//沿用2的设计思路,把构造函数私有,然后提供一个CreateObj的函数,
//该函数返回一个在栈上创建的对象。
//因为这个返回的是临时对象,所以不能把拷贝构造函数和赋值函数delete掉,
//因为传值返回对象需要被拷贝。
class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}void func(){cout << "StackOnly()" << endl;}private:StackOnly(){}// 对一个类实现专属operator new,这句代码的意思是把用new//创建该类对象的方法delete掉,外部不能再利用new来创建对象了void* operator new(size_t size) = delete;};int main()
{StackOnly so = StackOnly::CreateObj();cout << &so << endl;int a = 0;cout << &a << endl;so.func();//因为用户可能用new调用拷贝构造函数在堆上创建对象,所以需要// 把类的专属的operator new给delete掉,禁止用new在堆上创建对象//StackOnly* pso = new StackOnly(so);//这个类唯一不能禁止的就是在静态区创建对象,因为要在栈上创建对象就//一定要有拷贝构造函数,有拷贝构造函数就可以在静态区创建静态对象static StackOnly so1= StackOnly::CreateObj();static int b = 0;cout << &so1 << endl;cout << &b << endl;return 0;
}
四、设计一个类,不能被继承
//4. 请设计一个类,不能被继承
//
//C++98语法
//构造函数私有,然后提供一个CreateObj函数创建对象
// 原因:构造函数私有,也就意味着构造函数不能被显式地调用,
// 因为在继承体系中,子类成员中父类的成员必须调用父类的构造函数
// 初始化父类那一部分成员的,所以如果把父类的构造函数私有,子类
// 就没有办法调用父类的构造函数初始化父类那一部分成员,所以就继承不了
//
class Final
{
public:
private:Final(int f):_f(f){}int _f = 0;
};class A:public Final
{
public://A的构造函数无法调用Final的构造函数,所以Final类不能被继承A():Final(2),_a(1){}private:int _a;
};
//C++11语法:
//C++11提供了一个关键字final,即直接在类后面加上final表示该类不能被继承
class Final final
{
public:Final(int f):_f(f){}private:int _f = 10;
};这里就会报错了,因为Final是不可被继承的
//class F :public Final
//{
//
//};
五、设计一个类,只能创建一个对象(单例模式)
设计模式:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大楼的结构一样。
单例模式:
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置
信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
5.1 饿汉模式
//1、饿汉模式:一开始(main函数之前)就创建单例对象
//优点:简单
//缺点:
// (1) 如果单例对象要初始化的内容很多,启动速度慢。
// (2) 如果A单例对象的创建依赖B单例对象,要求B对象先创建好,但是我们无法保证先让B单例对象创建好。
// (3) 如果单例对象很大,占用资源很多,但是单例对象创建出来之后不是立刻使用,
// 会占用着大量的内存,导致其它需要内存的地方获取不到内存。
namespace hungry
{class Singalton{public:static Singalton& GetInstance(){return _Inst;}private://构造函数私有,防止别人随意创建对象Singalton(){}//把拷贝构造函数和赋值重载函数删除掉,防止拷贝Singalton(const Singalton& sg) = delete;Singalton& operator=(const Singalton& sg) = delete;//因为全局只有唯一的一个对象,如何保证我们每次获取到的都是同一个对象呢?// 因为静态的全局变量在main函数之前就会定义好的,所以静态的全局变量是全局唯一的。// 所以这里一般都是在类里面声明一个静态的Singalton对象(类外定义),// 在Singalton类里面可以声明Singalton的静态对象吗?// 声明静态对象static Singalton是可以的,// 但是声明普通对象Singalton就不行,为什么呢?// 因为声明普通对象的话就会出现无限套娃的情况了,对象里面又会套一个对象;但// 是声明静态的Singalton对象为什么就可以了呢?// 因为静态的Singalton对象本身并不存在于Singalton类的空间里面,而是存在于// 静态区中,属于所有对象共有的,所以不存在套娃的情况的,所以可以声明静态的Singalton对象的。// // 同时要注意,这里只是声明,普通静态对象必须在类外面定义,但是const static对象比较特殊,// 可以在类内定义这样每一次调用GetInstance的时候就返回这个静态的对象就可以保证每次返回的都是// 同一个_Inst了static Singalton _Inst;// 在C++中,允许在类内部声明一个本类的静态对象的原因是为了方便和灵活性,//当声明一个类的静态成员时,编译器只需要知道该成员的类型和名称,而不需要//知道成员的具体定义和大小。这样做的好处是可以避免一些循环依赖的问题。如// 果不允许在类内部声明本类的静态对象,那么在类定义之前就无法实例化包含静// 态成员的对象,因为在类定义之前,编译器还不知道该类的完整定义。//通过在类内部声明本类的静态对象,可以为程序提供更高的灵活性。在类定义之后// 的任何位置,都可以在需要的时候进行定义和初始化这个静态对象。这样,程序员// 可以根据需要更具灵活性地控制对象的创建和使用。//需要注意的是,在定义之前使用这个静态对象可能会导致未定义的行为,因此在类// 定义之后的某个地方,一定要进行静态对象的定义和初始化,以确保它的正确使用。};//定义,在main函数之前就已经创建好了单例对象Singalton Singalton::_Inst;
}int main()
{//每次调用GetInstance获取到的对象都是同一个cout << &hungry::Singalton::GetInstance() << endl;cout << &hungry::Singalton::GetInstance() << endl;cout << &hungry::Singalton::GetInstance() << endl;return 0;
}
如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源(例如锁)竞争,提高响应速度更好。
5.2 懒汉模式
如果单例对象构造十分耗时或者占用很多资源,比如加载插件, 初始化网络连接,读取文件等等操作时,并且有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。
//2、懒汉模式
//比较懒,到有人定义对象的时候才创建对象
//(1) 优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制。
//(2) 缺点:复杂。
namespace lazy
{class Singalton{public:static Singalton* GetInstance(){//这里要使用双判断加锁的方式处理,这样才能很好地提高效率//这个if是判断第一次调用实例对象时需要先创建对象if (_pInst == nullptr){//加锁避免线程安全的问题,两个线程同时进入了这里,需要先竞争锁_pmtx->lock();//这个if是判断如果两个进程同时来到了这里,竞争到锁的进程//先来到这个判断条件,如果_pInst还是nullptr,说明这是第一次调用实例对象//此时创建一个Singalton,后竞争到锁的进程在再一次if判断时_pInst就不再是nullptr//了,此时说明单例对象已经存在了,就不会再创建了if (_pInst == nullptr){_pInst = new Singalton;}_pmtx->unlock();}return _pInst;}//一般情况下,单例对象不需要释放,因为程序正常结束就释放了,// 并且单例对象一般也不大,所以可以把析构函数设置成私有//// 但是有些特殊场景:// 1、中途需要显式释放;//2、程序结束时需要做一些持久化(把数据写入到文件中);// 所以需要提供一个显式调用的DelInstance函数(里面封装析构函数)static void DelInstance(){cout << "DelInstance()" << endl;if (_pInst != nullptr){//自定义对象,调用_pInst对象的析构函数delete _pInst;delete _pmtx;}}void Add(const pair<string, string>& val){_um.insert(val);}private://构造函数Singalton(){}//析构函数~Singalton(){//显式调用析构函数书写日志或者持久化(数据写入文件)cout << "~Singalton()" << endl;FILE* fp = fopen("test.txt", "w");for (const auto& e : _um){fputs(e.first.c_str(), fp);fputs(":", fp);fputs(e.second.c_str(), fp);fputs("\n", fp);}}//拷贝构造函数,单例模式防拷贝Singalton(const Singalton& sg) = delete;//赋值重载函数Singalton& operator=(const Singalton& sg) = delete;//相当于一个垃圾回收类class GC{public://用Gc的析构函数管理单例类的析构函数,因为在Singalton中声明了一个Gc的静态的//成员变量,所以在进程结束的时候会调用析构函数,而Gc析构函数又管理着Singalton的// 析构函数DelInstance,所以无论如何进程结束的时候都会自动调用Singalton的析构// 函数的,所以就不存在内存泄漏的隐患了//~GC(){DelInstance();}};private://如何保证每次调用GetInstance函数的时候获取到的_Inst都是同一个呢?因为这里是运行时//才创建对象的,所以不能用静态的对象,而这里要获取到同一个对象,所以只能在堆上开辟;//但是这里为什么是用静态的呢?因为GetInstance是静态的,没有this指针,但是GetInstance//函数中需要用到_Inst,所以需要这个_Inst也要设置为静态的,这样GetInstance函数才能访问_Inst//同理_mtx也要是静态的static Singalton* _pInst;static mutex* _pmtx;unordered_map<string, string> _um;//在单例类中声明一个Gc类型的静态的成员变量,在类外定义;该对象在进入main函数前就已经创建好了,//到进程结束时才调用析构函数销毁,说明这个变量是整个进程都有效的static GC gc;};//必须在类外定义类内的静态成员变量Singalton* Singalton::_pInst = nullptr;mutex* Singalton::_pmtx = new mutex;Singalton::GC Singalton::gc;
}//GC也可以这样写,这样写更容易理解,用GC创建一个全局对象,进程结束时GC调用析构函数,
// 进而调用lazy::Singalton::DelInstance()释放单例对象,但是遇到多个单例类就把它们
// 全部放到~GC函数中即可,上面那种写法就是把GC定义到单例类内部,每一个GC对象管理一个单例类
//class GC
//{
//public:
// ~GC()
// {
// lazy::Singalton::DelInstance();
// }
//};
//GC gc;int main()
{//lazy::Singalton* p1 = lazy::Singalton::GetInstance();//lazy::Singalton* p2 = lazy::Singalton::GetInstance();//lazy::Singalton* p3 = lazy::Singalton::GetInstance();//cout << p1 << endl;//cout << p2 << endl;//cout << p3 << endl;lazy::Singalton* p1 = lazy::Singalton::GetInstance();p1->Add(make_pair("string", "字符串"));p1->Add(make_pair("left", "左边"));p1->Add(make_pair("right", "右边"));return 0;
}
以上就是常见的特殊类的设计,你学会了吗?今天的分享就到这里啦,如果你感觉到有所收获,那么就点点小心心点点关注呗,后期还会持续更新C++的相关知识哦,我们下期见!!!
相关文章:
特殊类的设计
目录 一、设计一个类,不能被拷贝二、设计一个类,只能在堆上创建对象三、设计一个类,只能从栈上创建对象四、设计一个类,不能被继承五、设计一个类,只能创建一个对象(单例模式)5.1 饿汉模式5.2 懒…...
HTTP 协议的基本格式(部分)
要想了解HTTP,得先知道什么是HTTP,那么HTTP是什么呢?HTTP (全称为 "超文本传输协议") 是一种应用非常广泛的 应用层协议。那什么是超文本呢?那就是除了文本,还有图片,声音,视频等。 …...
Android 第三方app https 抓包
工具选择 Charles 或 Fiddler 都可以 在PC上安装工具并进行设置 Charles Fiddler 设置按官网说明设置一下好。 Charles设置 Fiddler设置 Android Api Level > 24 SSL特殊设置 当Android 的 Api Level > 24时需要修改一下app的一起配置 1.在项目中添加 Android/src/…...
Linux-gitlab常用命令
gitlab常用命令 1、查看gitlab状态2、gitlab启动3、gitlab关闭 1、查看gitlab状态 gitlab-ctl status2、gitlab启动 gitlab-ctl start3、gitlab关闭 gitlab-ctl stop...
android 13.0 Settings主页动态显示和隐藏设置项(一级菜单显示和隐藏)
1.前言 在13.0定制化开发Settings时,有产品需求要求对主页设置项需要动态控制显示和隐藏,这就需要用定义两个页面来区分加载不同settings页面 接下来分析下相关的实现流程 实现思路: 1.用系统变量控制显示和隐藏某些项 2.增加一个自定义页面来适配不同页面 2.Settings主页动态…...
Android MJPEG播放器
MJPEG Android MJPEG播放 支持http mjpeg直播流播放; 支持编码MP4保存视频; 资源 名字资源jar下载GitHub查看Gitee查看 Maven 1.build.grade allprojects {repositories {...maven { url https://jitpack.io }} }2./app/build.grade dependencies {implementation com.g…...
Ubuntu - 安装 MySQL 8
以下是在 Ubuntu 上安装 MySQL 8 的完整步骤: 步骤 1:更新包列表 首先,打开终端并执行以下命令来确保包列表是最新的: sudo apt update 步骤 2:安装 MySQL 8 服务器 接下来,使用以下命令安装 MySQL 8 …...
谷歌浏览器跨域及--disable-web-security无效解决办法
谷歌浏览器跨域设置 (1)创建一个目录,例如我在C盘创建MyChromeDevUserData文件夹 (2) 在桌面选择谷歌浏览器右键 -> 属性 -> 快捷方式 -> 目标,添加--disable-web-security --user-data-dirC:\M…...
IT售前“楠“知识之这!就是售前-尚文网络xUP楠哥
进Q群11372462领取专属报名福利 !!! # 何为售前工程师 售前工程师在一个IT信息化团队中起到了呈上启下的绝对重要作用!站在销售团队的视角,需要售前工程师从技术维度支持销售业务的开展;站在对立面用户的…...
JS元编程
如果说常规编程是写代码去操作数据,那么元编程就是写代码去操作其他代码。 1 属性的特性 JS的属性有名字和值,但每个属性也有3个关联的特性: 可写(writable)特性指定是否可修改属性的值。 可枚举(enume…...
通过Gunicorn、Supervisor和Nginx更好地运行Django
文章目录 通过runserver运行Django通过Gunicorn运行Django通过Nginx来做反向代理通过Supervisor来托管gunicorn和nginx 同步发布在个人站点:https://panzhixiang.cn 通过runserver运行Django 相信用过Django做开发的人对于python manage.py runserver 这个命令一定…...
[SQL] union all
UNION ALL 是一个用于合并多个查询结果集的操作符。它将多个 SELECT 查询的结果合并成一个结果集,并且保留所有的行,包括重复的行。 具体语法如下: SELECT column1, column2, ... FROM table1 UNION ALL SELECT column1, column2, ... FROM…...
Filebeat+Kafka+ELK日志分析架构
目录 一、zookeeper: 1. zookeeper 定义: 2. Zookeeper 工作机制: 3. Zookeeper 特点: 4. Zookeeper 数据结构: 5. Zookeeper 应用场景: 5.1 统一命名服务: 5.2 统一配置管理: 5.3 统一集群管理: 5.4 服务器动态上下线: 5.5 软负载均衡: 6. Zookeeper 选…...
RK3568驱动指南|第六篇-平台总线-第55章 初识设备树
瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…...
【ELK 使用指南 1】ELK + Filebeat 分布式日志管理平台部署
ELK和EFLK 一、前言1.1 日志分析的作用1.2 需要收集的日志1.3 完整日志系统的基本特征 二、ELK概述2.1 ELK简介2.2 为什么要用ELK?2.3 ELK的组件 三、ELK组件详解3.1 Logstash3.1.1 简介3.1.2 Logstash命令常用选项3.1.3 Logstash 的输入和输出流3.1.4 Logstash配置文件 3.2 E…...
Springboot高频应用注解
本文旨在记录开发中遇到的SpringBoot高频注解,并针对其具体应用记录。 一、LOMBOK相关注解 Slf4j 目的在于使用Log的日志功能,可以在JAVA中自动生成日志记录器!使用时在类上添加Slf4j注解后即可以在类中调用log方法如 可以 调用 log.info …...
面试总结分享:25道数据库测试题
1)什么是数据库测试? 数据库测试也称为后端测试。数据库测试分为四个不同的类别。数据完整性测试 数据有效性测试 数据库相关的性能 测试功能,程序和触发器 2)在数据库测试中,我们需要正常检查什么? 通常&a…...
和硕首次参加展OCP 峰会,将发布多项AI合作项目产品 | 百能云芯
电子代工大厂和硕联合科技宣布,将参与今年的 OCP 全球峰会 (OCP Global Summit),展示与英伟达 (NVIDIA) 合作成果,包含使用英伟达 GH200 Grace Hopper 超级芯片的 MGX AI 服务器,以及搭载 A100、L40 等服务器产品。 OCP 峰会于 10…...
FPGA基于1G/2.5G Ethernet PCS/PMA or SGMII实现 UDP 网络视频传输,提供工程和QT上位机源码加技术支持
目录 1、前言版本更新说明免责声明 2、我这里已有的以太网方案3、设计思路框架视频源选择OV5640摄像头配置及采集动态彩条UDP协议栈UDP视频数据组包UDP协议栈数据发送UDP协议栈数据缓冲IP地址、端口号的修改Tri Mode Ethernet MAC1G/2.5G Ethernet PCS/PMA or SGMIIQT上位机和源…...
小程序setData动态传递key
有些时候可能需要根据key是个变量 比如 let keyName "name" this.setData({keyName :"张三" })本来想将keyName替换为name的,但是小程序只会在data中定义一个key为keyName ,value为“张三”的一条数据。 正确写法为: let keyNam…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
Windows 下端口占用排查与释放全攻略
Windows 下端口占用排查与释放全攻略 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。 一、准…...
