特殊类的设计

张开发
2026/4/14 7:04:37 15 分钟阅读

分享文章

特殊类的设计
目录一、精准控制对象创建仅堆 / 仅栈实例化1. 仅允许在堆上创建对象HeapOnly2. 仅允许在栈上创建对象StackOnly二、限制类的行为禁止拷贝、不可继承1. 禁止拷贝构造与赋值CopyBan2. 不可被继承的类NonInherit三、设计模式实战单例模式饿汉 / 懒汉1. 饿汉模式饿汉式单例2. 懒汉模式懒汉式单例四、总结在 C 面向对象编程中灵活控制类对象的创建方式、限制拷贝行为、实现单例模式等是提升代码健壮性和设计合理性的核心技巧。本文将从 “仅堆 / 仅栈创建对象”“禁止拷贝”“不可继承”“单例模式饿汉 / 懒汉” 等场景出发详解各类特殊类的设计思路与实现细节帮助你掌握 C 类设计的进阶玩法。一、精准控制对象创建仅堆 / 仅栈实例化在实际开发中我们有时需要限制对象的创建位置比如仅允许堆上创建避免栈溢出或仅允许栈上创建管控内存核心思路是通过构造函数私有化运算符禁用实现。1. 仅允许在堆上创建对象HeapOnly要禁止栈上创建对象关键是私有化构造函数栈对象创建依赖公开的构造函数同时提供静态成员函数作为 “对象创建入口”并禁用拷贝构造 / 赋值防止通过拷贝绕开限制。#define _CRT_SECURE_NO_WARNINGS #includeiostream using namespace std; class HeapOnly { public: // 静态成员函数唯一的对象创建入口返回堆上对象的指针 static HeapOnly* CreateObj(int a) { HeapOnly* obj new HeapOnly; // 堆上创建对象 obj-_a a; return obj; } int get() { return _a; } // 辅助函数获取成员变量 private: // 1. 构造函数私有化禁止栈上直接创建如 HeapOnly obj; HeapOnly() : _a(0) {} // 2. 禁用拷贝构造C11避免通过拷贝创建栈对象 HeapOnly(const HeapOnly) delete; // 3. 禁用赋值运算符避免对象拷贝赋值 HeapOnly operator(const HeapOnly) delete; int _a; // 成员变量 }; int main() { // 正确通过静态函数获取堆对象 HeapOnly* sp1 HeapOnly::CreateObj(123); cout sp1-get() endl; // 输出 123 // 错误栈上创建被禁止构造函数私有 // HeapOnly obj; // 错误拷贝构造被禁用 // HeapOnly* sp2 new HeapOnly(*sp1); delete sp1; // 注意释放堆对象 return 0; }核心原理栈对象的创建会直接调用构造函数私有化后无法调用而静态成员函数属于类而非对象可访问私有构造函数从而唯一掌控对象的堆创建逻辑。2. 仅允许在栈上创建对象StackOnly要禁止堆上创建对象需禁用 new/delete 运算符堆对象依赖new分配内存同时私有化构造函数通过静态函数返回栈对象利用返回值优化避免拷贝。class StackOnly { public: // 静态函数返回栈对象编译器会优化拷贝无性能损耗 static StackOnly CreateObj(int a 0) { return StackOnly(a); } void PrintA() const { cout _a _a endl; } // 禁用 new/delete 及其数组版本彻底禁止堆创建 void* operator new(size_t size) delete; void operator delete(void* ptr) delete; void* operator new[](size_t size) delete; void operator delete[](void* ptr) delete; private: // 构造函数私有化避免直接创建必须通过 CreateObj StackOnly(int a 0) : _a(a) {} // 禁用所有拷贝/移动语义防止绕开限制 StackOnly(const StackOnly) delete; StackOnly operator(const StackOnly) delete; StackOnly(StackOnly) delete; StackOnly operator(StackOnly) delete; int _a; }; int main() { // 正确栈上创建对象 StackOnly obj1 StackOnly::CreateObj(10); obj1.PrintA(); // 输出 _a 10 // 错误堆创建被禁用new 运算符已删除 // StackOnly* ptr new StackOnly::CreateObj(20); return 0; }核心原理new运算符底层会调用operator new禁用该运算符后无法通过new分配堆内存静态函数返回栈对象时编译器的 “返回值优化RVO” 会直接在调用方栈上构造对象无需拷贝。二、限制类的行为禁止拷贝、不可继承1. 禁止拷贝构造与赋值CopyBan某些场景下如单例、资源独占类需要禁止对象拷贝核心是私有化并删除拷贝构造和赋值运算符C11 后推荐用 delete。class CopyBan { public: CopyBan() {} // 构造函数公开允许创建对象 private: // 禁用拷贝构造和赋值运算符 CopyBan(const CopyBan) delete; CopyBan operator(const CopyBan) delete; }; int main() { CopyBan obj1; // 错误拷贝构造被禁用 // CopyBan obj2 obj1; // 错误赋值运算符被禁用 // CopyBan obj3; // obj3 obj1; return 0; }2. 不可被继承的类NonInheritC 中没有原生的final关键字C11 后支持传统方式是将构造函数私有化—— 子类构造时需调用父类构造函数私有化后子类无法访问从而禁止继承。class NonInherit { public: // 静态函数获取类对象唯一创建入口 static NonInherit CreateObj() { return NonInherit(); } private: // 构造函数私有化子类无法调用禁止继承 NonInherit() {} }; // 错误子类无法访问父类私有构造函数 // class Derived : public NonInherit {}; int main() { NonInherit obj NonInherit::CreateObj(); return 0; }补充C11 后可直接用final关键字更简洁class NonInherit final {};三、设计模式实战单例模式饿汉 / 懒汉单例模式确保一个类只有一个实例并提供全局访问点。根据实例初始化时机分为 “饿汉模式”程序启动时初始化和 “懒汉模式”首次使用时初始化。1. 饿汉模式饿汉式单例“饿汉” 即 “迫不及待”在程序入口前完成单例对象初始化优点是线程安全无需加锁缺点是可能提前占用资源。class Singleton { public: // 全局访问点返回单例对象的引用避免拷贝 static Singleton GetInstance() { return *_inst; } private: // 1. 构造函数私有化 禁用拷贝防止外部创建/拷贝 Singleton() {} Singleton(const Singleton) delete; Singleton operator(const Singleton) delete; // 2. 静态指针存储单例对象程序启动时初始化 static Singleton* _inst; }; // 全局静态成员初始化程序入口前完成线程安全 Singleton* Singleton::_inst new Singleton; int main() { // 获取单例对象 Singleton obj1 Singleton::GetInstance(); Singleton obj2 Singleton::GetInstance(); // 验证obj1 和 obj2 是同一个对象 cout obj1 obj2 endl; // 地址相同 return 0; }2. 懒汉模式懒汉式单例“懒汉” 即 “懒加载”首次调用GetInstance时才初始化单例对象优点是按需分配资源缺点是多线程下需加锁保证线程安全双检查锁优化。#include mutex // 引入互斥锁 class Singleton { public: // 全局访问点双检查锁 懒加载 static Singleton GetInstance() { // 第一层检查避免每次调用都加锁提升性能 if (_inst nullptr) { _mtx.lock(); // 加锁保证线程安全 // 第二层检查防止多个线程同时通过第一层检查 if (_inst nullptr) { _inst new Singleton; } _mtx.unlock(); // 解锁 } return *_inst; } private: // 构造函数私有化 禁用拷贝 Singleton() {} Singleton(const Singleton) delete; Singleton operator(const Singleton) delete; // 静态成员单例指针 互斥锁 static Singleton* _inst; static mutex _mtx; }; // 静态成员初始化程序启动时置空 Singleton* Singleton::_inst nullptr; mutex Singleton::_mtx; // 初始化互斥锁 int main() { Singleton obj Singleton::GetInstance(); return 0; }双检查锁原理第一层if如果单例已创建直接返回避免每次加锁的性能损耗加锁后第二层if防止多个线程同时通过第一层检查重复创建对象。四、总结本文讲解的各类特殊类设计核心都是围绕构造函数、运算符、静态成员的灵活运用控制对象创建位置私有化构造函数 禁用new/delete/ 拷贝限制类行为删除拷贝构造 / 赋值、私有化构造函数单例模式私有化构造 静态指针 全局访问点饿汉提前初始化懒汉双检查锁。这些技巧在框架开发、资源管控、设计模式落地等场景中广泛应用掌握后能大幅提升 C 代码的设计能力和健壮性。

更多文章