【C++】特殊类的设计、单例模式以及Cpp类型转换
📚 博主的专栏
🐧 Linux | 🖥️ C++ | 📊 数据结构 | 💡C++ 算法 | 🅒 C 语言 | 🌐 计算机网络
上篇文章: C++ 智能指针使用,以及shared_ptr编写
下篇文章: C++ IO流
目录
特殊类的设计
请设计一个类,不能被拷贝
请设计一个类,只能在堆上创建对象
请设计一个类,只能在栈上创建对象
请设计一个类,不能被继承
请设计一个类,只能创建一个对象(单例模式)
设计模式:
单例模式:
饿汉模式
懒汉模式
C++的类型转换
C语言中的类型转换
CPP中类型转换
为什么C++需要四种类型转换
隐式类型转换
示例:内置类型 -> 自定义类型
示例:自定义类型 -> 内置类型
自定义类型和自定义类型之间的转换
隐式类型转换的坑:
C++强制类型转换
static_cast(对应之前的隐式类型转换)
reinterpret_cast(对应的之前的显式类型转换)
const_cast
dynamic_cast(专门争对C++设计的,向下转换)
RTTI(了解)运行时类型识别
特殊类的设计
请设计一个类,不能被拷贝
拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。
线程不能被拷贝,IO流(IO流中的缓冲区不拷贝)不能被拷贝
C++98:
将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可。
C++11:
请设计一个类,只能在堆上创建对象
实现方式:
1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
class HeapOnly
{
public:static HeapOnly* CreateObject(){return new HeapOnly;//智能在堆上new}
private:HeapOnly() {}// C++98// 1.只声明,不实现。因为实现可能会很麻烦,而你本身不需要// 2.声明成私有HeapOnly(const HeapOnly&);// or
// C++11HeapOnly(const HeapOnly&) = delete;HeapOnly& operator=(const HeapOnly&) = delete;};
调用成员函数需要对象,因此将函数指定为static让其只属于类,不属于对象
//调用成员函数需要对象,因此将函数指定为static让其只属于类,不属于对象HeapOnly* obj4 = HeapOnly::CreateObject();
第一种办法:
为了防止调用拷贝构造,因此将拷贝构造也设置为私有,或者使用C++11的方法,直接封掉拷贝构造
HeapOnly obj5(*obj4);
一般封了拷贝构造,将赋值也封上,避免发生浅拷贝。
第二种方法:
将析构私有化(让析构无法自动调用):再自己写函数显示调用自己写的释放指针函数:
class HeapOnly { public:void Release(){delete this;} private:~HeapOnly(){ } };
请设计一个类,只能在栈上创建对象
同上将构造函数私有化,然后设计静态方法创建对象返回即可
class StackOnly { public:static StackOnly CreateObj(){return StackOnly();}// 禁掉operator new可以把下面用new 调用拷贝构造申请对象给禁掉// StackOnly obj = StackOnly::CreateObj();// StackOnly* ptr3 = new StackOnly(obj);void* operator new(size_t size) = delete;void operator delete(void* p) = delete; private:StackOnly():_a(0){} private:int _a; };
请设计一个类,不能被继承
C++98方式
// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承 class NonInherit { public:static NonInherit GetInstance(){return NonInherit();} private:NonInherit(){} };
C++11方法
final关键字,final修饰类,表示该类不能被继承。
class A final {// .... };
请设计一个类,只能创建一个对象(单例模式)
设计模式:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。为什么会产生设计模式这样的东西呢?就像人类历史发展会产生兵法。最开始部落之间打仗时都是人拼人的对砍。后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后来孙子就总结出了《孙子兵法》。孙子兵法也是类似。
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
设计模式举例:
单例模式
迭代器模式
适配器模式
观察者
工厂
单例模式:
一个类只能创建一个对象,即单例(单实例)模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
单例模式有两种实现模式:
饿汉模式
就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。
优点:简单
缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定。
饿汉(很饥饿,极早就创建对象)模式 : 一开始就(main函数之前)就创建对象
问题1:很多单例类,都是饿汉模式,有些单例对象初始化资源很多,导致程序启动慢,迟迟进不了main函数
问题2:如果两个单例类有初始化依赖关系,饿汉也无法解决。比如A类和B类是单例,A单例要连接数据库,B单例要用A单例访问数据库。
示例代码:
//饿汉(很饥饿,极早就创建对象)模式 : 一开始就(main函数之前)就创建对象//问题1:很多单例类,都是饿汉模式,有些单例对象初始化资源很多,导致程序启动慢,迟迟进不了main函数//如果两个单例类有初始化依赖关系,饿汉也无法解决。比如A类和B类是单例,A单例要连接数据库,B单例要用A单例访问数据库
class ConfigInfo
{
public:static ConfigInfo* GetInstance(){return &_sInfo;//可以用指针也能用引用(看需求)}string GetIp(){return _ip;}void SetIp(const string& ip){_ip = ip;}private://1.私有化构造函数ConfigInfo(){cout << "ConfigInfo()" << endl;}//2.把拷贝构造和赋值封掉ConfigInfo(const ConfigInfo&) = delete;ConfigInfo& operator=(const ConfigInfo&) = delete;
private:string _ip = "127.0.0.1";//存网络ipint _port = 80;//端口//...// 声明 static ConfigInfo _sInfo;//受类域的限制,但实际上在静态区,这里只是一个声明,需要在类外面定义
};// 定义
ConfigInfo ConfigInfo::_sInfo;
int main()
{//ConfigInfo info;cout << ConfigInfo::GetInstance() << endl;ConfigInfo::GetInstance()->SetIp("192.22.1.13");cout << ConfigInfo::GetInstance()->GetIp() << endl;return 0;
}
如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好
懒汉模式
优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制。
如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。
懒汉就是第一次调用时,创建单例对象
//懒汉完美解决上面饿汉存在的问题
class ConfigInfo
{
public:static ConfigInfo* GetInstance(){static ConfigInfo info;//定义一个局部的静态对象return &info;}string GetIp(){return _ip;}void SetIp(const string& ip){_ip = ip;}private://1.私有化构造函数ConfigInfo(){cout << "ConfigInfo()" << endl;}//2.把拷贝构造和赋值封掉ConfigInfo(const ConfigInfo&) = delete;ConfigInfo& operator=(const ConfigInfo&) = delete;
private:string _ip = "127.0.0.1";//存网络ipint _port = 80;//端口//...
};int main()
{//ConfigInfo info;cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;ConfigInfo::GetInstance()->SetIp("192.22.1.13");cout << ConfigInfo::GetInstance()->GetIp() << endl;return 0;
}
缺点是:在C++11前,局部static对象构造,有线程安全的风险
C++11之前的解决办法:仍然在第一次调用的时候再创建
class ConfigInfo
{
public:static ConfigInfo* GetInstance(){if (_spInfo == nullptr){_spInfo = new ConfigInfo;}return _spInfo;}string GetIp(){return _ip;}void SetIp(const string& ip){_ip = ip;}private://1.私有化构造函数ConfigInfo(){cout << "ConfigInfo()" << endl;}//2.把拷贝构造和赋值封掉ConfigInfo(const ConfigInfo&) = delete;ConfigInfo& operator=(const ConfigInfo&) = delete;
private:string _ip = "127.0.0.1";//存网络ipint _port = 80;//端口//...// 定义一个静态指针static ConfigInfo* _spInfo;//受类域的限制,但实际上在静态区,这里只是一个声明,需要在类外面定义
};ConfigInfo* ConfigInfo::_spInfo = nullptr;
int main()
{//ConfigInfo info;cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;ConfigInfo::GetInstance()->SetIp("192.22.1.13");cout << ConfigInfo::GetInstance()->GetIp() << endl;return 0;
}
现在还不能避免多线程调用的线程安全的问题:
如果两个线程都来,t1先来正在new的时候,t2判断了_spInfo为空,也要开始new,t1已经new完了,赋值给了_spInfo,最怕的是,t2时间片到了,开始在判断后的地方休眠,t1继续执行,并且已经SetIp(),t2醒了,又开始new,将t1申请的全给覆盖,导致内存泄漏。因此需要加锁 。
注意静态成员函数,只能访问静态的成员变量,因此mutex的对象也要设置成静态的:
注意看注释
class ConfigInfo
{
public:static ConfigInfo* GetInstance(){//加锁t1、t2只能一个进判断,保证只会new一个对象//单单只这样写,会导致,已经创建好对象了,但是每次调用GetInstance的时候都需要再被加锁/* unique_lock<mutex> lock(_mtx);if (_spInfo == nullptr){_spInfo = new ConfigInfo;}*///因为不能直接将锁加载if判断内,这仍然会导致线程安全,要的就是,每个线程都得判断对象是否创建//解决办法:多写一层if (_spInfo == nullptr){unique_lock<mutex> lock(_mtx);if (_spInfo == nullptr){_spInfo = new ConfigInfo;}}return _spInfo;}string GetIp(){return _ip;}void SetIp(const string& ip){_ip = ip;}private://1.私有化构造函数ConfigInfo(){cout << "ConfigInfo()" << endl;}//2.把拷贝构造和赋值封掉ConfigInfo(const ConfigInfo&) = delete;ConfigInfo& operator=(const ConfigInfo&) = delete;
private:string _ip = "127.0.0.1";//存网络ipint _port = 80;//端口//...// 定义一个静态指针static ConfigInfo* _spInfo;//受类域的限制,但实际上在静态区,这里只是一个声明,需要在类外面定义static mutex _mtx;
};ConfigInfo* ConfigInfo::_spInfo = nullptr;
mutex ConfigInfo::_mtx;
int main()
{//ConfigInfo info;cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;cout << ConfigInfo::GetInstance() << endl;ConfigInfo::GetInstance()->SetIp("192.22.1.13");cout << ConfigInfo::GetInstance()->GetIp() << endl;return 0;
}
C++的类型转换
C语言中的类型转换
在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。
1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
2. 显式类型转化:需要用户自己处理
隐式类型转换一般是类型关联度紧密(像是指针和double不能转换)的就能转,整形、浮点型、char(ASCII码)之间就能互相隐式类型转。
显式(强制)类型转换一般就是任意指针之间,整形(数据大小)和指针(字节编号)之间
示例:
// 隐式类型转换double d = i;printf("%d, %.2f\n", i, d);int* p = &i;// 显示的强制类型转换int address = (int)p;printf("%p, %d\n", p, address);
缺陷:
转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换
CPP中类型转换
为什么C++需要四种类型转换
C风格的转换格式很简单,但是有不少缺点的:
1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
2. 显式类型转换将所有情况混合在一起,代码不够清晰
因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格。
隐式类型转换
示例:
仍然支持有一定关联的类型的类型转换
1.C++内置类型支持转换为自定义类型
2.C++自定义类型支持转换成内置类型
单参数的构造函数支持隐式类型的转换
示例:内置类型 -> 自定义类型
class A { public:A(int a1):_a1(a1){}A(int a1, int a2):_a1(a1), _a2(a2){} private:int _a1 = 1;int _a2 = 1; };
// 内置类型 -> 自定义类型 A aa1 = 1; // C++11 A aa2 = {2,2};
示例:自定义类型 -> 内置类型
默认是不支持的,我们需要重载operator int
int x = aa1; cout << x << endl;
想转什么类型就写什么类型: 这里想转成int,因此就写int
operator int(){return _a1 + _a2;}
在OJ当中会遇到这样的写法:
while (cin>>x){cout << x << endl; }
原理是:
while (cin>>x)while (cin.operator>>(x))while (cin.operator>>(x).operator bool()){cout << x << endl;}
如果想要输入string呢?
string str;while (cin>>str){cout << str << endl;}
自定义类型和自定义类型之间的转换
比如我现在有一个B类型,正常情况下:能否将B类型转为A类型,不可以,强制类型转换也不可以
class B { public:private:int _b1; };
解决办法:用构造函数来支持相关的转换
class B { public:B(const A& aa):_b1(aa.get()){}private:int _b1; };
B bb = aa1;
就能支持了(实际上,我们模拟写const iterator和普通iterator时,就用的这个方法)
隐式类型转换的坑:
// 隐式类型转换的坑 void Insert(size_t pos) {int end = 10;while (end >= pos){cout << end << endl;--end;} } // int main() {Insert(5);Insert(0);return 0; }
运行结果:由于隐式类型转换导致的死循环,原因是因为,这里的int被隐式类型转换为unsize_int
C++强制类型转换
标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符: static_cast、reinterpret_cast、const_cast、dynamic_cast
static_cast(对应之前的隐式类型转换)
static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换。
int i = 1;// 隐式类型转换 : static_castdouble d = static_cast<double>(i);printf("%d, %.2f\n", i, d);int* p = &i;// error C2440: “static_cast”: 无法从“int *”转换为“int”// int address1 = static_cast<int>(p);
reinterpret_cast(对应的之前的显式类型转换)
reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型
示例:
// 显示的强制类型转换 : reinterpret_castint address = reinterpret_cast<int>(p);printf("%p, %d\n", p, address);
之前不支持的还是不会支持
// 类型强制转换”: 无法从“int *”转换为“double”// double x = (double)p;// 类型强制转换”: 无法从“int *”转换为“double”//double x = reinterpret_cast<double> p;
const_cast
const_cast最常用的用途就是删除变量的const属性,方便赋值
示例:
const int a = 1;//a不是存在常量区的,还是在栈上的(常变量// a++;int x = 0;cout << &a << endl;cout << &x << endl;
是可以修改的,间接修改:
int* ptr = (int*)&a;(*ptr)++;cout << *ptr << endl;cout << a << endl;
为啥用*ptr间接去访问拿到的是2,直接访问a又拿到的是1
但是又通过监视窗口,又会发现:a已经被修改了,为什么却打印1。
这是因为编译器的优化,第一种是因为:a是const修饰了的,不会被改变,把a存在寄存器中,寄存器中的a值没有被改变,内存变了,但是取值是直接从寄存器中拿。
第二种是:a直接被替换成 1,类似于宏,在编译的时候被替换
这个时候就可以在定义a的时候加一个关键字:volatile,稳定的。告诉编译器别优化,每次都到内存当中取
volatile const int a = 1;
运行结果:
因此增加一个const_cast,来显式告诉自己,a的const属性已经被去掉了,他已经可以被改变了,提醒要加上volatile:
int* ptr = const_cast<int*>(&a);
示例:这种情况用哪一种隐式类型转换方式
A aa1 = static_cast<A>(1);
这是单参数的构造函数,还是应该走隐式类型的转换因此使用 static_cast ,reinterpret_cast是显式类型转换。
dynamic_cast(专门争对C++设计的,向下转换)
dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
向上转型:子类对象指针/引用->父类指针/引用(是天然的,不会产生临时对象,切片父类,不需要转换,赋值兼容规则)
向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
注意:
1. dynamic_cast只能用于父类含有虚函数的类
2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
示例:
class A
{
public:virtual void f() {}int _a1 = 1;
};class B : public A
{
public:int _b1 = 1;
};void fun(A* pa)
{// 无差别转换,存在一定风险B* pb = (B*)pa;cout << pb << endl;//pb->_b1++;
}int main()
{A a;B b;fun(&a);fun(&b);return 0;
}
这样转换是有风险,我们分别给A、B成员_a1,_b1,pa指针有可能只想A对象也有可能指向B对象,如果原本就指向B对象,将你强转成B是没有问题的。转换的时候,现在就指向整个B。如果原来指向A,转成B之后,会多看一部分,但是那一部分并不属于pb,越界。
因此C++设计了dynamic_cast来动态转换:
不是无差别转换,他会检查pa原本指向什么对象,如果指向B对象,转换成功,如果指向A对象,转换失败,返回空。能识别是指向父类还是子类。
void fun(A* pa)
{// pa指向B对象,转换成功// pa指向A对象,转换失败,返回空B* pb = dynamic_cast<B*>(pa);if (pb){cout << pb << endl;pb->_b1++;}else{cout << "转换失败" << endl;}
}
RTTI(了解)运行时类型识别
RTTI:Run-time Type identification的简称,即:运行时类型识别。C++通过以下方式来支持RTTI:
1. typeid运算符
2. dynamic_cast运算符
3. decltype
复习RAII是什么:把一个资源交给一个对象管理,可能是动态开辟的资源,或者锁,当生命周期到了自动调用析构函数,解锁、释放资源
结语:
随着这篇博客接近尾声,我衷心希望我所分享的内容能为你带来一些启发和帮助。学习和理解的过程往往充满挑战,但正是这些挑战让我们不断成长和进步。我在准备这篇文章时,也深刻体会到了学习与分享的乐趣。
在此,我要特别感谢每一位阅读到这里的你。是你的关注和支持,给予了我持续写作和分享的动力。我深知,无论我在某个领域有多少见解,都离不开大家的鼓励与指正。因此,如果你在阅读过程中有任何疑问、建议或是发现了文章中的不足之处,都欢迎你慷慨赐教 。
你的每一条反馈都是我前进路上的宝贵财富。同时,我也非常期待能够得到你的点赞、收藏,关注这将是对我莫大的支持和鼓励。当然,我更期待的是能够持续为你带来有价值的内容。
相关文章:

【C++】特殊类的设计、单例模式以及Cpp类型转换
📚 博主的专栏 🐧 Linux | 🖥️ C | 📊 数据结构 | 💡C 算法 | 🅒 C 语言 | 🌐 计算机网络 上篇文章: C 智能指针使用,以及shared_ptr编写 下篇文章ÿ…...

050_基于springboot的音乐网站
一、系统架构 前端:vue | element-ui | html | jquery | css | ajax 后端:springboot | mybatis 环境:jdk1.8 | mysql | maven | nodejs | idea 二、代码及数据 三、功能介绍 01. web端-注册 02. web端-登录 03. web…...
全局变量Msg.sender
msg.sender 在 Solidity 中,有一些全局变量可以被所有函数调用。 其中一个就是 msg.sender,它指的是当前调用者(或智能合约)的 address。 注意:在 Solidity 中,功能执行始终需要从外部调用者开始。 一个合…...

【论文阅读】平滑量化:对大型语言模型进行准确高效的训练后量化
论文题目:SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models 论文地址:[2211.10438] SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models 代码地址:http…...

【资料推荐】LVDS Owner’s Manual
一份年代有些久远的技术资料,但是内容全面且经典! 本用户手册提供了很多有用的信息,首先简要概述了三种最常见的高速接口技术:LVDS(包括B-LVDS和M-LVDS)、CML和LVPECL,并对其相应的特性进行了分…...

ARM Cortex-M (STM32)如何调试HardFault
目录 步骤 1: 实现一个有效的 HardFault 处理程序 步骤 2: 复现 HardFault 并使用调试器分析 步骤 3: 解读故障信息 步骤 4: 定位并修复源代码 HardFault 是 ARM Cortex-M 处理器中的一种异常。当处理器遇到无法处理的错误,或者配置为处理特定类型错误ÿ…...

黑马 redis面试篇笔记
redis主从 version: "3.2"services:r1:image: rediscontainer_name: r1network_mode: "host"entrypoint: ["redis-server", "--port", "7001"]r2:image: rediscontainer_name: r2network_mode: "host"entrypoint:…...
Docker端口映射与容器间DNS发现:打通服务通信的任督二脉
Docker端口映射与容器间DNS发现:打通服务通信的任督二脉 一、端口映射深度解析1.1 端口映射核心机制映射规则语法: 1.2 高级映射技巧批量端口映射:查看端口绑定状态: 二、容器间服务发现机制2.1 自定义网络DNS体系DNS解析特性&…...

DBdriver使用taos数据库
首先创建连接 连接后比如数据库里有三个库 选择其中的hypon 选中localhost,右键sql编辑器,打开sql控制台 就插入了一条数据...

观成科技:摩诃草组织Spyder下载器流量特征分析
一、概述 自2023年以来,摩诃草组织频繁使用Spyder下载器下载远控木马,例如Remcos。观成安全研究团队对近几年的Spyder样本进行了深入研究,发现不同版本的样本在数据加密、流量模式等方面存在差异。基于此,我们对多个版本样本的通…...

AIGC实战之如何构建出更好的大模型RAG系统
一、RAG 系统核心架构解析 1. 检索模块深度优化 1.1 混合检索技术实现 技术原理:结合稀疏检索(BM25)与密集检索(DPR),通过动态权重分配提升检索精度。例如,在医疗领域,BM25 负责精…...

C++入门小馆: 深入了解STLlist
嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的pa…...
【Git】Fork和并请求
当你在 GitHub 或其他代码托管平台上 Fork 了一个项目后,你可以基于你的 Fork 进行开发,并通过 Pull Request(PR) 的方式将你的更改提交给原始项目(也称为上游仓库)。以下是完整的流程和步骤: 1…...

小白学习java第15天:JDBC
1.数据库驱动 想一下我们之前是怎么操作数据库,是不是使用SQL语句对其mysql数据库管理系统,然后管理系统在进行数据库(硬盘文件里面的)进行操作。那么我现在想使用应用程序对其数据库进行操作,应该怎么办呢࿱…...

大模型应用开发(PAFR)
Prompt问答 特征:利用大模型推理能力完成应用的核心功能 应用场景: 文本摘要分析 舆情分析 坐席检查 AI对话 AgentFunction Calling 特征:将应用端业务能力与AI大模型推理能力结合,简化复杂业务功能开发 应用场景: 旅行指南 数据…...
Go 剥离 HTML 标签的三把「瑞士军刀」——从正则到 Bluemonday
1 为什么要「剥皮」? 安全:去掉潜在的 <script onload…> 等恶意标签,防止存储型 XSS。可读性:日志、消息队列、搜索索引里往往只需要纯文本。一致性:不同富文本编辑器生成的 HTML 五花八门,统一成「…...

U-Mail邮件加速服务:全球链路加速,安全稳定收发
由于跨国网络拥堵、带宽不稳定等因素,导致海外用户在使用企业邮箱收发邮件时,经常出现邮件收发不畅的问题。针对这种情况,U-Mail正式推出了邮件加速服务,U-Mail邮件加速服务依托全球优质加速链路和转发集群服务器,为海…...
实战交易策略 篇十七:翻倍黑马交易策略
文章目录 系列文章设置指标判断大盘买入的条件判断大盘卖出的条件精选个股,挖掘明天能上涨的黑马熊市选股牛市选股短线最佳买点短线最佳卖点“翻倍”的核心秘籍系列文章 实战交易策略 篇一:奥利弗瓦莱士短线交易策略 实战交易策略 篇二:杰西利弗莫尔股票大作手操盘术策略 实…...
反爬策略应对指南:淘宝 API 商品数据采集的 IP 代理与请求伪装技术
一、引言 在电商数据驱动决策的时代,淘宝平台海量的商品数据极具价值。然而,淘宝为保障平台安全和用户体验,构建了严密的反爬体系。当采集淘宝 API 商品数据时,若不采取有效措施,频繁的请求极易触发反爬机制&#x…...

论文精读:大规模MIMO波束选择问题的量子计算解决方案
论文精读:大规模MIMO波束选择问题的量子计算解决方案 概要: 随着大规模多输入多输出系统(MIMO)在5G及未来通信技术中的应用,波束选择问题(MBS)成为提升系统性能的关键。传统的波束选择方法面临计…...
精益数据分析(13/126):洞察数据关系,灵活调整创业方向
精益数据分析(13/126):洞察数据关系,灵活调整创业方向 大家好!在创业和数据分析的探索之路上,每一次的学习都是成长的宝贵机会。今天,咱们接着深入学习《精益数据分析》,一起探索相…...

uniapp-商城-37-shop 购物车 选好了 进行订单确认3 支付栏
支付栏 就是前面用的 car-Layout 在shop也用来这个组件 只是在那里用来的是购物车。 1、 样式 我们开始进入这个页面是点击的shop的购物篮 到这里就变成了支付栏 其实他们是同一个组件 只是做了样式区分 2、具体看看样式和代码 2.1 消失了购物车和改变了按钮名字 如何…...

【LLM+Code】Claude Code Agent 0.2.9 版本PromptTools最细致解读
一、Claude Code 是anthropic团队开发的一个code agent bash工具 具体使用文档:https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview 1.1 安装/使用Claude Code 自行安装 npm install -g anthropic-ai/claude-code cd your-project-dire…...

ISCTF2024-misc(部分)
前言 之前写的,一直没发,留个记录吧,万一哪天记录掉了起码在csdn有个念想 1.少女的秘密花园 打开是个图片 随波逐流binwalk一下分离得到一个zip,解压得到base_misc发现是zip 爆破得到密码 解压得到一个txt,将里面的…...

U8G2在PC端模拟(C语言版本)
前提: 电脑已经准备好mingw编译器环境,已经加入环境变量. 测试方法: window下打开cmd,输入gcc -v 会有信息打印. u8g2 u8g2官方支持sdl2接口,已经做好了适配. 所以只需要在使用的开发环境配置好SDL2路径即可. sdl2和u8g2的适配…...

【计算机视觉】CV实战项目 - 深入解析基于HOG+SVM的行人检测系统:Pedestrian Detection
深入解析基于HOGSVM的行人检测系统:从理论到实践 技术核心:HOGSVM检测框架HOG特征原理SVM分类器 项目架构与数据准备INRIA Person数据集目录结构 实战指南:从零构建检测系统环境配置完整训练流程检测应用 关键技术问题与解决方案1. 难例挖掘不…...
如何借助全球动态IP实现多平台账号的批量注册?
无论是社交网络、在线购物平台还是专业应用软件,账号的创建和使用都是必不可少的。然而,在面对不同平台各自的注册限制和策略时,如何高效、安全且合法地进行账号批量注册成为了亟待解决的问题。本文将探讨全球动态IP在这一过程中的作用及其如…...

PR第二课--混剪
1.音乐打点 1.1 手动打点 按钮(如图),或者,快捷键M(如果在已有打点处,再次按M键会进入对标记点的设置界面,如下下图) 1.2 插件打点 一段音乐中,有明显的鼓点时,可以使用打点插件,快捷打点;如果鼓点不明显的话,最好还是手动打点,用插件打点会打出大量的标记点,…...

网页不同渲染方式的应对与反爬机制的处理——python爬虫
文章目录 写在前面爬虫习惯web 网页渲染方式服务器渲染客户端渲染 反爬机制使用session对象使用cookie让请求头信息更丰富使用代理和随机延迟 写在前面 本文是对前两篇文章所介绍的内容的补充,在了解前两篇文章——《爬虫入门与requests库的使用》和《BeautifulSou…...

高级电影感户外街拍人像摄影后期Lr调色教程,手机滤镜PS+Lightroom预设下载!
调色介绍 高级电影感户外街拍人像摄影后期 Lr 调色,是运用 Adobe Lightroom 软件,对户外街拍的人像照片进行后期处理,以塑造出具有电影质感的独特视觉效果。此调色过程借助 Lr 丰富的工具与功能,从色彩、光影、对比度等多维度着手…...