业务处理时常常会出现一些特定的要求,需要设计出特殊的功能,下面介绍几个常见的特殊类设计
请设计一个类,不能被拷贝
涉及拷贝的只有拷贝构造
和赋值重载
,把这些禁用了就行了
1 2 3 4 5 6 7 8 9
| class CopyBan {
private: CopyBan(const CopyBan&); CopyBan& operator=(const CopyBan&); };
|
对于 C++98
,直接设置为私有即可,这样类外就无法访问了,只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了
1 2 3 4 5 6 7 8
| class CopyBan { CopyBan(const CopyBan&) = delete; CopyBan& operator=(const CopyBan&) = delete; };
|
对于 C++11
,直接在默认成员函数后跟上 = delete
,表示让编译器删除掉该默认成员函数
请设计一个类,只能在堆上创建对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class HeapOnly { public: static HeapOnly* CreateObject() { return new HeapOnly; } private: HeapOnly() {}
HeapOnly(const HeapOnly&);
HeapOnly(const HeapOnly&) = delete; };
|
创建对象需要构造函数,所以首先把构造函数给禁用了,还注意应该禁止拷贝构造,防止再创建,因为类内能调用构造函数,所以创建一个 public
函数提供接口
在构造函数被私有化的情况下,静态方法是唯一能够访问私有构造函数并创建对象的途径,静态方法属于类本身,而非类的某个实例,因此无需创建对象即可调用,例如: HeapOnly::CreateObject()
可直接通过类名调用
请设计一个类,只能在栈上创建对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class StackOnly { public: static StackOnly CreateObj() { return StackOnly(); }
void* operator new(size_t size) = delete; void operator delete(void* p) = delete; private: StackOnly() :_a(0) { } private: int _a; };
|
因为堆上创建销毁需要通过 new
和 delete
,之前又学过 new -> operator new + 构造函数
,delete -> operator delete + 析构函数
,所以直接将这些禁掉就好了
请设计一个类,不能被继承
1 2 3 4 5 6 7 8 9 10 11
| class NonInherit { public: static NonInherit GetInstance() { return NonInherit(); } private: NonInherit() {} };
|
C++98
中构造函数私有化,派生类中调不到基类的构造函数,则无法继承
final
关键字,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 25
| class Singleton { public: static Singleton* GetInstance() { return &m_instance; } private: Singleton() {};
Singleton(Singleton const&); Singleton& operator=(Singleton const&);
Singleton(Singleton const&) = delete; Singleton& operator=(Singleton const&) = delete;
static Singleton m_instance; };
Singleton Singleton::m_instance;
|
静态变量属于类而非对象,程序运行期间仅存在一份实例,且在程序入口(main()
)前初始化,static Singleton m_instance;
是声明,Singleton Singleton::m_instance;
是定义
饿汉模式在程序启动时(或类加载时)立即创建单例实例,若实例的初始化逻辑复杂(如:
读取大文件 / 配置(如数据库连接、配置文件)
网络请求(初始化远程服务连接)
复杂计算(预加载数据字典、缓存构建)
这些操作会阻塞进程的启动流程,导致启动时间明显增加
全局静态对象的初始化顺序问题:
在 C++
中,多个全局静态对象的初始化顺序是未定义的(由编译器和链接器决定),若某个饿汉单例 A
依赖另一个全局对象 B
,而 B
的初始化顺序在 A
之后,会导致 A
初始化时访问未初始化的 B
,引发逻辑错误或崩溃
这类问题难以调试,且会间接增加启动阶段的异常处理开销
🚩懒汉模式
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| class Singleton { public: static Singleton& GetInstance() { if (_psinst == nullptr) { _psinst = new Singleton; }
return *_psinst; }
static void DelInstance() { if (_psinst) { delete _psinst; _psinst = nullptr; } }
void Add(const pair<string, string>& kv) { _dict[kv.first] = kv.second; }
void Print() { for (auto& e : _dict) { cout << e.first << ":" << e.second << endl; } cout << endl; }
class GC { public: ~GC() { lazy::Singleton::DelInstance(); } };
private: Singleton() { }
~Singleton() { cout << "~Singleton()" << endl;
FILE* fin = fopen("map.txt", "w"); for (auto& e : _dict) { fputs(e.first.c_str(), fin); fputs(":", fin); fputs(e.second.c_str(), fin); fputs("\n", fin); } }
Singleton(const Singleton& s) = delete; Singleton& operator=(const Singleton& s) = delete;
map<string, string> _dict;
static Singleton* _psinst; static GC _gc; };
Singleton* Singleton::_psinst = nullptr; Singleton::GC Singleton::_gc;
|
在第一次使用时才初始化单例实例,而非程序启动时。这种方式避免了不必要的资源浪费,但需要处理多线程环境下的线程安全问题
希望读者们多多三连支持
小编会继续更新
你们的鼓励就是我前进的动力!
