中级C++:单例模式
文章目录
- 写一个不能被拷贝和复制的类
- 请设计一个类,只能在堆上创建对象
- 请设计一个类,只能在栈上创建对象
- 请设计一个类,不能被继承
- 设计模式
- 请设计一个类,只能创建一个对象(单例模式)
- 饿汉模式
- 懒汉模式
- 单例模式对象的销毁
- 展望
写一个不能被拷贝和复制的类
- 拷贝和赋值重载函数私有化。
- 分C++98和C++11写法;推荐C++11写法。
//C++98
class CopyBan
{// ...private:CopyBan(const CopyBan&);CopyBan& operator=(const CopyBan&);//...
};//C++11
class CopyBan
{// ...CopyBan(const CopyBan&)=delete;CopyBan& operator=(const CopyBan&)=delete;//...
};
原因
- 设置成私有:如果只声明,没有设置成private,用户自己如果在类外定义了,就可以不能禁止拷贝了
- 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。
- C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上=delete,表示让编译器删除掉该默认成员函数。
请设计一个类,只能在堆上创建对象
- 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
- 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
class MyClass
{public:static MyClass* get_init(){return new MyClass;}private:MyClass() :_a(0){}MyClass(const MyClass&)=delete;MyClass& operator=(const MyClass&) = delete;int _a;
};
static:
- 静态成员函数与普通成员函数的根本区别在于:普通成员函数有 this 指针,可以访问类中的任意成员;
- 而静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
- 防止在栈上进行拷贝构造。
请设计一个类,只能在栈上创建对象
- 方法一:同上将构造函数私有化,然后设计静态方法创建对象返回即可。
class MyClass1
{public:static MyClass1 get_init(){return MyClass1();}private:MyClass1(){}MyClass1(const MyClass1&) = delete;MyClass1& operator=(const MyClass1&) = delete;int _a;
};
- 方法二:屏蔽new:因为new在底层调用
void* operator new(size_t size)
函数,只需将该函数屏蔽掉即可。
class MyClass
{public:MyClass() {}
private:void* operator new(size_t x) = delete;void operator delete(void* ptr) = delete;
};
原因:
- 有专属的new会调用专属的,向内存池申请,效率更高。
- 没有专属的会调用全局的operator new 向系统申请内存。
- 我写了你就要调用我…,但是你调用到了,我让你用不了
- **虚表:**虚函数表在编译时生成,虚表指针是在 构造函数初始化列表 初始化。
请设计一个类,不能被继承
- C++98
// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
{public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
};
C++11:
- final关键字,final修饰类,表示该类不能被继承。
class A final
{// ....
};
比较:
- C++98可以被继承,但继承的派生类不能创建对象;
- 派生类的对象构造函数必须调用基类的,但基类的私有不可见;所以继承不会报错,创建对象会报错。
设计模式
设计模式:
- 设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
- 使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。
- 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
- 单例模式,工厂模式,观察者模式:迭代器模式 、适配器模式等等。
设计模式详细介绍
请设计一个类,只能创建一个对象(单例模式)
- 一个类只能创建一个对象,即单例模式。
- 该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
- 比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
- 实现模式分为饿汉模式和懒汉模式。
- 假如定义一个全局对象,在所有文件都是可见的,只能定义在一个头文件里,多个源文件包含时,每个源文件预处理时头文件展开,链接会报错,重定义错误。
- 假如定义一个静态全局对象,只在每个源文件内部可见,都有一份不冲突,但无法保证时同一个。
- 对于C语言,可以在头文件extern声明全局对象,别的原文件定义;软性约束,使用场景有限。
。h
extern std::vector<int> v; //全局对象声明,别的源文件定义
。cpp
std::vector<int> v;
pragma once
等于条件编译,有多个头文件时,只展开一份。
饿汉模式
- 就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。(在 main 函数之前就创建初始化)
- 优点:简单
- 缺点:可能会导致进程启动慢,且如果有多个单例类对象实例存在依赖关系时,启动顺序不确定。
- 启动慢:如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。
实现:
- 构造函数私有化,不能随意创建对象
- 声明一个私有的静态类型对象
- 写一个获取初私有对象的静态函数
- 声明与定义分开
。h
class MyClass
{public://3. 写一个获取初始化的静态函数static MyClass& get_init();vector<int> _vi;//想把vector对象私有,再包一层对象的插入等等/*void PushBcak(size_t x){return _vi.push_back(x);}*/
private://1.构造函数私有化,不能随意创建对象MyClass(){}//防拷贝MyClass(const MyClass&) = delete;MyClass& operator=(const MyClass&) = delete;//2.声明一个私有的静态类型对象static MyClass _my;
};
.cpp
MyClass MyClass::_my;MyClass& MyClass::get_init()
{return _my;
}test:
int main()
{MyClass::get_init()._vi.push_back(222);MyClass::get_init()._vi.push_back(24);MyClass::get_init()._vi.push_back(34);for (auto& i : MyClass::get_init()._vi){cout << i << endl;}return 0;
}
懒汉模式
- 优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制。
- 缺点:复杂
实现:
- 构造函数私有化,不能随意创建对象
- 声明一个私有的静态类型指针对象
- 写一个获取私有对象的静态函数
- 声明与定义分开
- 要加双层锁,保证线程安全和效率;避免线程数据被覆盖、线程频繁上下文切换和阻塞。
。h
class MyClass //静态成员函数,成员变量 声明定义分开
{public://3. 写一个获取初始化的静态函数static MyClass* get_init();vector<int> _vi;//想把vector对象私有,再包一层对象的插入等等/*void PushBcak(size_t x){return _vi.push_back(x);}*/
private://1.构造函数私有化,不能随意创建对象MyClass() {}//放拷贝MyClass(const MyClass&) = delete;MyClass& operator=(const MyClass&) = delete;//2.声明一个私有的静态类型指针对象static MyClass* _my;static mutex _tex;//互斥锁
};,cpp
MyClass* MyClass::_my = nullptr;
mutex MyClass::_tex;
MyClass* MyClass::get_init()
{if (_my==nullptr)//双锁保证了线程效率,避免了线程频繁的上下文切换,来回阻塞{_tex.lock();if (_my == nullptr){_my = new MyClass;}_tex.unlock(); //枷锁保证线程安全,避免数据被覆盖。}return _my;
}
懒汉模式测试用例
源1.cpp
void f1()
{MyClass* pm = MyClass::get_init();pm->_vi.push_back(21);pm->_vi.push_back(22);pm->_vi.push_back(23);cout << &pm->_vi << endl;for (auto& i : pm->_vi){cout << i << endl;}cout << endl;
}源.cpp
int main()
{f1();MyClass* pm = MyClass::get_init();pm->_vi.push_back(24);pm->_vi.push_back(25);pm->_vi.push_back(26);cout << &pm->_vi << endl;for (auto& i : pm->_vi){cout << i << endl;}//MyClass1 m1 = MyClass1::get_init();return 0;
}
单例模式对象的销毁
- 饿汉模式,由于对象是静态的,想释放也释放不了,main函数结束以后,意味着整个进程就结束了,系统会对整个进程的资源进行清理。
- 懒汉模式,同上,不用手动释放问题不大:手动如下:
void MyClass::Delmc()
{if (_my != nullptr)//双锁保证了线程效率,避免了线程频繁的上下文切换,来回阻塞{_tex.lock();if (_my!=nullptr){delete _my;_my = nullptr;}_tex.unlock(); //枷锁保证线程安全,避免数据被覆盖。}
}
展望
中级C++:单例模式相关推荐
- 0725(016天 多态复习 java中级-抽象类01)
0725(016天 多态复习.java中级-抽象类01) 每日一狗(田园犬西瓜瓜) 主标题 文章目录 0725(016天 多态复习.java中级-抽象类01) 主标题 1. 多态续 1.1 补充知识 ...
- Unity(入门、中级、中高级、高级)
Unity Unity 入门 1.Unity的安装与激活 1.1.中国版与国际版 中国版 https://unity.cn/ 国际版 https://unity.com/ 1.2.Unity下载 ht ...
- java 初级、中级、高级工程师
一.初级工程师 1.首先要学习java的基础知识. 不要被新技术迷惑,所谓万变不离其宗,新技术都是基于java的基础之上,如果基础不扎实,对于这些新技术的理解也是一知半解,学不到根源. 2.做一个ja ...
- 如何面试Java中级开发(16k)试题讲解和Java学习
面试题: HashMap底层实现原理,红黑树,B+树,B树的结构原理,volatile关键字,CAS(比较与交换)实现原理 Spring的AOP和IOC是什么?使用场景有哪些?Spring事务,事务的 ...
- Java中级开发面试题
面试题: HashMap底层实现原理,红黑树,B+树,B树的结构原理,volatile关键字,CAS(比较与交换)实现原理 Spring的AOP和IOC是什么?使用场景有哪些?Spring事务,事务的 ...
- 中级软件设计师知识总结
文章目录 复习进度 分型 一.面向对象 1 面向对象的概念 面向对象设计原则 2 UML 静态图/结构图包括: 动态图/行为图包括: 3 4 设计模式 设计模式概念 设计模式的分类 创建型模式 结构型 ...
- java中级开发面试总结
中级开发面试总结 分布式事务的四种解决方案 一.两阶段提交(2PC) 两阶段提交(Two-phase Commit,2PC),通过引入协调者(Coordinator)来协调参与者的行为,并最终决定这些 ...
- java 中级面试题及答案
java 中级面试题及答案 1.MyBatis中,根据Id查询单个Order对象,动态SQL如何编写? A. SELECT * FROM Order WHERE ID = #{id}; B. SELE ...
- java 初级、中级、高级工程师有什么区别?
技术不同,简单的可以理解为:初级中级的只关注代码,编程.高级的就要考虑系统的架构,整体框架. 具体区别如下: 一.初级工程师 1.首先要学习java的基础知识. 不要被新技术迷惑,所谓万变不离其宗,新 ...
最新文章
- Python股票分析系列——基础股票数据操作(二).p4
- springmvc 实例应用
- python函数包_python-函数包和模块
- XAMPP修改80和443端口及创建虚拟目录
- slider轮播插件的多种写法
- 手机可以和linux数据互传吗,没网络也可以传输数据?OPPO互传与HUAWEI Share实测体验...
- 无锡公交也有两套支付
- Linux系统-Ubuntu的下载和安装
- RS485设计技巧TOP10
- AI人工智能基础自学(一)
- 如何用Web Scraper抓取巨潮资讯网全站乐视相关pdf文件
- CCF CSP 201912-3 化学方程式配平【Python 满分代码】
- python代码完成Fisher判别
- 华为服务器修改root密码,华为云服务器root权限设置密码
- pg_hint_plan 使用hint固定SQL执行计划
- 怎么给PDF删除其中一页,PDF删除其中一页的方法
- 忆暖行动|“ 还可以留一点做成柿饼,做法也很简单,就是挑硬柿子把皮削掉,用开水烫个几秒”
- 缺省(默认)端口参数
- MapX和MapXtreme区别
- Python 快速入门学习总结
热门文章
- 一篇文章带你学懂C++虚函数表的继承问题
- [No00000E]PPT快捷键大全 PowerPoint2013/2010/2007/2003常用快捷
- [源码解析] 机器学习参数服务器ps-lite (1) ----- PostOffice
- sandboxie (沙箱机制)
- ASP.NET : 如何将服务端的多个文件打包下载
- C++ 虚函数的神奇效用
- Apache的安装与配置(Windows系统)
- MITxPro Base SPOC-MachineLearning, Modeling, and Simulation Principles.
- 在知网数据库中如何下载pdf格式的硕博士论文
- 看图要仔细-设计74HC165的原理图库文件-PCB系列教程2-2