目录
设计一个类,不能被拷贝
设计一个类,只能在堆上创建对象
设计一个类,只能在栈上创建对象
设计一个类,无法被继承
设计一个类,只能创建一个对象(单例模式)
饿汉模式
懒汉模式
设计一个类,不能被拷贝
这个很简单,利用C11新特性中的关键字delete给到拷贝构造与赋值重载即可~
class BanCopy
{//...BanCopy(const BanCopy&) = delete;BanCopy& operator=(const BanCopy&) = delete;//...
};
设计一个类,只能在堆上创建对象
既然是要在堆上创建对象,那么首先要做的就是确保该对象是new出来的而非是由构造函数生成的~
class HeapOnly
{
public://禁止赋值重载HeapOnly& operator=(const HeapOnly&) = delete;//禁止拷贝构造HeapOnly(const HeapOnly&) = delete;
private://构造私有化//无参HeapOnly(){}//有参HeapOnly(int x, int y):_x(x),_y(y){}int _x;int _y;
};int main()
{HeapOnly ho1;HeapOnly* ho2 = new HeapOnly;return 0;
}
不过这样new的时候也无法调用构造了,所以我们再包装一层~
不过还是遇到问题,OBJ是创建对象用的,但调用OBJ得是对象调用,那么我们就不要让它作为成员函数,而是超脱其作用域~
然后再把默认的拷贝函数与赋值重载禁掉,防止在栈上拷贝对象~
class HeapOnly
{
public:template<class... Args>static HeapOnly* CreateObject(Args&&... args){return new HeapOnly(args...);}/*static HeapOnly* CreateObject(){return new HeapOnly;}*///禁止赋值重载HeapOnly& operator=(const HeapOnly&) = delete;//禁止拷贝构造HeapOnly(const HeapOnly&) = delete;
private://构造私有化//无参HeapOnly(){}//有参HeapOnly(int x, int y):_x(x),_y(y){}int _x =1;int _y =2;
};int main()
{/*HeapOnly ho1;HeapOnly* ho2 = new HeapOnly;*/HeapOnly* ho2 = HeapOnly::CreateObject();HeapOnly* ho3 = HeapOnly::CreateObject(3,4);//禁止拷贝//HeapOnly copy(*ho2);return 0;
}
ps:可搭配上前面所学的可变参数模板使用~
设计一个类,只能在栈上创建对象
只能在栈上的话思路和前面差不多,先把构造给私有化,由我们来控制在那开辟对象,再把new给禁止掉,防止在堆上开辟~
class StackOnly
{
public:template<class... Args>static StackOnly CreateObj(Args&&... args){return StackOnly(args...);}// 禁掉operator new可以把下面用new 调用拷贝构造申请对象给禁掉void* operator new(size_t size) = delete;void operator delete(void* p) = delete;
private:StackOnly():_a(0){}
private:int _a;int _b;
};int main()
{StackOnly so1 = StackOnly::CreateObj();StackOnly so2 = StackOnly::CreateObj(3,4);//无法使用StackOnly* ptr3 = new StackOnly(obj);return 0;
}
设计一个类,无法被继承
class A final
{//...
};
直接用C11新特性的关键字final即可~
设计一个类,只能创建一个对象(单例模式)
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个 访问它的全局访问点,该实例被所有程序模块共享 。
饿汉模式
饿汉:一开始(main之前)就创建出对象。就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。想让一些数据,当前程序只有一份,那就可以把这些数据放到这个类里面,再把这个类设计成单例,这个数据就只有一份了
namespace hunger
{class Singleton{public://利用静态成员函数拿到静态成员static Singleton* GetInstance(){return &_sint;}void Print(){cout << _x << endl;cout << _y << endl;}//禁止拷贝构造与赋值重载,防止其他对象生成Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;private://构造函数私有防止构造其他对象Singleton(int x,int y):_x(x), _y(y){}int _x;int _y;// 静态成员对象,不存在对象中,存在静态区,相当于全局的,定义在类中,受类域限制// 这才符合在main之前创建对象static Singleton _sint;};//静态成员声明:成员类型+成员所处內域Singleton Singleton::_sint(1, 1);
}
int main()
{//直接调静态函数拿到对象hunger::Singleton::GetInstance()->Print();
}
ps:之所以拿指针而非对象一个是安全问题,指针销毁方便~但我感觉无论用指针还是引用返回都差不多~
不过饿汉模式有两个问题存在:
- 如果单例对象数据较多,构造初始化成本较高,那么会影响程序启动的速度。迟迟进不了main函数
- 多个单例类有初始化启动依赖关系,饿汉无法控制。假设:A和B两个单例,假设要求A先初始化,B再初始化,饿汉无法保证
懒汉模式
懒汉优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控
制。
如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊,初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。所以这种情况使用懒汉模式( 延迟加载 )更好。
//在饿汉模式基础上进行改造
namespace lazy
{class Singleton{public://利用静态成员函数拿到静态成员static Singleton* GetInstance(){// 第一次调用时,创建单例对象// 线程安全问题,需要加锁if (_psint == nullptr){_psint = new Singleton;}return _psint;}static void DelInstance(){if (_psint){delete _psint;_psint = nullptr;}}void Print(){cout << _x << endl;cout << _y << endl;}//禁止拷贝构造与赋值重载,防止其他对象生成Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;private://构造函数私有防止构造其他对象Singleton(int x =0,int y=0):_x(x), _y(y){}~Singleton(){cout << "~Singleton()" << endl;}int _x;int _y;// 静态成员对象,不存在对象中,存在静态区,相当于全局的,定义在类中,受类域限制static Singleton* _psint;// 内部类class GC{public:~GC(){Singleton::DelInstance();}};// 定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象static GC gc;};Singleton* Singleton::_psint = nullptr;Singleton::GC Singleton::gc;
}
int main()
{//直接调静态函数拿到对象lazy::Singleton::GetInstance()->Print();return 0;
}
在懒汉模式中我们最开始是构建出一个对象指针,只有在第一次被调用的时候才会创建对象,这样可以减少初始化时的开销~由于静态成员变量是指针,那就需要写对应的析构函数及时释放其资源,如果我们不想手动释放也可以学一下构建内部类的方式让其自动调用对指针的析构函数~
如果不想用GC内部类析构对象指针也可以这样写:
namespace lazy
{class Singleton{public://利用静态成员函数拿到静态成员static Singleton* GetInstance(){// 第一次调用时,创建单例对象// 线程安全问题,需要加锁//局部静态对象,在第一次调用该函数时才初始化static Singleton _sint;return &_sint;}static void DelInstance(){if (_psint){delete _psint;_psint = nullptr;}}void Print(){cout << _x << endl;cout << _y << endl;}//禁止拷贝构造与赋值重载,防止其他对象生成Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;private://构造函数私有防止构造其他对象Singleton(int x = 0, int y = 0):_x(x), _y(y){}~Singleton(){cout << "~Singleton()" << endl;}int _x;int _y;// 静态成员对象,不存在对象中,存在静态区,相当于全局的,定义在类中,受类域限制static Singleton* _psint;};Singleton* Singleton::_psint = nullptr;
}int main()
{//直接调静态函数拿到对象lazy::Singleton::GetInstance()->Print();return 0;
}
不用new而是直接创建对象~
总结:在main之前初始化就是饿汉,在main中第一次调用就是懒汉~