• C++之特殊类的设计


    目录

    一、单例模式

    1、设计模式

    2、单例模式

    1、饿汉模式

    2、懒汉模式

    3、单例对象的释放问题

    二、设计一个不能被拷贝的类

    三、设计一个只能在堆上创建对象的类

    四、设计一个只能在栈上创建对象的类

    五、设计一个不能被继承的类


    一、单例模式

    1、设计模式

    概念:

    设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。

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

    2、单例模式

    一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

    单例模式有两种实现模式:

    1、饿汉模式

    就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。即在main函数之前就创建好一个唯一的对象。

    1. class MemoryPool
    2. {
    3. public:
    4. static MemoryPool& GetInstance()
    5. {
    6. return _inst;
    7. }
    8. //防拷贝
    9. MemoryPool(MemoryPool const&) = delete;
    10. MemoryPool& operator=(MemoryPool const&) = delete;
    11. private:
    12. //构造函数私有化
    13. MemoryPool()
    14. {}
    15. char* _ptr = nullptr;
    16. static MemoryPool _inst;
    17. };
    18. MemoryPool MemoryPool::_inst;// 在程序入口之前就完成单例对象的初始化

    优点:简单,没有线程安全问题。

    缺点:1、一个程序中有多个单例,并且有先后创建初始化顺序要求时,饿汉模式无法控制(无法控制初始化顺序)。2、如果饿汉单例类,初始化时任务多,会影响程序的启动速度。

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

    2、懒汉模式

    第一次使用实例对象时,再创建唯一的实例对象。

    1. class MemoryPool
    2. {
    3. public:
    4. static MemoryPool* GetInstance()
    5. {
    6. if (_inst == nullptr)
    7. {
    8. _inst = new MemoryPool;
    9. }
    10. return _inst;
    11. }
    12. private:
    13. //构造函数私有化
    14. MemoryPool()
    15. {}
    16. char* _ptr = nullptr;
    17. static MemoryPool* _inst;
    18. };
    19. MemoryPool* MemoryPool::_inst = nullptr;

    优点: 1、一个程序中有多个单例,并且有先后创建初始化顺序要求时,懒汉模式可以控制(能够控制初始化顺序)。2、不影响启动速度。

    缺点:1、相对复杂。2、线程安全问题要处理好。

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

    3、单例对象的释放问题

    1、一般情况下,单例对象不需要释放。因为一般整个程序运行期间都会用到它。单例对象在进程结束后,也会资源释放。

    2、有些特殊场景需要释放。实现一个内嵌的垃圾回收类。


    二、设计一个不能被拷贝的类

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

    1. class A
    2. {
    3. public:
    4. A()
    5. {}
    6. ~A()
    7. {}
    8. A(const A&) = delete;
    9. A& operator=(const A&) = delete;
    10. private:
    11. int _a = 1;
    12. };
    13. int main()
    14. {
    15. A a1;
    16. A a2(a1);
    17. return 0;
    18. }


    三、设计一个只能在堆上创建对象的类

    实现方式:
    1、将类的构造函数或者析构函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
    2、提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建或析构。

    析构函数私有:

    1. class HeapOnly
    2. {
    3. public:
    4. static void Delete(HeapOnly* hp)
    5. {
    6. delete hp;
    7. }
    8. private:
    9. ~HeapOnly()
    10. {}
    11. private:
    12. int _a;
    13. };
    14. int main()
    15. {
    16. HeapOnly hp1;
    17. static HeapOnly hp2;
    18. HeapOnly* ptr = new HeapOnly;
    19. HeapOnly::Delete(ptr);
    20. }

    构造函数私有:

    1. class HeapOnly
    2. {
    3. public:
    4. static HeapOnly* CreatHeapOnly()
    5. {
    6. return new HeapOnly;
    7. }
    8. HeapOnly(const HeapOnly& p) = delete;
    9. HeapOnly& operator=(const HeapOnly& p) = delete;
    10. private:
    11. HeapOnly()
    12. {}
    13. private:
    14. int _a;
    15. };
    16. int main()
    17. {
    18. HeapOnly hp1;
    19. static HeapOnly hp2;
    20. HeapOnly* ptr = HeapOnly::CreatHeapOnly();
    21. delete ptr;
    22. }

     


    四、设计一个只能在栈上创建对象的类

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

    1. class StackOnly
    2. {
    3. public:
    4. static StackOnly CreateObj()
    5. {
    6. return StackOnly();
    7. }
    8.  
    9.    // 禁掉operator new可以把下面用new 调用拷贝构造申请对象给禁掉
    10. // StackOnly obj = StackOnly::CreateObj();
    11. // StackOnly* ptr3 = new StackOnly(obj);
    12. void* operator new(size_t size) = delete;
    13. void operator delete(void* p) = delete;
    14. private:
    15. StackOnly()
    16. :_a(0)
    17. {}
    18. private:
    19. int _a;
    20. };

    五、设计一个不能被继承的类

    1、构造函数私有化,派生类中调不到基类的构造函数。则无法继承。

    1. class A
    2. {
    3. public:
    4. static A GetA()
    5. {
    6. return A();
    7. }
    8. private:
    9. A()
    10. {}
    11. int _a = 1;
    12. };
    13. class B :public A
    14. {
    15. public:
    16. B()
    17. {}
    18. private:
    19. int _b = 2;
    20. };
    21. int main()
    22. {
    23. B b;
    24. return 0;
    25. }

    2、使用关键字 final :final关键字,final修饰类,表示该类不能被继承。

    1. class A  final
    2. {
    3.   // ....
    4. };
  • 相关阅读:
    2022.08.08_每日一题
    RK3568 Android11 默认打开网络ADB
    玉米社:短视频运营主要做哪些工作?
    Vue3执行流程思路分析-流程图
    图像也是一门语言?微软提出19亿参数的超大通用模型BEIT-3,刷榜多个CV和多模态任务!
    【机器学习基础】对数几率回归(logistic回归)
    手写代码模拟Spring底层原理
    基于java的企业办公自动化系统设计与实现【附源码+lun文】
    【JavaScript】js判断一个变量是数组
    C++保姆级入门教程(10)—— 一维数组练习
  • 原文地址:https://blog.csdn.net/zdlynj/article/details/133280737