C++特殊类设计(不能被拷贝的类、只能在堆上创建对象的类、不能被继承的类 ...

打印 上一主题 下一主题

主题 808|帖子 808|积分 2424

C++特殊类设计

在实际应用中,可能必要设计一些特殊的类对象,如不能被拷贝的类、只能在堆上创建对象的类、只能在栈上创建对象的类、不能被继承的类、只能创建一个对象的类(单例模式)
1. 不能被拷贝的类

拷贝只会发生在两个场景中:拷贝构造函数和赋值运算符重载。因此,让一个类禁止被拷贝,只必要让其拷贝构造函数和赋值运算符重载不能被调用即可
1.1 c++98做法

c++98通过将拷贝构造函数和赋值运算符重载只声明不界说,并将其访问权限设置为私有实现禁止被拷贝。
  1. class CopyBan
  2. {
  3. private:
  4.         CopyBan(const CopyBan& cb);
  5.         CopyBan& operator=(const CopyBan & cb);
  6. };
复制代码
1.2 现代做法

利用c++11提供的delete关键字“删除”拷贝构造函数和赋值运算符重载。
  1. class CopyBan
  2. {
  3. private:
  4.         CopyBan(const CopyBan& cb) = delete;
  5.         CopyBan& operator=(const CopyBan& cb) = delete;
  6. };
复制代码
2. 只能在堆上创建对象的类

2.1 直接法

要使一个类只能在堆上创建对象,思路是:
   

  • 将类的构造函数和拷贝构造函数私有,防止别人调用拷贝在栈上生成对象。
  • 再提供一个静态成员函数,在该静态成员函数内部完成堆对象的创建。
  1. class HeapOnly
  2. {
  3.         static HeapOnly* Create()//静态解决“先有函数还是现有对象问题”
  4.         {
  5.                 return new HeapOnly;
  6.         }
  7. private:
  8.         HeapOnly(){}
  9. };
复制代码
但此不能完全封死在栈上创建对象,如果通过 Create()函数先创建一个堆上的对象,再利用默认拷贝构造拷贝堆上的对象,就能够实现在栈上创建对象。
  1. HeapOnly* ho1 = HeapOnly::Create();
  2. HeapOnly* ho2(ho1);
复制代码
以是末了还必要封死通过拷贝构造创建栈上对象:
   c++98:private:HeapOnly& HeapOnly(const HeapOnly& ho){}
  c++11:HeapOnly& HeapOnly(const HeapOnly& ho)=delete;
  2.2 私有析构函数法

设计不能被拷贝的类还有一种方法,通过私有化析构函数,让栈上对象无法在脱离作用域时自动调用析构函数,因此在栈上的创建对象的代码都不能被编译通过。再设计一个 release()函数手动释放堆上的对象
  1. class HeapOnly
  2. {
  3. public:
  4.         static HeapOnly* Create()
  5.         {
  6.                 return new HeapOnly;
  7.         }
  8.         void relase()
  9.         {
  10.                 delete this;
  11.         }
  12. private:
  13.         ~HeapOnly(){}
  14. };
复制代码
3. 只能在栈上创建对象的类

要使一个类只能在栈上创建对象,思路是:
   

  • 私有化构造函数
  • 设计静态函数返回对象
  1. class StackOnly
  2. {
  3. public:
  4.         static StackOnly Create()
  5.         {
  6.                 return StackOnly();
  7.         }
  8.         void* operator new(size_t size) = delete;
  9.         void operator delete(void* p) = delete;
  10. private:
  11.         StackOnly():_a(0){}
  12.         int _a;
  13. };
复制代码
设计只能在栈上创建对象的类还要注意将new和delete删除,避免利用new通过拷贝构造创建堆上对象。且由于 Create()函数被设计成传值返回,不能直接通过删除拷贝构造实现(因为临时对象)。
   删除new和delete的原理是,编译器默认生成一个new和一个delete,现将重载new和delete在类中重载,那么类对象会调用重载的new和重载的delete(重载后不再默认生成),但由于重载的new和重载的delete被删除,类对象在创建时便无法利用。
  1. StackOnly so1 = StackOnly::Create();
  2. StackOnly* so2 = new StackOnly(so1);
复制代码
4. 不能被继承的类

要使一个类不能被继承,方法是:
   

  • c++98:基类析构函数私有,派生类不能调用基类的构造函数,无法编译通过
  • c++11:利用final关键字标记基类,表现该类不能被继承
  5. 单例模式

单例模式要求一个类只能创建一个对象,该模式可以抱枕系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有步伐模块共享。
单例模式有两种实现模式:

  • 饿汉模式
  • 懒汉模式
5.1 饿汉模式

饿汉形容步伐对对象的必要比较紧急,不管将来用不消,在步伐启动时就马上先创建一个唯一的实例对象(一般在main函数之前创建)。
  1. #include<iostream>
  2. using namespace std;
  3. class ehan
  4. {
  5. public:
  6.         static ehan* GetInstance()
  7.         {
  8.                 return &_e;
  9.         }
  10.         int SetInfo(int info)
  11.         {
  12.                 _info = info;
  13.                 return _info;
  14.         }
  15.         ehan(const ehan& e) = delete;
  16.         ehan& operator=(const ehan& e) = delete;
  17. private:
  18.         ehan(){}
  19.         int _info;
  20.         static ehan _e;//声明
  21. };
  22. ehan ehan::_e;//定义
  23. int main()
  24. {
  25.         cout<<ehan::GetInstance()->SetInfo(1);
  26.         return 0;
  27. }
复制代码
  优先:简单
  缺点:可能会导致进程启动慢,且如果有多个单例类利用饿汉模式,它们的对象实例启动顺序不确定
  5.2 懒汉模式

懒汉模式可以完美解决饿汉模式的缺点,懒汉模式一般在第一次调用 GetInstance() 的时间创建单例对象。
  1. #include<iostream>
  2. using namespace std;
  3. class lanhan
  4. {
  5. public:
  6.         static lanhan* GetInstance()
  7.         {
  8.                 static lanhan _lh;
  9.                 return &_lh;
  10.         }
  11.         int SetInfo(int info)
  12.         {
  13.                 _info = info;
  14.                 return _info;
  15.         }
  16.         lanhan(const lanhan& e) = delete;
  17.         lanhan& operator=(const lanhan& e) = delete;
  18. private:
  19.         lanhan(){}
  20.         int _info;
  21. };
  22. int main()
  23. {
  24.         cout<<lanhan::GetInstance()->SetInfo(1);
  25.         return 0;
  26. }
复制代码
  这里在 GetInstance()里 界说了一个局部静态对象 static lanhan _lh; ,即使调用多次 GetInstance(),这个创建对象的代码也只会实行一次,但这种利用方法是c++11之后支持,且有线程安全风险
  传统且线程安全方法:
  1. #include<iostream>
  2. #include<mutex>
  3. using namespace std;
  4. class lanhan
  5. {
  6. public:
  7.         static lanhan* GetInstance()
  8.         {
  9.                 if (_lh == nullptr)//双重检查保证线程安全
  10.                 {
  11.                         unique_lock<mutex> lock(_mtx);
  12.                         if (_lh == nullptr)
  13.                         {
  14.                                 _lh = new lanhan;
  15.                         }
  16.                 }
  17.                 return _lh;
  18.         }
  19.         int SetInfo(int info)
  20.         {
  21.                 _info = info;
  22.                 return _info;
  23.         }
  24.         lanhan(const lanhan& e) = delete;
  25.         lanhan& operator=(const lanhan& e) = delete;
  26. private:
  27.         lanhan(){}
  28.         int _info;
  29.         static mutex _mtx;
  30.         static lanhan* _lh;
  31. };
  32. lanhan* lanhan::_lh = nullptr;
  33. mutex lanhan::_mtx;
  34. int main()
  35. {
  36.         cout<<lanhan::GetInstance()->SetInfo(1);
  37.         return 0;
  38. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

渣渣兔

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表