C++之特殊类设计及类型转换
目录
一、设计一个不能被拷贝的类
二、设计一个只能在堆上创建对象的类
三、设计一个只能在栈上创建对象的类
四、设计一个不能被继承的类
五、设计一个只能创建一个对象的类(单例模式)
六、C语言中的类型转换
七、C++中的三类类型转换
八、C++强制类型转换
8.1、为什么C++需要四种类型转换
8.2、static_cast
8.3、reinterpret_cast
8.4、const_cast
8.5、dynamic_cast
九、RTTI
一、设计一个不能被拷贝的类
拷贝只会发生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝, 只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。
C++98:
将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可。
原因:
- 设置成私有:如果只声明没有设置成private,用户自己如果在类外定义了,就可以不被禁止拷贝了
- 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。
示例代码:
class CopyBan
{
private:CopyBan(const CopyBan&);CopyBan& operator=(const CopyBan&);//...
};
C++11:
C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上
=delete,表示让编译器删除掉该默认成员函数。
示例代码:
class CopyBan
{// ...CopyBan(const CopyBan&) = delete;CopyBan& operator=(const CopyBan&) = delete;//...};
二、设计一个只能在堆上创建对象的类
实现方式:
1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
方法一:
class HeapOnly
{
public://提供在堆上创建对象的方法static HeapOnly* CreateObj(){return new HeapOnly;}//将拷贝构造和赋值重载也禁止HeapOnly(const HeapOnly&) = delete;HeapOnly& operator=(const HeapOnly&) = delete;
private://将构造私有,防止外界直接创建对象HeapOnly(){}
};int main()
{//静态区上创建对象//static HeapOnly hp0;// 栈上创建对象//HeapOnly hp1;//堆上创建对象//HeapOnly* hp2 = new HeapOnly;HeapOnly* hp3 = HeapOnly::CreateObj();//要防止别人通过这种方式在栈上创建对象//通过禁止拷贝构造来防止这种方式//HeapOnly hp4(*hp3);//手动释放堆上的资源delete hp3;return 0;
}
解释:上面代码是通过私有构造函数的方式来阻止外界自己创建对象,并提供一个在堆上创建对象的方法,使得外界只能在堆上创建对象,将拷贝构造和赋值重载禁止是防止别人像图中那样通过这两个方法在栈上创建对象。
方法二:
class HeapOnly
{
public:void Destroy(){delete this;}private://析构函数私有化~HeapOnly(){}
};int main()
{//static HeapOnly hp0;//HeapOnly hp1;HeapOnly* hp2 = new HeapOnly;//delete hp2;hp2->Destroy();return 0;
}
解释:该方法是通过私有析构函数的方式使外界无法自动调用析构函数,进而无法创建对象,只能在堆上创建对象,因为在堆上申请的空间需要自己主动释放,不会自动调用析构。这种实现的方法无需禁止拷贝构造和赋值重载,因为通过这两种方式创建出来的栈上的对象仍会因为无法调用析构而无法创建。
三、设计一个只能在栈上创建对象的类
方法一:同上将构造函数私有化,然后设计静态方法创建对象返回,并禁止掉重载的new和delete。
class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}//StackOnly(const StackOnly& s) = delete;void* operator new(size_t size) = delete;void operator delete(void* p) = delete;
private:StackOnly():_a(0){}
private:int _a;
};int main()
{//static StackOnly s1;//StackOnly s2;//StackOnly* s3 = new StackOnly;StackOnly s4 = StackOnly::CreateObj();//StackOnly* s5 = new StackOnly(s4);static StackOnly s6(s4);return 0;
}
解释:私有构造函数,并提供创建对象的方法,这样外界无法自己创建对象,只能使用提供的方法在栈上创建对象。但如果只是这样外界可以通过拷贝构造在堆上或在静态区创建对象,可我们不能禁止掉拷贝构造,因为在栈上创建对象并返回,会用到拷贝构造,如上述代码中s4接收返回的栈上的对象就是将栈上的对象拷贝给s4的,所以我们重载new和delete,C++中如果我们重载了这两个方法,那么我们调用这两个方法时会优先调用我们自己的而不是库的,我们再将这两个方法禁止,这样就阻止别人在堆上创建对象了。但是在静态区禁止不了。
方法二:同上将构造函数私有化,然后设计静态方法创建对象返回,并禁止掉拷贝构造,但提供移动构造。
class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}StackOnly(const StackOnly&& s){//......}StackOnly(const StackOnly& s) = delete;
private:StackOnly():_a(0){}
private:int _a;
};int main()
{StackOnly s4 = StackOnly::CreateObj();//StackOnly* s5 = new StackOnly(s4);//static StackOnly s6(s4);//这种方式禁止不掉StackOnly* s5 = new StackOnly(move(s4));static StackOnly s6(move(s4));return 0;
}
解释:提供的在栈上创建对象的方法返回的是匿名对象,是右值,可以通过移动构造赋值出去,这样外界用事先创建好的对象再通过拷贝的方式在堆上或者在静态区创建对象就创建不了了,但如果有人将左值move成右值再去拷贝,那就阻止不了了。
四、设计一个不能被继承的类
C++98方式:构造函数私有化,派生类中调不到基类的构造函数。则无法继承
示例代码:
// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}private:NonInherit(){}
};
C++11方法:final关键字,final修饰类,表示该类不能被继承。
示例代码:
class A final
{// ....
};
五、设计一个只能创建一个对象的类(单例模式)
设计模式:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的 总结。为什么会产生设计模式这样的东西呢?就像人类历史发展会产生兵法。最开始部落之间打 仗时都是人拼人的对砍。后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后 来孙子就总结出了《孙子兵法》。孙子兵法也是类似。
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模 式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
单例模式:
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个 访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置 信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再 通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
单例模式有两种实现模式:
- 饿汉模式
就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。
// 饿汉模式
// 1、多个饿汉模式的单例,某个对象初始化内容较多(读文件),会导致程序启动慢
// 2、A和B两个饿汉,对象初始化存在依赖关系,要求A先初始化,B再初始化,饿汉无法保证
class InfoMgr
{
public:static InfoMgr& GetInstance(){return _ins;}void Print(){cout << _ip << endl;cout << _port << endl;cout << _buffSize << endl;}
private:InfoMgr(const InfoMgr&) = delete;InfoMgr& operator=(const InfoMgr&) = delete;InfoMgr(){cout << "InfoMgr()" << endl;}
private:string _ip = "127.0.0.1";int _port = 80;size_t _buffSize = 1024 * 1024;//...static InfoMgr _ins;
};InfoMgr InfoMgr::_ins;int main()
{InfoMgr::GetInstance().Print();//InfoMgr copy(InfoMgr::GetInstance());return 0;
}
解释:首先单例模式只允许一个类创建一个对象,所以还是将构造函数,拷贝构造,赋值重载全部禁掉,防止外界自己创建对象,然后再类里面添加一个私有的静态的类的对象,这个对象因为是静态的,不会存在类中,存在静态区,所以不会造成类里面有类对象,类对象里面又有类对象这种无穷套娃的问题,这里将该类的对象放到类中是为了让它受到类域的限制,不让外界随意访问,其实就相当于静态的全局变量(但被类域限制着),当程序一启动,这个对象就会被创建,我们再提供一个方法供外界获取这个对象即可。
注意点:首先,多个饿汉模式的单例,某个对象初始化内容较多(如需要读文件),会导致程序启动慢。其次,A和B两个饿汉,对象初始化存在依赖关系,要求A先初始化,B再初始化,饿汉无法保证,因为都是全局变量,谁先初始化无法保证。
如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避 免资源竞争,提高响应速度更好。
- 懒汉模式
如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化, 就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。
// 懒汉模式
class InfoMgr
{
public:static InfoMgr& GetInstance(){// 第一次调用时创建单例对象// 有线程安全的风险if (_pins == nullptr){_pins = new InfoMgr;}return *_pins;}void Print(){cout << _ip << endl;cout << _port << endl;cout << _buffSize << endl;}static void DelInstance(){delete _pins;_pins = nullptr;}private:InfoMgr(const InfoMgr&) = delete;InfoMgr& operator=(const InfoMgr&) = delete;InfoMgr(){cout << "InfoMgr()" << endl;}
private:string _ip = "127.0.0.1";int _port = 80;size_t _buffSize = 1024 * 1024;//...static InfoMgr* _pins;
};InfoMgr* InfoMgr::_pins = nullptr;int main()
{InfoMgr::GetInstance().Print();InfoMgr::GetInstance().Print();return 0;
}
解释:和饿汉思路类似,只不过懒汉不能一开始就创建好这个唯一的类对象,只有当需要的时候才会创建,不过这里懒汉的对象是在堆上创建的,可以对外提供一个释放资源的方法。
注意点:懒汉模式创建对象时有线程风险问题,这里只是演示一下基本思路,所以代码并没有做的非常严谨,如果想解决这个问题可以加锁。
方法二:(此方法适用C++11之后)
class InfoMgr
{
public:static InfoMgr& GetInstance(){// 第一次调用时创建单例对象// C++11之后static InfoMgr ins;return ins;}void Print(){cout << _ip << endl;cout << _port << endl;cout << _buffSize << endl;}
private:InfoMgr(const InfoMgr&) = delete;InfoMgr& operator=(const InfoMgr&) = delete;InfoMgr(){cout << "InfoMgr()" << endl;}
private:string _ip = "127.0.0.1";int _port = 80;size_t _buffSize = 1024 * 1024;//...
};int main()
{InfoMgr::GetInstance().Print();InfoMgr::GetInstance().Print();cout << &InfoMgr::GetInstance() << endl;cout << &InfoMgr::GetInstance() << endl;return 0;
}
解释:这里提供一个局部的静态变量,而不是全局的,这样只有第一次需要的时候才会创建,后面因为是静态变量,再去申请对象时使用的是前面创建好的静态对象。
六、C语言中的类型转换
在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与 接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型 转换和显式类型转换。
- 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
- 显式类型转化:需要用户自己处理
缺陷:转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换。
七、C++中的三类类型转换
内置类型之间:
- 隐式类型转换 整形之间/整形和浮点数之间
- 显示类型的转换 指针和整形、指针之间
示例代码:
// a、内置类型之间
// 1、隐式类型转换 整形之间/整形和浮点数之间
// 2、显示类型的转换 指针和整形、指针之间int main()
{int i = 1;// 隐式类型转换double d = i;printf("%d, %.2f\n", i, d);int* p = &i;// 显示的强制类型转换int address = (int)p;printf("%p, %d\n", p, address);return 0;
}
内置类型和自定义类型之间:
- 自定义类型 = 内置类型 ->构造函数支持
- 内置类型 = 自定义类型 ->operator重载支持
示例代码:
// b、内置类型和自定义类型之间
// 1、自定义类型 = 内置类型 ->构造函数支持
// 2、内置类型 = 自定义类型
class A
{
public://explicit A(int a) //explicit关键字可以禁止隐式转换,必须显示转换A(int a):_a1(a),_a2(a){}A(int a1, int a2):_a1(a1), _a2(a2){}//自定义类型 -> 内置类型// ()被仿函数占用了,不能用// operator 类型实现,有返回值,无返回类型// 默认返回类型就是要转换的类型//explicit operator int()operator int(){return _a1 + _a2;}
private:int _a1 = 1;int _a2 = 1;
};
int main()
{//内置类型转换自定义类型string s1 = "1111111";A aa1 = 1;//A aa1 = (A)1;A aa2 = { 2,2 };const A& aa3 = { 2,2 };//自定义类型转换内置类型int z = aa1.operator int();//int x = (int)aa1;int x = aa1;int y = aa2;cout << x << endl;cout << y << endl;//库里的shared_ptr提供了转换为bool类型的重载函数std::shared_ptr<int> foo;std::shared_ptr<int> bar(new int(34));//这里本质是转换为了bool类型//if (foo.operator bool())if (foo)std::cout << "foo points to " << *foo << '\n';else std::cout << "foo is null\n";if (bar)std::cout << "bar points to " << *bar << '\n';elsestd::cout << "bar is null\n";return 0;
}
自定义类型和自定义类型之间:
- 对应的构造函数支持
示例代码:
// c、自定义类型和自定义类型之间 -- 对应的构造函数支持
class A
{
public:A(int a):_a1(a), _a2(a){}A(int a1, int a2):_a1(a1), _a2(a2){}int get() const{return _a1 + _a2;}
private:int _a1 = 1;int _a2 = 1;
};class B
{
public:B(int b):_b1(b){}B(const A& aa):_b1(aa.get()){}private:int _b1 = 1;
};#include"List.h"
#include<list>int main()
{A aa1(1);B bb1(2);bb1 = aa1;B& ref1= bb1;const B& ref2 = aa1;bit::list<int> lt = { 1,2,3,4 };// 权限的缩小?权限缩小和放大,仅限于const的指针和引用// 不是权限缩小,这里类型转换bit::list<int>::const_iterator cit = lt.begin();while (cit != lt.end()){cout << *cit << " ";++cit;}cout << endl;return 0;
}
解释:上面代码中涉及到一个从普通迭代器到const迭代器的转换问题,这不属于权限缩小,权限问题只有在指针和引用中存在,这里无法转换是因为迭代器的实现使用了模版,模版实例化后普通迭代器和const迭代器本就是不同的类型,所以这里是类型不同导致相互之间无法赋值,解决办法如下图。
解释:我们需要再迭代器中增加一个方法,这个方法的形参必须是普通迭代器类型,当该迭代器模版实例化为普通迭代器后,这个函数在普通迭代器中就是拷贝构造,当该迭代器模板实例化为const迭代器后,这个函数在const迭代器中就能够将传入的普通迭代器转换为const迭代器。
八、C++强制类型转换
8.1、为什么C++需要四种类型转换
C风格的转换格式很简单,但是是有不少缺点的:
- 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
- 显式类型转换将所有情况混合在一起,代码不够清晰
因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的 转化风格。标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:
- static_cast
- reinterpret_cast
- const_cast
- dynamic_cast
8.2、static_cast
static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用。但它不能用于两个不相关的类型进行转换。(即static_cast对应隐式类型转换)
示例代码:
int main()
{// 对应隐式类型转换 -- 数据的意义没有改变double d = 12.34;int a = static_cast<int>(d);cout << a << endl;return 0;
}
8.3、reinterpret_cast
reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型。(即reinterpret_cast对应强制类型转换)
示例代码:
int main()
{// 对应隐式类型转换 -- 数据的意义没有改变double d = 12.34;int a = static_cast<int>(d);cout << a << endl;// 对应强制类型转换 -- 数据的意义已经发生改变int* p1 = reinterpret_cast<int*>(a);;return 0;
}
8.4、const_cast
const_cast最常用的用途就是删除变量的const属性,方便赋值。
示例代码:
int main()
{// 对应强制类型转换中有风险的去掉const属性//volatile const int b = 2;const int b = 2;int* p2 = const_cast<int*>(&b);*p2 = 3;cout << b << endl;cout << *p2 << endl;return 0;
}
解释:上面代码中存在一个问题这里我们确实将b的值改变了,但是如果我们直接打印b的值会发现打印出来的值还是变化前的,这是因为编译器可能直接将b当做一个常量(2)输出出来了,或者从寄存器中直接获取的b的值,而没有重新上内存中获取新的值,导致使用时还是旧值。我们可以通过关键字volatile解决这个问题,被该关键字修饰后每次都会上内存中去取值,确保拿到更新后的新值。
8.5、dynamic_cast
dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
- 向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
- 向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
注意:
- dynamic_cast只能用于父类含有虚函数的类。
- dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0(即空指针)。
示例代码:
class A
{
public:virtual void f() {}int _a = 1;
};class B : public A
{
public:int _b = 2;
};void fun(A* pa)
{// dynamic_cast会先检查是否能转换成功(指向子类对象),能成功则转换,// (指向父类对象)不能则返回NULL// 指向父类转换时有风险的,后续访问存在越界访问的风险// 指向子类转换时安全B* pb1 = dynamic_cast<B*>(pa);if (pb1){cout << "pb1:" << pb1 << endl;cout << pb1->_a << endl;cout << pb1->_b << endl;pb1->_a++;pb1->_b++;cout << pb1->_a << endl;cout << pb1->_b << endl;}else{cout << "转换失败" << endl;}
}int main()
{A a;B b;fun(&a);fun(&b);return 0;
}
解释:子类转父类没有问题,主要是父类转子类,当父类指针指向子类对象时可以转换成功,当父类指针指向父类对象时会转换失败。
注意:强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用域,以减少发生错误的机会。强烈建议:避免使用强制类型转换
九、RTTI
RTTI:Run-time Type identification的简称,即:运行时类型识别。
C++通过以下方式来支持RTTI:
- typeid运算符
- dynamic_cast运算符
- decltype
相关文章:
C++之特殊类设计及类型转换
目录 一、设计一个不能被拷贝的类 二、设计一个只能在堆上创建对象的类 三、设计一个只能在栈上创建对象的类 四、设计一个不能被继承的类 五、设计一个只能创建一个对象的类(单例模式) 六、C语言中的类型转换 七、C中的三类类型转换 八、C强制类型转换 8.1、为什么C需…...
【Linux】C语言补充知识
有一些Linux常见的C语言用法需要哈好复习一下。 部分图片和经验来源于网络,若有侵权麻烦联系我删除,主要是做笔记的时候忘记写来源了,做完笔记很久才写博客。 专栏目录:记录自己的嵌入式学习之路-CSDN博客 1 结构体 1.1 结…...
怎么查看数据库容量
要查看数据库容量,你需要登录数据库管理系统,然后执行相应的 SQL 查询语句。不同的数据库管理系统有不同的语法,以下是一些常见的数据库管理系统中查看数据库容量的 SQL 查询语句示例: MySQL/MariaDB: SELECT table_schema &quo…...
深度学习中卷积的计算复杂度与内存访问复杂度
深度学习中卷积的计算复杂度与内存访问复杂度 在深度学习中,普通卷积(Standard Convolution)、深度可分离卷积(Depthwise Separable Convolution, DWConv)和部分卷积(Partial Convolution, PConvÿ…...
神经网络—损失函数
文章目录 前言一、损失函数概念二、损失函数原理1、分类问题中常见的损失函数(1)0-1损失函数原理优缺点 (2)交叉熵损失(Cross-Entropy Loss)原理优缺点 (3) 合页损失(Hin…...
Rust中避免过度使用锁导致性能问题的策略
一、引言 在 Rust 多线程编程中,锁是实现线程同步的重要工具,它可以防止多个线程同时访问和修改共享数据,从而避免数据竞争和不一致的问题。然而,过度使用锁会带来严重的性能问题,如锁竞争导致的线程阻塞、上下文切换…...
Qt connect第五个参数
在 Qt 中,QObject::connect 函数的第五个参数用于指定 连接类型(Qt::ConnectionType),它决定了信号与槽之间的通信方式。以下是各枚举值的详解及使用场景: 1. Qt::AutoConnection(默认值) 行为…...
QT —— 信号和槽(带参数的信号和槽函数)
QT —— 信号和槽(带参数的信号和槽函数) 带参的信号和槽函数信号参数个数和槽函数参数个数1. 参数匹配规则2. 实际代码示例✅ 合法连接(槽参数 ≤ 信号参数)❌ 非法连接(槽参数 > 信号参数) 3. 特殊处理…...
极简GIT使用
只为极简使用。 创建本地仓库 初始化git仓库 1.创建一个新文件夹 2.在文件夹内打开git bash 之后进入如下界面,输入git init,这样此文件就可以使用git了。 在此文件夹中,除了.git文件外,其他全部都是工作文件。 接下来将以一个…...
【嵌入式———通用定时器基本操作——实验需求2:案列:测量PWM的频率/周期】
通用定时器输入捕获 需求:把测到的结果通过串口发送到电脑,检查测试结果。 在溢出之前,两次上升/下降沿记录时间。 345部分 滤波器:用来滤掉一些毛刺信息,信号质量好可以不滤波 边沿检测器:确定要捕获的是…...
兰亭妙微:数据驱动的 B 端设计:如何用 UI 提升企业级产品体验?
在数字化转型的浪潮中,企业级产品的用户体验成为了决定产品竞争力的关键因素。对于 B 端产品而言,其使用场景复杂、用户需求多元,如何通过 UI 设计提升产品体验,成为了摆在设计者面前的重要课题。而数据驱动的设计方法&#x…...
Spring AOP---面向切面编程由认识到使用
1. AOP AOP(Aspect-Oriented Programming), 是一种思想, 面向切面编程。 在前文统一异常处理,统一结果返回就是使用了这一思想(都是在集中处理某一类事情, 但又不影响原有代码的正常运行),但他们不是AOP,只是应用了这…...
深入解析 Python 应用日志监控:ELK、Graylog 的实战指南
深入解析 Python 应用日志监控:ELK、Graylog 的实战指南 引言 在现代应用开发中,日志不仅仅是用于记录错误和调试信息,它更是系统运行状况的窗口,帮助开发者和运维人员监控、优化应用性能。Python 作为广泛应用的开发语言,其应用日志管理的重要性不言而喻。而 ELK(Elas…...
贝叶斯算法实战:从原理到鸢尾花数据集分类
贝叶斯算法实战:从原理到鸢尾花数据集分类 在机器学习的广阔领域中,贝叶斯算法以其基于概率推理的独特优势,成为数据分类和预测的重要工具。今天,我们将通过一段Python代码,深入探讨贝叶斯算法在鸢尾花数据集分类任务…...
CSS学习笔记14——移动端相关知识(rem,媒体查询,less)
移动端 rem适配布局 rem单位 rem基准是相对于html元素的字体大小 父元素设定font-size,子元素根据rem缩放对应字体大小 媒体查询(Media Query) media可以针对不同屏幕尺寸设置不同样式当你重置浏览器大小过程中,页面也会根据…...
使用Node编写轻量级后端快速入门
使用Node编写轻量级后端快速入门 node 要作为轻量级后端需要下载一些对应模块可以参考下面命令。你可以借助 npm(Node Package Manager)来下载它们。 模块下载 express:这是一个广受欢迎的 Node.js Web 应用框架,能用于构建 Web…...
海量数据存储与分析:HBase vs ClickHouse vs Doris 三大数据库优劣对比指南
1.引言 在当今大数据时代,数据正以前所未有的速度持续增长。来自各个领域的数据,如互联网行业用户的每一次点击、浏览记录,金融机构的海量交易数据,以及物联网设备源源不断上传的实时监测数据等,其规模呈指数级攀升。…...
Redis 挂掉后高并发系统的应对策略:使用 Sentinel 实现限流降级与 SkyWalking 监控优化
前言 在现代分布式系统中,Redis 被广泛用作缓存中间件以提升性能和减轻数据库压力。然而,在高并发场景下,一旦 Redis 出现故障(如宕机、网络中断等),如果没有有效的容错机制,可能会导致大量请求…...
C++11新特性_自动类型推导_decltype
decltype 是 C11 引入的一个关键字,用于在编译时推导表达式的类型。它提供了一种方式,让编译器根据表达式的类型来确定变量的类型,而不需要显式地指定类型。下面为你详细介绍 decltype 的使用方法和应用场景。 基本语法 decltype 的基本语法…...
Scrapy爬虫实战总结:动态与登录爬取的精炼经验
引言 在AI时代,信息和数据往往成就你的速度和高度。。。 这篇文章基于前两篇的实践基础之上的一次小结,通过“爬取动态网页”和“登录网站”两场实战,我用Scrapy+Splash破译JavaScript,用FormRequest敲开权限大门。这篇总结凝练两场冒险的体验,淬炼Scrapy爬虫的通用经验…...
windows系统搭建自己的ftp服务器,保姆级教程(用户验证+无验证)
前言 最近在搭建环境时,我发现每次都需要在网上下载依赖包和软件,这不仅耗时,而且有时还会遇到网络不稳定的问题,导致下载速度慢或者中断,实在不太方便。于是,我产生了搭建一个FTP服务器的想法。通过搭建FT…...
PDF本地化开源项目推荐
Stirling-PDF 项目详细总结 1. 项目概述 Stirling-PDF 是一个基于 Docker 的本地化 Web 应用,专注于 PDF 文件的多样化处理。其核心特点是: 完全本地化部署:所有文件处理均在用户设备或服务器内存中进行,任务完成后自动清理临…...
从工厂到生活:算法 × 深度学习,正在改写自动化的底层逻辑
一.背景: 从工业革命时期的机械自动化,到信息时代的智能自动化,人类对自动化技术的追求从未停歇。近年来,随着物联网、大数据、云计算等技术的蓬勃发展,自动化系统的复杂度与智能化程度显著提升。算法与深度学习的深度…...
如何拿奖蓝桥杯
要在蓝桥杯中拿奖,可参考以下方法: 备赛规划方面 - 明确目标与计划:选择自己感兴趣或有基础的组别,了解比赛大纲和历年真题,制定包含基础语法学习、算法入门、真题训练等阶段的合理学习计划。 - 合理安排时间…...
【STM32单片机】#12 SPI通信(软件读写)
主要参考学习资料: B站江协科技 STM32入门教程-2023版 细致讲解 中文字幕 开发资料下载链接:https://pan.baidu.com/s/1h_UjuQKDX9IpP-U1Effbsw?pwddspb 单片机套装:STM32F103C8T6开发板单片机C6T6核心板 实验板最小系统板套件科协 目录 SPI…...
从请求到响应:初探spring web
引入: 首先小编想分享下一些开发小知识 2000年——手写servlet/JSP时代 在这个阶段中,那时候写后端代码,可谓是个麻烦事。 毕竟什么都要自己干 发来的请求都要写extends HttpServlet的类,手动在web.xml配置 <servlet>…...
【中间件】bthread_基础_TaskControl
TaskControl 1 Definition2 Introduce**核心职责** 3 成员解析**3.1 数据结构与线程管理****3.2 任务调度与负载均衡****3.3 线程停放与唤醒(ParkingLot)****3.4 统计与监控** 4 **工作流程**5 **设计亮点**6 **使用场景示例**7 **总结**8 学习过程中的疑…...
systemd和OpenSSH
1 systemd 1.1 配置文件 /etc/systemd/system /lib/systemd/system /run/systemd/system /usr/lib/systemd/user 1.2 commands systemctl list-unit-files | grep enable systemctl cat dlt-daemon.service systemctl cat dlt-system.service systemctl show dlt-daemon.ser…...
08 Python集合:数据 “去重神器” 和运算魔法
文章目录 一、Python 中的集合概述1. 集合的特性 二、集合的创建三、元素的遍历四、集合的运算1. 成员运算2. 二元运算3. 比较运算 五、集合的方法六、不可变集合 一、Python 中的集合概述 在 Python 里,集合(Set)是一种无序且元素唯一的数据…...
配置和使用基本存储
配置和使用基本存储 文章目录 配置和使用基本存储[toc]一、什么是卷?二、卷的类型三、使用EmptyDir卷存储数据1.了解EmptyDir卷2.测试EmptyDir卷的使用 四、使用HostPath卷挂载宿主机文件1.了解HostPath卷2.测试HostPath卷的使用 五、使用NFS卷挂载NFS共享目录1.准备…...
win11 终端 安装ffmpeg 使用终端Scoop
1、安装scoop (Windows 包管理器) Set-ExecutionPolicy RemoteSigned -Scope CurrentUser iwr -useb get.scoop.sh | iex 2、使用scoop来安装ffmpeg scoop install ffmpeg 3、测试一下ffmpeg,将Mp3文件转为Wav文件 ffmpeg -i A.mp3 A.wav 然后我们就看到A.wav生成…...
navicat中导出数据表结构并在word更改为三线表(适用于navicat导不出doc)
SELECTCOLUMN_NAME 列名,COLUMN_TYPE 数据类型,DATA_TYPE 字段类型,IS_NULLABLE 是否为空,COLUMN_DEFAULT 默认值,COLUMN_COMMENT 备注 FROMINFORMATION_SCHEMA.COLUMNS WHEREtable_schema db_animal(数据库名) AND table_name activity(…...
Azure Monitor 实战指南:全方位监控应用与基础设施
Azure Monitor 是 Azure 云原生的统一监控解决方案,能够实时追踪应用性能、基础设施健康状态及日志数据。本文将通过 实战步骤 演示如何利用 Azure Monitor 监控 GPT-4 服务、虚拟机、存储等资源,并结合自动化告警和日志分析,构建企业级监控体系。 1. Azure Monitor 核心功能…...
【人工智能】释放本地AI潜能:LM Studio用户脚本自动化DeepSeek的实战指南
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 随着大型语言模型(LLM)的快速发展,DeepSeek以其高效的性能和开源特性成为开发者关注的焦点。LM Studio作为一款强大的本地AI模型管理工具…...
智能体-CyberTask Orchestrator设计概要(V4.1超长版)
智能体-CyberTask Orchestrator设计概要(V4.0超长版) 一、深度演进背景与战略定位(核心篇幅拓展至2187字) (本段新增行业趋势与技术必要性论证) 1.1 全球网络安全威胁态势分析(2023-2025&…...
C# 面向对象实例演示
C# 面向对象编程实例演示 一、基础概念回顾 面向对象编程(OOP)的四大基本特性: 封装 - 将数据和操作数据的方法绑定在一起继承 - 创建新类时重用现有类的属性和方法多态 - 同一操作作用于不同对象产生不同结果抽象 - 简化复杂系…...
软件产品测试报告:如何全面评估及保障软件质量?
软件产品测试报告可以对软件产品质量做全面评估,还能够把评估结果展示出来,它依靠一系列测试手段和数据分析,能为产品的完善以及决策提供重要依据。下面从不同方面展开说明。 测试目的 开展本次软件产品测试,主要目的有三个。一…...
leetcode42-接雨水
leetcode 42 思路 本题使用 单调栈 来计算每个位置能够接住的雨水量 理解问题 题目要求计算一系列柱子之间可以接住的雨水量。输入是一个数组,每个元素代表柱子的高度。输出是一个整数,表示能够接住的水量。 找到边界条件 什么情况下可以接住雨水…...
普通IT的股票交易成长史--20250430晚
声明:本文章的内容只是自己学习的总结,不构成投资建议。文中观点基本来自yt站Andylee,美股Alpha姐,综合自己的观点得出。感谢他们的无私分享。 送给自己的话: 仓位就是生命,绝对不能满仓!&…...
Elastic Security 8.18 和 9.0 中的新功能
作者:来自 Elastic Mark Settle, Tamarian Del Conte, James Spiteri, Tinsae Erkailo, Charles Davison, Raquel Tabuyo, Kseniia Ignatovych, Paul Ewing, Smriti 检测规则的自动迁移、用于 ES|QL 的 Lookup Join、AI 功能增强,以及更多功能。 Elasti…...
使用 Vue 开发 VS Code 插件前端页面(上)
本文的方案主要参考了这篇博客: Vscode 的 extension webview 开发示例: Vue 和 React 实现 https://juejin.cn/post/7325132202970136585样例项目地址: github | vscode-webview-with-vuehttps://github.com/HiMeditator/vscode-webview-w…...
Vue Router路由原理
Vue Router 是 Vue.js 官方的路由管理器,它与 Vue.js 核心深度集成,使得构建单页应用(SPA)变得非常容易。Vue Router 的主要功能包括动态路由匹配、嵌套路由、编程式导航、命名路由、路由守卫等 Vue Router 原理 单页应用&#x…...
Tauri v1 与 v2 配置对比
本文档对比 Tauri v1 和 v2 版本的配置结构和内容差异,帮助开发者了解版本变更并进行迁移。 配置结构变化 v1 配置结构 {"package": { ... },"tauri": { "allowlist": { ... },"bundle": { ... },"security":…...
详解 MyBatis-Plus 框架中 QueryWrapper 类
QueryWrapper 一、 QueryWrapper 的概念为什么需要 QueryWrapper? 二、 QueryWrapper 的基本使用1. 创建 QueryWrapper 实例2. 添加查询条件3. 执行查询 三、 QueryWrapper 的常见方法1. 基本条件方法1.1 eq - 等于1.2 ne - 不等于1.3 gt - 大于1.4 ge - 大于等于1.…...
小米MiMo-7B大模型:解锁推理潜力的新传奇!
在大语言模型(LLMs)蓬勃发展的时代,推理能力成为衡量模型优劣的关键指标。今天为大家解读的这篇论文,介绍了小米的MiMo-7B模型,它通过独特的预训练和后训练优化,展现出强大的推理实力,快来一探究…...
联邦学习的收敛性分析(全设备参与,不同本地训练轮次)
联邦学习的收敛性分析 在联邦学习中,我们的目标是分析全局模型的收敛性,考虑设备异构性(不同用户的本地训练轮次不同)和数据异质性(用户数据分布不均匀)。以下推导从全局模型更新开始,逐步引入假设并推导期望损失的递减关系,最终给出收敛性结论。 1. 全局模型更新与泰…...
硬件工程师面试常见问题(10)
第四十六问:锁存器,触发器,寄存器三者的区别 触发器:能够存储一位二值信号的基本单元电路统称为 "触发器"。(单位) 锁存器:一位触发器只能传送或存储一位数据,而在实际工…...
1295. 统计位数为偶数的数字
题目 解法一 遍历数组挨个判断元素位数并统计(我的第一想法) class Solution { public:int findNumbers(vector<int>& nums) {int result 0;for(int n: nums){if(judge(n)) result;}return result;}bool judge(int a){int sum 1;a a / 10…...
3.1/Q1,Charls最新文章解读
文章题目:Social participation patterns and associations with subsequent cognitive function in older adults with cognitive impairment: a latent class analysis DOI:10.3389/fmed.2025.1493359 中文标题:认知障碍老年人的社会参与模…...
楼宇智能化四章【期末复习】
四、火灾自动报警系统 结构组成:火灾探测器、区域报警器、集中报警器 形式:1. 多线制系统 2.总线制系统 3.集中智能系统 4.分布智能系统 5.网络通信系统 工作原理: 以下是关于火灾自动报警系统及相关灭火系统的详细解答: 1. 火灾自动报警系统有哪几种形式? 区…...