文章目录

  • 写一个不能被拷贝和复制的类
  • 请设计一个类,只能在堆上创建对象
  • 请设计一个类,只能在栈上创建对象
  • 请设计一个类,不能被继承
  • 设计模式
  • 请设计一个类,只能创建一个对象(单例模式)
  • 饿汉模式
  • 懒汉模式
  • 单例模式对象的销毁
  • 展望

写一个不能被拷贝和复制的类

  • 拷贝和赋值重载函数私有化。
  • 分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;//...
};

原因

  1. 设置成私有:如果只声明,没有设置成private,用户自己如果在类外定义了,就可以不能禁止拷贝了
  2. 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。
  3. C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上=delete,表示让编译器删除掉该默认成员函数。

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

  1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
  2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
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:

  1. 静态成员函数与普通成员函数的根本区别在于:普通成员函数有 this 指针,可以访问类中的任意成员;
  2. 而静态成员函数没有 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;
};

原因:

  1. 有专属的new会调用专属的,向内存池申请,效率更高。
  2. 没有专属的会调用全局的operator new 向系统申请内存。
  3. 我写了你就要调用我…,但是你调用到了,我让你用不了
  • **虚表:**虚函数表在编译时生成,虚表指针是在 构造函数初始化列表 初始化。

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

  • C++98
// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
{public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
};

C++11:

  • final关键字,final修饰类,表示该类不能被继承。
class A final
{// ....
};

比较:

  1. C++98可以被继承,但继承的派生类不能创建对象;
  2. 派生类的对象构造函数必须调用基类的,但基类的私有不可见;所以继承不会报错,创建对象会报错。

设计模式

设计模式:

  1. 设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
  2. 使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。
  3. 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
  4. 单例模式,工厂模式,观察者模式:迭代器模式 、适配器模式等等。

设计模式详细介绍



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

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

  • 假如定义一个全局对象,在所有文件都是可见的,只能定义在一个头文件里,多个源文件包含时,每个源文件预处理时头文件展开,链接会报错,重定义错误。
  • 假如定义一个静态全局对象,只在每个源文件内部可见,都有一份不冲突,但无法保证时同一个。
  • 对于C语言,可以在头文件extern声明全局对象,别的原文件定义;软性约束,使用场景有限。
。h
extern std::vector<int> v;  //全局对象声明,别的源文件定义
。cpp
std::vector<int> v;
  • pragma once等于条件编译,有多个头文件时,只展开一份。

饿汉模式

  • 就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。(在 main 函数之前就创建初始化)
  • 优点:简单
  • 缺点:可能会导致进程启动慢,且如果有多个单例类对象实例存在依赖关系时,启动顺序不确定。
  • 启动慢:如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。

实现:

  1. 构造函数私有化,不能随意创建对象
  2. 声明一个私有的静态类型对象
  3. 写一个获取初私有对象的静态函数
  4. 声明与定义分开
。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;
}

懒汉模式

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

实现:

  1. 构造函数私有化,不能随意创建对象
  2. 声明一个私有的静态类型指针对象
  3. 写一个获取私有对象的静态函数
  4. 声明与定义分开
  5. 要加双层锁,保证线程安全和效率;避免线程数据被覆盖、线程频繁上下文切换和阻塞。
。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++:单例模式相关推荐

  1. 0725(016天 多态复习 java中级-抽象类01)

    0725(016天 多态复习.java中级-抽象类01) 每日一狗(田园犬西瓜瓜) 主标题 文章目录 0725(016天 多态复习.java中级-抽象类01) 主标题 1. 多态续 1.1 补充知识 ...

  2. Unity(入门、中级、中高级、高级)

    Unity Unity 入门 1.Unity的安装与激活 1.1.中国版与国际版 中国版 https://unity.cn/ 国际版 https://unity.com/ 1.2.Unity下载 ht ...

  3. java 初级、中级、高级工程师

    一.初级工程师 1.首先要学习java的基础知识. 不要被新技术迷惑,所谓万变不离其宗,新技术都是基于java的基础之上,如果基础不扎实,对于这些新技术的理解也是一知半解,学不到根源. 2.做一个ja ...

  4. 如何面试Java中级开发(16k)试题讲解和Java学习

    面试题: HashMap底层实现原理,红黑树,B+树,B树的结构原理,volatile关键字,CAS(比较与交换)实现原理 Spring的AOP和IOC是什么?使用场景有哪些?Spring事务,事务的 ...

  5. Java中级开发面试题

    面试题: HashMap底层实现原理,红黑树,B+树,B树的结构原理,volatile关键字,CAS(比较与交换)实现原理 Spring的AOP和IOC是什么?使用场景有哪些?Spring事务,事务的 ...

  6. 中级软件设计师知识总结

    文章目录 复习进度 分型 一.面向对象 1 面向对象的概念 面向对象设计原则 2 UML 静态图/结构图包括: 动态图/行为图包括: 3 4 设计模式 设计模式概念 设计模式的分类 创建型模式 结构型 ...

  7. java中级开发面试总结

    中级开发面试总结 分布式事务的四种解决方案 一.两阶段提交(2PC) 两阶段提交(Two-phase Commit,2PC),通过引入协调者(Coordinator)来协调参与者的行为,并最终决定这些 ...

  8. java 中级面试题及答案

    java 中级面试题及答案 1.MyBatis中,根据Id查询单个Order对象,动态SQL如何编写? A. SELECT * FROM Order WHERE ID = #{id}; B. SELE ...

  9. java 初级、中级、高级工程师有什么区别?

    技术不同,简单的可以理解为:初级中级的只关注代码,编程.高级的就要考虑系统的架构,整体框架. 具体区别如下: 一.初级工程师 1.首先要学习java的基础知识. 不要被新技术迷惑,所谓万变不离其宗,新 ...

最新文章

  1. Python股票分析系列——基础股票数据操作(二).p4
  2. springmvc 实例应用
  3. python函数包_python-函数包和模块
  4. XAMPP修改80和443端口及创建虚拟目录
  5. slider轮播插件的多种写法
  6. 手机可以和linux数据互传吗,没网络也可以传输数据?OPPO互传与HUAWEI Share实测体验...
  7. 无锡公交也有两套支付
  8. Linux系统-Ubuntu的下载和安装
  9. RS485设计技巧TOP10
  10. AI人工智能基础自学(一)
  11. 如何用Web Scraper抓取巨潮资讯网全站乐视相关pdf文件
  12. CCF CSP 201912-3 化学方程式配平【Python 满分代码】
  13. python代码完成Fisher判别
  14. 华为服务器修改root密码,华为云服务器root权限设置密码
  15. pg_hint_plan 使用hint固定SQL执行计划
  16. 怎么给PDF删除其中一页,PDF删除其中一页的方法
  17. 忆暖行动|“ 还可以留一点做成柿饼,做法也很简单,就是挑硬柿子把皮削掉,用开水烫个几秒”
  18. 缺省(默认)端口参数
  19. MapX和MapXtreme区别
  20. Python 快速入门学习总结

热门文章

  1. 一篇文章带你学懂C++虚函数表的继承问题
  2. [No00000E]PPT快捷键大全 PowerPoint2013/2010/2007/2003常用快捷
  3. [源码解析] 机器学习参数服务器ps-lite (1) ----- PostOffice
  4. sandboxie (沙箱机制)
  5. ASP.NET : 如何将服务端的多个文件打包下载
  6. C++ 虚函数的神奇效用
  7. Apache的安装与配置(Windows系统)
  8. MITxPro Base SPOC-MachineLearning, Modeling, and Simulation Principles.
  9. 在知网数据库中如何下载pdf格式的硕博士论文
  10. 看图要仔细-设计74HC165的原理图库文件-PCB系列教程2-2