当前位置: 首页 > news >正文

特殊类设计

1.请设计一个类,不能被拷贝

拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝, 只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。

C++98的方式(只声明)

将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可。

原因:

1. 设置成私有:如果只声明没有设置成private,用户自己如果在类外定义了,就可以不 能禁止拷贝了

2. 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写 反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。

C++11的方式(=delete)

C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上

=delete表示让编译器删除掉该默认成员函数

2. 请设计一个类,只能在堆上创建对象

实现方式:

1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。

2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建

new的需要手动delete,其他两个会自动释放

解决办法1

直接把析构私有,让hp1和hp3无法自动析构

不过会引发hp2无法手动释放

解决办法

解决办法2

这样就会有可以拷贝hp2的情况(拷贝后可能在栈)

解决办法

把拷贝构造和赋值封死

3. 请设计一个类,只能在栈上创建对象

方法:

同上将构造函数私有化,然后设计静态方法创建对象返回即可。

因为这里的拷贝也符合了,所以就会出现以下问题(就可以在堆上开空间了)

重要知识点

解决办法:要先了解new的原理,这里new的时候不可以调用构造,但是还可以调用拷贝构造,但这里不能直接封了拷贝构造,因为StackOnly st用的是拷贝构造,new:会调用两个部分,一部分是构造一部分是operator new,之所以要调用operator new,而不直接调用malloc,是因为operator new会抛异常

4. 请设计一个类,不能被继承

C++98方式

// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承

class NonInherit{public:static NonInherit GetInstance(){return NonInherit();}private:NonInherit(){}
};

C++11方法(final)

final关键字,final修饰类,表示该类不能被继承。

class A  final{// ....};

5. 请设计一个类,只能创建一个对象(单例模式)

设计模式:

设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的 总结。为什么会产生设计模式这样的东西呢?就像人类历史发展会产生兵法。最开始部落之间打 仗时都是人拼人的对砍。后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后 来孙子就总结出了《孙子兵法》。孙子兵法也是类似。

使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模 式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

单例模式:

一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个 访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置 信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再 通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。 单例模式有两种实现模式:

饿汉模式

就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。

// 饿汉模式

// 优点:简单

// 缺点:可能会导致进程启动慢(都不知道是在初始化还是系统挂了),且如果有多个单例类对象实例启动顺序不确定。

第一步:构造函数私有(不能随意创建)

把map<string,string>设为私有

创建static变量

 类外声明

2、提供获取单例对象的接口函数

创建对象

问题(需要防止拷贝)

然后就会出现一个问题,没有绝对防死可以拷贝构造对象

Singleton copy(Singleton::GetInstance());

第三步防拷贝


添加数据并打印

 饿汉模式:一开始(main函数之前)就创建单例对象
静态的在main之前就创建了1、如果单例对象初始化内容很多,影响启动速度2、如果两个单例类,互相有依赖关系。 假设有A B两个单例类,要求A先创建,B再创建,B的初始化创建依赖A
class Singleton
{
public:// 2、提供获取单例对象的接口函数static Singleton& GetInstance()//instance是实例的意思{return _sinst;}//覆盖型的Addvoid Add(const pair<string, string>& kv){_dict[kv.first] = kv.second;}void Print(){for (auto& e : _dict){cout << e.first << ":" << e.second << endl;}cout << endl;}private:// 1、构造函数私有Singleton(){// ...}// 3、防拷贝Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;//使map全局只有唯一实例map<string, string> _dict;// ...//可以创建自己类型的对象,也不会套娃,因为静态的在静态区//静态的在main之前就创建了static Singleton _sinst;
};Singleton Singleton::_sinst;int main()
{//保证创建的都是一个对象//三个地址都一样,说明三个创建的是同一个cout << &Singleton::GetInstance() << endl;cout << &Singleton::GetInstance() << endl;cout << &Singleton::GetInstance() << endl;Singleton copy(Singleton::GetInstance());//添加数据Singleton::GetInstance().Add({ "1111","2222" });Singleton::GetInstance().Print();return 0;
}

如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避 免资源竞争,提高响应速度更好。

大问题用懒汉解决

1、如果单例对象初始化内容很多,影响启动速度
2、如果两个单例类,互相有依赖关系。 
假设有A B两个单例类,要求A先创建,B再创建,B的初始化创建依赖A,就没法用饿汉了,然后就有了下面的懒汉

懒汉模式

如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取 文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化, 就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。

// 懒汉

// 优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控 制。

// 缺点:复杂

//懒汉用的static指针,main之前创建一个指针不耽误时间
//顺序可以随便控制
//单例一般不用智能指针,所以需要显示释放
// 特殊场景:1、中途需要显示释放  2、程序结束时,需要做一些特殊动作(如持久化)

改进


//懒汉用的static指针,main之前创建一个指针不耽误时间
//顺序可以随便控制
//单例一般不用智能指针,所以需要显示释放
// 特殊场景:1、中途需要显示释放  2、程序结束时,需要做一些特殊动作(如持久化)namespace lazy
{class Singleton{public://改进::2// 2、提供获取单例对象的接口函数static Singleton& GetInstance(){if (_psinst == nullptr){// 第一次调用GetInstance的时候创建单例对象_psinst = new Singleton;}return *_psinst;}//改进::3// 一般单例不用释放。// 特殊场景:1、中途需要显示释放  2、程序结束时,需要做一些特殊动作(如持久化)static void DelInstance(){if (_psinst){delete _psinst;_psinst = nullptr;}}void Add(const pair<string, string>& kv){_dict[kv.first] = kv.second;}void Print(){for (auto& e : _dict){cout << e.first << ":" << e.second << endl;}cout << endl;}//改进::5,因为一个单例显示释放一次多个就要多次delete太麻烦//所以有了GC//用智能指针又没办法显示释放class GC{public:~GC(){lazy::Singleton::DelInstance();}};private:// 1、构造函数私有Singleton(){// ...}//程序结束后,把东西写入文件中(可持久化)~Singleton(){cout << "~Singleton()" << endl;//改进::4// map数据写到文件中,可持久化FILE* fin = fopen("map.txt", "w");for (auto& e : _dict){fputs(e.first.c_str(), fin);fputs(":", fin);fputs(e.second.c_str(), fin);fputs("\n", fin);}}// 3、防拷贝Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;map<string, string> _dict;// ...//改进::这里弄一个指针static Singleton* _psinst;//改进::5static GC _gc;};//类外定义Singleton* Singleton::_psinst = nullptr;//改进::5Singleton::GC Singleton::_gc;
}
int main()
{//Singleton s1;//Singleton s2;cout << &lazy::Singleton::GetInstance() << endl;cout << &lazy::Singleton::GetInstance() << endl;cout << &lazy::Singleton::GetInstance() << endl;//Singleton copy(Singleton::GetInstance());lazy::Singleton::GetInstance().Add({ "xxx", "111" });lazy::Singleton::GetInstance().Add({ "yyy", "222" });lazy::Singleton::GetInstance().Add({ "zzz", "333" });lazy::Singleton::GetInstance().Add({ "abc", "333" });lazy::Singleton::GetInstance().Print();//lazy::Singleton::DelInstance();lazy::Singleton::GetInstance().Add({ "abc", "444" });lazy::Singleton::GetInstance().Print();//lazy::Singleton::DelInstance();return 0;
}

http://www.mrgr.cn/news/35195.html

相关文章:

  • Tensorflow基本概念
  • linux逻辑卷练习
  • 网页作业9
  • 自动化运维(k8s):一键获取指定命名空间镜像包脚本
  • MySQL数据库:SQL语言入门 【2】(学习笔记)
  • 大模型时代,呼叫中心部门如何建设一套呼出机器人系统?
  • 一步一步优化一套生成式语言模型系统
  • 二分查找算法(8) _点名
  • Solidity——抽象合约和接口详解
  • 【python】数据类型
  • WebRtc实际应用
  • 【数学二】极限的计算- 等价无穷小替换、洛必达法则求极限
  • 找不到MFC140.dll无法继续执行代码怎么办,共有6种解决方法
  • 离线一机一码验证和网络验证的区别以及使用场景
  • Figma 中要放大并下载 UI 设计中的图标
  • 如何利用 Kafka,实时挖掘企业数据的价值?
  • 基于Ambari搭建大数据分析平台(30分钟速成)全网最全最详细的Ambari搭建大数据分析平台:
  • (13)mysql慢查询常用语句
  • 船只类型识别系统源码分享
  • 月考成绩发布步骤-易查分
  • 异云双活实践案例
  • 【Docker】如何让docker容器正常使用nvidia显卡
  • 大数据Flink(一百二十四):案例实践——淘宝母婴数据加速查询
  • CaLM 因果推理评测体系:如何让大模型更贴近人类认知水平?
  • 英码科技亮相华为全联接大会2024,携手共赢行业智能化
  • Mapbox封装图形绘制工具 线,圆,polygon,删除,点 mapbox-gl-draw-circle mapbox-gl-draw