设计不能被拷贝的类
代码语言:javascript复制c 11是下边的用法,c 98就是将拷贝构造变成私有,并且只声明并不实现
class A
{
public:
A(int val):_val(val){}
A(const A& a) = delete;
A& operator=(const A& a) = delete;
private:
int _val;
};
设计只能在堆上创建的类
代码语言:javascript复制方案1、将析构函数私有化
class HeapOnly
{
public:
void destroy()
{
delete this;
}
private:
~HeapOnly(){}
};
int main()
{
HeapOnly* hp = new HeapOnly;
hp->destroy();
return 0;
}
代码语言:javascript复制方案2、构造函数私有
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(){}
};
代码语言:javascript复制在C 11中有了final关键字,修饰类就说明该类不能被继承。
class A final
{
// ....
};
设计只能创建一个对象的类(单例)
饿汉模式
构造函数私有,在静态区创建一个对象,
- 简单,没有线程安全问题
- 一个程序中,多个单例,并且有先后创建初始化的顺序要求时,饿汉无法控制,比如多个文件,就无法控制顺序
- 饿汉的单例类,初始化时任务多,会影响程序的启动速度。
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();
}
懒汉模式
第一次使用对象再创建实例对象
- 可以控制创建的顺序
- 不影响启动速度
- 相对复杂,有线程安全问题
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();
}
单例对象释放
- 一般情况下,单例对象不需要释放,因为一般整个程序运行期间都可能用它
- 单例对象在进程正常结束后,也会资源释放
- 有些特殊场景需要释放,比如单例对象析构时,要进行一些持久化操作(往文件数据库写)操作
- 释放时,可以做个内部类,如上边代码