前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >特殊类设计

特殊类设计

作者头像
芝士就是菜
发布2023-04-20 19:16:07
3140
发布2023-04-20 19:16:07
举报
文章被收录于专栏:芝士就是菜芝士就是菜

设计不能被拷贝的类

c++11是下边的用法,c++98就是将拷贝构造变成私有,并且只声明并不实现

代码语言:javascript
复制
class A
{
public:
 A(int val):_val(val){}
 A(const A& a) = delete;
 A& operator=(const A& a) = delete;
private:
 int _val;
};

设计只能在堆上创建的类

方案1、将析构函数私有化

代码语言:javascript
复制
class HeapOnly
{
public:
 void destroy()
 {
  delete this;
 }
private:
 ~HeapOnly(){}
};
int main()
{
 HeapOnly* hp = new HeapOnly;
 hp->destroy();
 return 0; 
}

方案2、构造函数私有

代码语言:javascript
复制
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; 
}
代码语言:javascript
复制
注意:也要把拷贝构造给删除掉

设计只能在栈上创建的类

代码语言:javascript
复制
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

代码语言:javascript
复制
class StackOnly
{
public:
 static StackOnly CreatObj()
 {
  return StackOnly();
 }
 void* operator new(size_t n) = delete;
private:
 StackOnly() {}
};

但是静态区的拷贝构造还是不能被禁止。

设计不能被继承的类

代码语言:javascript
复制
// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承  
class NonInherit  
{  
public:  
 static NonInherit GetInstance()  
 {  
  return NonInherit();  
 }  
private:  
 NonInherit(){}  
};

在C++11中有了final关键字,修饰类就说明该类不能被继承。

代码语言:javascript
复制
class A final
{
// ....  
};

设计只能创建一个对象的类(单例)

饿汉模式

构造函数私有,在静态区创建一个对象,

  • 简单,没有线程安全问题
  • 一个程序中,多个单例,并且有先后创建初始化的顺序要求时,饿汉无法控制,比如多个文件,就无法控制顺序
  • 饿汉的单例类,初始化时任务多,会影响程序的启动速度。
代码语言:javascript
复制
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();
}

懒汉模式

第一次使用对象再创建实例对象

  • 可以控制创建的顺序
  • 不影响启动速度
  • 相对复杂,有线程安全问题
代码语言:javascript
复制
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;
// 回收对象,main函数结束后,他会调用析构函数,就会释放单例对象
static A::CGarbo gc;

int main()
{
 A* p = A::getInstance();
 p->fun();
}

单例对象释放

  • 一般情况下,单例对象不需要释放,因为一般整个程序运行期间都可能用它
  • 单例对象在进程正常结束后,也会资源释放
  • 有些特殊场景需要释放,比如单例对象析构时,要进行一些持久化操作(往文件数据库写)操作
  • 释放时,可以做个内部类,如上边代码
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-01-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 芝士就是菜 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 设计不能被拷贝的类
  • 设计只能在堆上创建的类
  • 设计只能在栈上创建的类
  • 设计不能被继承的类
  • 设计只能创建一个对象的类(单例)
    • 饿汉模式
      • 懒汉模式
        • 单例对象释放
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档