主页 > 电脑硬件  > 

C++【特殊类的设计】【单例设计模式】

C++【特殊类的设计】【单例设计模式】

文章目录 特殊类的设计1.不能被拷贝的类2.只能在堆上创建对象的类3.只能在栈上创建的类 单例模式1.饿汉模式2.饿汉模式3.单例对象的释放问题

特殊类的设计 1.不能被拷贝的类

在我们上一章的unique中就是让我们的对象不能被拷贝。 我们这里可以将赋值和拷贝构造都设置为私有属性。

class CopyBan { // ... private: Copy(const Copy&); Copy& operator=(const Copy&); //... }; 2.只能在堆上创建对象的类 #include <iostream> class HeapOnly { //将析构函数私有 private: ~HeapOnly() {} private: int _a; }; int main() { HeapOnly hp1; static HeapOnly hp2; HeapOnly* ptr =new HeapOnly; return 0; }

正常定义的对象我们都需要调用析构函数,如果我们把析构函数设置成私有,那么我们的上面代码中的hp1,hp2都会报错,而我们的ptr因为没有调用析构函数,所以可以正常编译通过。 那么我们就需要手动释放ptr,也就是写成下面的写法

#include <iostream> using namespace std; class HeapOnly { public: static void Delete(HeapOnly* p) { delete p; } //将析构函数私有 private: ~HeapOnly() { cout<<"heapOnly"<<endl; } private: int _a; }; int main() { // HeapOnly hp1; // static HeapOnly hp2; HeapOnly* ptr =new HeapOnly; ptr->Delete(ptr); return 0; }

或者将构造函数私有化,采用下面的写法

#include <iostream> using namespace std; class HeapOnly { public: //提供一个共有的,获取对象的方式,对象控制是new出来的 static HeapOnly* CreateObject() { return new HeapOnly; } private: HeapOnly() :_a(0) {} private: int _a; }; int main() { // HeapOnly hp1; // static HeapOnly hp2; HeapOnly* hp3 =HeapOnly::CreateObject(); delete hp3; return 0; }

但是我们还需要防止别人采用拷贝构造的方式在栈上开辟空间,这里我们还需要将拷贝构造和赋值设置成私有的。

#include <iostream> using namespace std; class HeapOnly { public: //提供一个共有的,获取对象的方式,对象控制是new出来的 static HeapOnly* CreateObject() { return new HeapOnly; } private: HeapOnly(const HeapOnly& hp)=delete; HeapOnly& operator=(const HeapOnly& hp)=delete; HeapOnly() :_a(0) {} private: int _a; }; int main() { // HeapOnly hp1; // static HeapOnly hp2; HeapOnly* hp3 =HeapOnly::CreateObject(); //拷贝构造的空间在栈上 HeapOnly copy(*hp3); delete hp3; return 0; } 3.只能在栈上创建的类 #include <iostream> using namespace std; class StackOnly { public: static StackOnly CreateObj() { StackOnly st; return st; } // StackOnly(const StackOnly& hp)=delete; // StackOnly& operator=(const StackOnly& hp)=delete; void* operator new(size_t n)=delete; private: StackOnly() :_a(0) {} private: int _a; }; int main() { // StackOnly hp1; // static StackOnly hp2; StackOnly hp3 =StackOnly::CreateObj(); //拷贝构造 //因为我们这里一定要传值返回,然后如果把传值返回给禁用了,我们这里上面的 //正产的hp3也没有办法创建了。 //所以这里的copy(hp3)没有办法禁用 StackOnly copy2(hp3); //不好处理,小缺陷 // StackOnly * copy3=new StackOnly(hp3); return 0; } 单例模式

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

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

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

JAVA版本的单例模式

1.饿汉模式

饿汉模式–一开始(main函数之前)就创建出对象 可以使用下面这种生成一个静态的对象

//饿汉模式 class MemoryPool { public: private: //构造函数私有化 MemoryPool() {} char* _ptr= nullptr; //创建一个静态的自己的对象 //因为静态的对象是存在静态区的,是属于所有类的 static MemoryPool _inst;//声明 }; //定义,在类外进行构造 MemoryPool MemoryPool::_inst; int main() { // MemoryPool pool1; //MemoryPool pool2; }

或者像下面这样采用指针的形式

#include <iostream> using namespace std; //饿汉模式 class MemoryPool { public: static MemoryPool*GetInstance() { return _pinst; } void* Alloc(size_t n) { void* ptr= nullptr; return ptr; } void Dealloc(void*ptr) {} private: //构造函数私有化 MemoryPool() {} char* _ptr= nullptr; //创建一个静态的自己的对象 //因为静态的对象是存在静态区的,是属于所有类的 static MemoryPool* _pinst;//声明 }; //定义,在类外进行构造 MemoryPool* MemoryPool::_pinst=new MemoryPool; int main() { // MemoryPool pool1; //MemoryPool pool2; void* ptr1=MemoryPool::GetInstance()->Alloc(10); MemoryPool::GetInstance()->Dealloc(ptr1); }

饿汉模式: 优点:简单,没有线程安全问题(因为它在main函数之前就执行了,不存在竞争的问题)。 缺点:1、一个程序中,有多个单例,并且有先后创建初始化顺序要求时,饿汉无法控制 (比方说A先创建,然后B在创建,这样是没有办法做到的,因为它们都是静态成员,我们是没有办法确定的。同一个文件中可能谁在前,谁先初始化,但是如果是在多个文件中就不好控制了) 2、饿汉单例模式,初始化任务多的时候,会影响程序的启动速度。因为我们上面的单例的初始化是在main函数之前就创建的。

2.饿汉模式

懒汉模式:第一次使用对象再创建实例对象。

#include <iostream> using namespace std; //饿汉模式 class MemoryPool { public: static MemoryPool*GetInstance() { if(_pinst== nullptr) { _pinst=new MemoryPool; } return _pinst; } void* Alloc(size_t n) { void* ptr= nullptr; return ptr; } void Dealloc(void*ptr) {} private: //构造函数私有化 MemoryPool() {} char* _ptr= nullptr; //创建一个静态的自己的对象 //因为静态的对象是存在静态区的,是属于所有类的 static MemoryPool* _pinst;//声明 }; //定义,在类外进行构造 MemoryPool* MemoryPool::_pinst=nullptr; int main() { // MemoryPool pool1; //MemoryPool pool2; void* ptr1=MemoryPool::GetInstance()->Alloc(10); MemoryPool::GetInstance()->Dealloc(ptr1); }

优点 1、控制顺序 2、不影响启动速度 缺点: 1、相对复杂(线程安全问题) 2、线程安全问题要处理好

3.单例对象的释放问题

1、一般情况下,单例对象不需要释放。一般整个程序运行期间都可能会用到。 2、单例对象在进程正常结束之后也会资源释放 3、有些特殊的场景需要释放,比如单例对象析构时,要进行一些持久化(往文件,数据库写)操作。

我们可以通过定义一个内嵌类型的垃圾回收器来释放我们的空间

#include <iostream> using namespace std; //饿汉模式 class MemoryPool { public: static MemoryPool*GetInstance() { if(_pinst== nullptr) { _pinst=new MemoryPool; } return _pinst; } void* Alloc(size_t n) { void* ptr= nullptr; return ptr; } void Dealloc(void*ptr) {} // 实现一个内嵌垃圾回收类 class CGarbo { public: ~CGarbo() { if (_pinst) delete _pinst; } }; private: //构造函数私有化 MemoryPool() {} char* _ptr= nullptr; //创建一个静态的自己的对象 //因为静态的对象是存在静态区的,是属于所有类的 static MemoryPool* _pinst;//声明 }; //定义,在类外进行构造 MemoryPool* MemoryPool::_pinst=nullptr; //定义一个静态的全局的回收对象 //在main函数结束之后,它会调用析构函数,就会释放单例对象。 static MemoryPool::CGarbo gc; int main() { // MemoryPool pool1; //MemoryPool pool2; void* ptr1=MemoryPool::GetInstance()->Alloc(10); MemoryPool::GetInstance()->Dealloc(ptr1); }
标签:

C++【特殊类的设计】【单例设计模式】由讯客互联电脑硬件栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C++【特殊类的设计】【单例设计模式】