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语言中总共有两种形式的类型转换:隐式类型 转换和显式类型转换。

  1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
  2. 显式类型转化:需要用户自己处理

缺陷:转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换。

七、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风格的转换格式很简单,但是是有不少缺点的:

  1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
  2. 显式类型转换将所有情况混合在一起,代码不够清晰

因此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转型是安全的)

注意:

  1. dynamic_cast只能用于父类含有虚函数的类。
  2. 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:

  1. typeid运算符
  2. dynamic_cast运算符
  3. decltype

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/81809.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

制作一款打飞机游戏36:调度编辑器

我们正在创建一个调度编辑器。嗯&#xff0c;这个名字听起来可能有点奇怪&#xff0c;对吧&#xff1f;但如果你了解射击游戏中的“调度”&#xff0c;那就是敌人出现的时间表。 你可能已经看到了&#xff0c;我们有一个可以滚动的关卡。现在&#xff0c;我想增加一些交互性&a…

wordperss AI插件:AI图文+视频+长尾关键词自动生成,已内置deepseek、kimi全模型,支持简单一键接入更多自定义API

【2.17最新版】Linkreate wordperss AI插件&#xff1a;AI图文视频长尾关键词自动生成&#xff0c;已内置deepseek、kimi全模型。 支持自定义接入其它API&#xff0c;包括但不限于腾讯云API和它的deepseek模型 后台只需要设置对应的API url 、模型 、API key,就可以让插件调用…

从零开始学Python:开启编程新世界的大门

在当今数字化时代&#xff0c;Python作为一门简洁、高效且功能强大的编程语言&#xff0c;受到了越来越多人的喜爱与追捧。无论是数据科学、人工智能、Web开发&#xff0c;还是自动化脚本编写&#xff0c;Python都展现出了卓越的能力。本文将带领大家踏上Python学习之旅&#x…

【PostgreSQL数据分析实战:从数据清洗到可视化全流程】3.2 缺失值检测与处理(NULL值填充/删除策略)

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 缺失值检测与处理全攻略&#xff1a;NULL值填充与删除策略实战3.2 缺失值检测与处理3.2.1 缺失值类型与业务影响3.2.1.1 缺失值的三种形态3.2.1.2 业务影响分级 3.2.2 缺失值…

Java求职面试:Spring Boot与微服务的幽默探讨

Java求职者面试&#xff1a;技术与幽默的碰撞 场景概述 在某互联网大厂的面试现场&#xff0c;面试官严肃认真&#xff0c;程序员则是一个搞笑的水货角色。面试者名叫张伟&#xff0c;年龄28岁&#xff0c;硕士学历&#xff0c;拥有5年的Java开发经验。以下是面试的详细过程。…

使用 NGINX 实现 HTTP Basic 认证ngx_http_auth_basic_module 模块

一、前言 在 Web 应用中&#xff0c;对部分资源进行访问控制是十分常见的需求。除了基于 IP 限制、JWT 验证、子请求校验等方式外&#xff0c;最经典也最简单的一种方式便是 HTTP Basic Authentication。NGINX 提供的 ngx_http_auth_basic_module 模块支持基于用户名和密码的基…

map和set的设计以及红黑树的设计

1.map和set的底层是红黑树 2.map和set在STL是容器&#xff0c;在我看来&#xff0c;不过也是封装了平衡二叉搜索树红黑树的适配器 我们先看红黑树的设计&#xff0c;看完后map和set的封装易如反掌 #pragma once #include<utility> #include<iostream> using name…

Linux运维——Vim技巧二

Vim技巧 一、管理多个文件1.1、用缓冲区列表管理打开的文件1.2、用参数列表将缓冲区分组1.3、将工作区切分成窗口1.4、用标签页将窗口分组1.5、用:edit命令打开文件1.6、使用:find打开文件1.7、把文件保存到不存在的目录中 二、动作命令在文档中移动2.1、区分实际行与屏幕行2.2…

2025 年 408 真题及答案

2025 年 408 真题 历年408真题及答案下载直通车 1、以下 C 代码的时间复杂度是多少&#xff1f;&#xff08;&#xff09; int count 0; for (int i0; i*i<n; i)for (int j0; j<i; j)count;A O(log2n)B O(n)C O(nlogn)D O(n2) 2、对于括号匹配问题&#xff0c;符号栈…

【MuJoCo仿真】开源SO100机械臂导入到仿真环境

主要参考&#xff1a;https://github.com/jpata/gym-so100/tree/integration/gym_so100/assets/trs_so_arm100 参考&#xff1a;&#xff08;八&#xff09;lerobot开源项目扩展so100的仿真操控&#xff08;操作记录&#xff09;_so100机械臂 仿真-CSDN博客 下载&#xff1a;…

Socat 用法详解:网络安全中的瑞士军刀

Socat 用法详解&#xff1a;网络安全中的强大工具 引言 socat&#xff08;SOcket CAT&#xff09;是一款功能强大的命令行工具&#xff0c;被誉为“网络瑞士军刀”&#xff0c;广泛应用于数据传输、端口转发和网络调试等场景。它支持多种协议和数据通道&#xff08;如文件、管…

永磁同步电机控制算法--基于PI和前馈的位置伺服控制

一、原理介绍 永磁同步伺服系统是包含了电流环、速度环和位置环的三环控制系统。 伺服系统通过电流检测电路和光电编码器检测电动机三相绕组电流和转子位置θ&#xff0c;通过坐标变换&#xff0c;计算出转矩电流分量iq和励磁电流分量id。 位置信号指令与实际转子位置信号的差…

Lucene多种数据类型使用说明

Lucene 作为一款高性能的全文检索引擎库&#xff0c;其核心功能围绕索引和搜索文本数据&#xff0c;但它也支持多种数据类型以满足复杂的应用场景。以下是 Lucene 支持的主要数据类型及其用途的详细说明&#xff1a; 1. 文本类型&#xff08;Text&#xff09; 用途&#xff1a;…

Web网页布局

目录 一、传统的DIVCSS布局&#xff08;使用率最高的&#xff09; 1.div传统的一块块转 2.以猫眼电影为例‘ 3.div布局格式&#xff08;唯一的id属性&#xff0c;不唯一写class重复的&#xff09; 3.2总体布局样式 二、HTML5语义标签CSS3布局 1.把div改为绿色的语义标签…

大模型基础(五):transformers库(下):快速分词器、自动配置类、快速微调

transformers库&#xff08;下&#xff09; 1 快速分词器1.1 Fast 分词器的核心特点1.2 对比示例1.3 何时使用 Fast 分词器&#xff1f;1.4 注意事项 2 自动配置类 AutoConfig2.1 核心功能2.2 基本用法2.3 主要应用场景2.4 常用函数2.5 与具体配置类的区别2.6 注意事项 3 快速微…

在pycharm profession 2020.3上离线安装.whl类型的包(以PySimpleGUI为例)

今天写个小代码&#xff0c;用到了PySimpleGUI。 在pycharm profession 2020.3的项目中的Terminal里运行如下代码即可安装。 python3 -m pip install --force-reinstall --extra-index-url https://PySimpleGUI.net/install PySimpleGUI 安装方法如图&#xff1a; 安装后使用…

SpringBoot整合RabbitMQ(Java注解方式配置)

1.生产端 1. 创建生产者SpringBoot工程 2. 引入start&#xff0c;依赖坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency> 3. 编写yml配置&#xff0c;基本…

分析strtol(),strtoul()和strtod()三个函数的功能

字符串转换为数值部分和子字符串首地址的函数有strtol(),strtoul()和strtod()三个函数。 1、strtol()函数 long int strtol(const char *str, char **endptr, int base) //当base0时,若字符串不是以"0","0x"和"0X"开头,则将数字部分按照10进制…

Spring 的事务隔离

在Spring框架中&#xff0c;事务管理是一个非常重要的方面&#xff0c;它允许开发者以声明式的方式定义事务边界&#xff0c;并且通过配置不同的隔离级别来控制并发事务的行为。Spring支持多种事务管理方式&#xff0c;包括编程式事务管理和声明式事务管理&#xff08;如使用Tr…

单片机自动排列上料控制程序

/****L2233 CODE11549 2025 4 18 08:53*******/ /***轴承上料机控制 提升 摇摆 光电检测***/ /***2025 3 21 电机控制PCB板 PAST ***/ /*2.3 2.2 1.2 1.3 1.4 1.5 1.6 1.7 5.3 3.2 ***/ /*启动 解锁 光电 接近 前停 后停 电机前 电机后*/ #include &quo…