特殊类设计

2023-04-20 19:16:07 浏览数 (1)

设计不能被拷贝的类

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();
}

单例对象释放

  • 一般情况下,单例对象不需要释放,因为一般整个程序运行期间都可能用它
  • 单例对象在进程正常结束后,也会资源释放
  • 有些特殊场景需要释放,比如单例对象析构时,要进行一些持久化操作(往文件数据库写)操作
  • 释放时,可以做个内部类,如上边代码

0 人点赞