石家庄网站建设行业公司,电商网名,dede 更新网站地图,本地wordpress 跳转目录
前言
特殊类设计
只能在堆上创建对象的类
1.方法一#xff08;构造函数下手#xff09; 2.方法二#xff08;析构函数下手#xff09;
只能在栈上创建对象的类
单例模式
饿汉模式实现
懒汉模式实现
后记 前言 在面向找工作学习c的过程中#xff0c;除了基本…目录
前言
特殊类设计
只能在堆上创建对象的类
1.方法一构造函数下手 2.方法二析构函数下手
只能在栈上创建对象的类
单例模式
饿汉模式实现
懒汉模式实现
后记 前言 在面向找工作学习c的过程中除了基本的语法知识以外还有一些被反复使用、经验总结的设计模式或者说设计思想值得大家学习也可以说是面试当中面试官大概率问到的面试题。在本节中除了介绍标题所述的单例模式还要了解一些特殊类的设计思想当然也需要引入这些思想才能更好的理解单例模式。对于常见的特殊类的设计比如不能被拷贝的类将拷贝构造函数和赋值运算符重载设置为删除函数、不能被继承的类在类名后面加上final关键字等这些都是一些较为简单的特殊类设计难一点的像只能在堆或者栈上创建的类、只能创建一个对象的类单例模式这些又如何实现往下看
特殊类设计 只能在堆上创建对象的类
1.方法一构造函数下手 从构造函数下手也就是把构造函数私有化这样我们就可以控制谁能去使用构造函数了控制的方法就是定义一个共有的接口在该接口内使用允许的方法创建对象。这里就是创建了一个静态成员函数——getObj()在接口内去new一个对象返回出去为什么是静态呢因为普通成员函数无法在类外使用必须创建出对象才能使用这就会产生“先有鸡还是先有蛋”的问题。 此外将拷贝构造函数和赋值运算符重载设置为删除函数是为了防拷贝因为拷贝与赋值可以在栈上或静态区创建对象参考代码如下。 代码
class HeapOnly
{
public:static HeapOnly* getObj(int a){return new HeapOnly(a);}private:HeapOnly(int a):_a(a){}HeapOnly(const HeapOnly hp) delete;HeapOnly operator(const HeapOnly hp) delete;private:int _a 0;
};
调试 2.方法二析构函数下手 除了将构造函数私有化也可以将析构函数私有化思想是一样的即将析构函数私有化之后定义一个共有的接口去使用允许的方式释放对象如下代码块的delObj函数那为什么不需要设置成静态函数呢因为此时对象已经创建出来了直接调用此函数来释放资源即可其他方式创建出来的对象会因为没有析构函数而编译不通过。 值得提一嘴的是我们可以不用传入指向资源的指针到delObj函数内因为普通成员函数有一个参数就是当前对象的指针直接去释放即可。 代码
class HeapOnly
{
public:void delObj(HeapOnly* pho){delete pho;}/*void delObj(){delete this;}*/
private:~HeapOnly(){}
private:int _a 0;
};
调试 只能在栈上创建对象的类 只能在栈上创建对象这种就不能够在析构函数上下手了考虑一下构造函数思想其实与只能在堆上创建对象一样——设置共有的静态接口在接口内定义对象返回出去但其实这样的做法是不能做到严格把控的也就是说写不出来只能在栈上创建对象的类下面解释。 我们先按之前的思想将其写出来如下代码块。图一可以看到的确只能在栈上创建对象但是看图二可以通过static将对象拷贝一份在静态区这就是存在的bug。有人说将拷贝函数和赋值函数都设置为delete函数但是这样就无法将getObj函数内定义的对象返回出来了大家可以尝试一下有解决的方法可以写在评论区一块讨论。 代码
class StackOnly
{
public:static StackOnly getObj(int a){return StackOnly(a);}private:StackOnly(int a 0):_a(a){}public:int _a 0;
};
单例模式 一个类只能创建一个对象即单例模式。单例模式是一种创建对象的设计模式它确保一个类只有一个实例并提供全局访问该实例的方式。 在单例模式中类的构造函数被私有化使得外部无法直接创建对象。类内部维护一个静态变量来保存唯一的实例通过一个公共的静态方法来获取该实例。当第一次调用该方法时会创建一个对象并赋值给静态变量以后的调用都直接返回这个静态变量。 单例模式常用于需要限制全局资源访问的场景比如数据库连接、线程池等。通过单例模式可以确保全局只有一个实例存在并提供一种方便的方式来访问该实例。有两个实现方式来实现单例模式饿汉模式和懒汉模式。 饿汉模式实现 饿汉模式不管你将来用不用程序启动时就创建一个唯一的实例对象也就是一开始在main函数之前就创建对象。 优点较简单不存在线程安全问题 缺点因为在main函数之前所以可能会导致进程启动慢而且如果有多个单例类对象实例启动顺序不确定 实现原理 首先因为是单例模式只能创建一个对象所以先将拷贝构造函数、赋值运算符重载函数设置为删除函数以防止拷贝。其次按照前面特殊类设计思想我们依旧将构造函数私有化并定义一个共有函数用来创建符合条件的对象这里需要只能创建一个对象因此我们定义一个静态成员变量可以是类指针也可以是类对象因为静态变量只有一份。静态成员变量是类内声明类外初始化因为是一开始就创建所以在初始化时我们就new一个对象。然后我们将定义一个共有的静态成员函数来获取这个变量即可为什么这个成员函数也是静态的因为普通成员函数内不能使用静态成员变量代码参考如下 代码
class Singleton
{
public:static Singleton* getInstance(){return _inst;}
private:Singleton(){}Singleton(const Singleton x) delete;Singleton operator(const Singleton x) delete;static Singleton* _inst;
};
Singleton* Singleton::_inst new Singleton(); 懒汉模式实现 当单例对象构造十分耗时或者占用很多资源比如加载插件、初始化网络连接、读取文件等而且有可能该对象程序运行时不会用到那么在程序一开始就进行初始化就会导致程序启动时非常的缓慢。 懒汉模式在第一次使用时才创建单例对象 优点进程启动无负载多个单例实例启动顺序可以自由控制 缺点复杂、存在线程安全问题 实现原理 如下代码块懒汉模式实现过程与饿汉模式实现的大致框架都是一样的主要在于因为懒汉模式是第一次使用时再创建这个对象因此静态成员变量在初始化时设置为空。先看非线程安全版本的getInstance函数如果静态成员变量_inst为空说明还没创建此时应该去创建这个对象如果非空说明已经创建过了直接返回这个变量出去。 其次考虑到多个线程同时竞争创建这个实例同时判断_inst为空同时创建出了多个对象导致线程安全问题所以我们需要加锁保护定义并初始化一把静态锁在判断_inst是否为空之前加锁保护这样就能保证进入判断的线程只有一个其他线程都得挂起等待。 但是发现在加锁的外面又加了一层判空的if语句这是因为只需要第一次进来时需要用到锁第二次往后进来都是只需要返回这个指针即可否则每次进入这个函数都需要申请锁会降低效率这种方式叫做Double-Cheack适用于第一次加锁后续不需要的情形。 以上是懒汉模式的实现过程下面再考虑一个问题——单例对象释放问题首先一般情况下单例对象是不需要释放的因为一整个程序都可能需要用到它单例对象在进程正常结束后也会自动释放其次有些场景需要释放比如单例对象释放时需要进行持久化操作将数据信息保存在文件中那么此时一个释放的方法就是可以通过内部类的方式实现单例对象释放机制。如下面代码块实现的DelInstance类在成员中定义这样类型的静态对象当程序结束时系统会自动调用其析构函数从而释放单例对象而所谓的持久化操作就可以在其析构函数内做。 代码
class Singleton
{
public://非线程安全版本/*static Singleton* getInstance(){if (_inst nullptr){_inst new Singleton();}return _inst;}*/static Singleton* getInstance(){if(_instnullptr){lock_guardmutex lg(_mtx);if (_inst nullptr){_inst new Singleton();}}return _inst;}class DelInstance{public://持久化操作~DelInstance(){if (_inst)delete _inst;}};static DelInstance _delins;
private:Singleton(){}Singleton(const Singleton x) delete;Singleton operator(const Singleton x) delete;static Singleton* _inst;static mutex _mtx;
};
Singleton* Singleton::_inst nullptr;
mutex Singleton::_mtx; //注意即使不需要初始化静态成员变量也需要写在这
后记 通过实现只能在堆或栈上创建对象的类学习到如何实现单例模式这是一种设计模式是大多数程序员共同发现的“套路”套用相同的模式可以让代码可读性更强、更容易被他人理解、使代码编写更加工程化。实现单例模式也是分为两种方法其中更加建议使用懒汉模式。不仅仅是学会本文中特殊类设计的方法更要注重设计的思想对于面试中面对考官出的其他类的实现题目提供了一种思考或解决办法好了以上类的设计自己尝试实现一把有问题举手。