设计不能被拷贝的类
c++11是下边的用法,c++98就是将拷贝构造变成私有,并且只声明并不实现
1 2 3 4 5 6 7 8 9 10
| class A { public: A(int val):_val(val){} A(const A& a) = delete; A& operator=(const A& a) = delete; private: int _val; };
|
设计只能在堆上创建的类
方案1、将析构函数私有化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class HeapOnly { public: void destroy() { delete this; } private: ~HeapOnly(){} }; int main() { HeapOnly* hp = new HeapOnly; hp->destroy(); return 0; }
|
方案2、构造函数私有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class HeapOnly { public: static HeapOnly* CreatObj() { return new HeapOnly; } HeapOnly(const HeapOnly& hp) = delete; private: HeapOnly(){} }; int main() { HeapOnly* hp = HeapOnly::CreatObj(); delete hp; return 0; }
|
注意:也要把拷贝构造给删除掉
设计只能在栈上创建的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class StackOnly { public: static StackOnly CreatObj() { return StackOnly(); } private: StackOnly() {} }; int main() { StackOnly sk = StackOnly::CreatObj(); static StackOnly copy(sk); StackOnly* copy2 = new StackOnly(sk); return 0; }
|
解决new
1 2 3 4 5 6 7 8 9 10 11
| class StackOnly { public: static StackOnly CreatObj() { return StackOnly(); } void* operator new(size_t n) = delete; private: StackOnly() {} };
|
但是静态区的拷贝构造还是不能被禁止。
设计不能被继承的类
1 2 3 4 5 6 7 8 9 10 11
| class NonInherit { public: static NonInherit GetInstance() { return NonInherit(); } private: NonInherit(){} };
|
在C++11中有了final关键字,修饰类就说明该类不能被继承。
设计只能创建一个对象的类(单例)
饿汉模式
构造函数私有,在静态区创建一个对象,
- 简单,没有线程安全问题
- 一个程序中,多个单例,并且有先后创建初始化的顺序要求时,饿汉无法控制,比如多个文件,就无法控制顺序
- 饿汉的单例类,初始化时任务多,会影响程序的启动速度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class A { public: static A* getInstance() { return _a; } void fun() { std::cout << "调用fun()\n"; } private: A(){} static A* _a; };
A* A::_a = new A;
int main() { A* p = A::getInstance(); p->fun(); }
|
懒汉模式
第一次使用对象再创建实例对象
- 可以控制创建的顺序
- 不影响启动速度
- 相对复杂,有线程安全问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| class A { public: static A* getInstance() { if(_a == nullptr) { _a = new A; } return _a; } void fun() { std::cout << "调用fun()\n"; }
class CGarbo { public: ~CGarbo() { if (_a) delete _a; } };
private: A(){} static A* _a; };
A* A::_a = nullptr;
static A::CGarbo gc;
int main() { A* p = A::getInstance(); p->fun(); }
|
单例对象释放
- 一般情况下,单例对象不需要释放,因为一般整个程序运行期间都可能用它
- 单例对象在进程正常结束后,也会资源释放
- 有些特殊场景需要释放,比如单例对象析构时,要进行一些持久化操作(往文件数据库写)操作
- 释放时,可以做个内部类,如上边代码