设计一个只允许在堆或栈上创建的对象
2018-04-10 本文已影响0人
cp3_1dbc
只允许在堆上创建
这很容易做到。非堆对象(non-heap object)在定义它的地方被自动构造,在生存时间结束时自动被释放,所以只要禁止使用隐式的构造函数和析构函数,就可以实现这种限制。
把这些调用变得不合法的一种最直接的方法是把构造函数和析构函数声明为 private。这样做副作用太大。没有理由让这两个函数都是 private。最好让析构函数成为 private,让构造函数成为 public。
- example1 代码如下:
#include <iostream>
class CreateOnHeap
{
public:
CreateOnHeap() {}
void destroy() const {
delete this;
}
private:
~CreateOnHeap() {}
};
int main() {
//CreateOnHeap c1; //compile error
CreateOnHeap* c2 = new CreateOnHeap;
c2->destroy();
return 0;
}
这样设计有个问题
- 这样的类无法作为基类
- 者其它类的成员
- example2 代码如下:
#include <iostream>
class CreateOnHeap
{
public:
CreateOnHeap() {}
void destroy() const {
delete this;
}
private:
~CreateOnHeap() {}
};
//作为基类
class CreateOnHeapDerived : public CreateOnHeap
{
public:
CreateOnHeapDerived() {}
};
//作为其他类成员
class CreateOnHeapOther
{
public:
CreateOnHeapOther() {}
private:
CreateOnHeap _c;
};
int main() {
return 0;
}
对于第一个问题,可以将基类的析构函数声明为protected(子类可以访问基类的protected成员);对于第二个问题,可以声明为指针类型。
- example3 代码如下:
class CreateOnHeap2
{
public:
CreateOnHeap2() {}
void destroy() const {
delete this;
}
protected:
~CreateOnHeap2() {}
};
class CreateOnHeapDerived2 : public CreateOnHeap2
{
public:
CreateOnHeapDerived2() {}
};
class CreateOnHeapOther2
{
public:
CreateOnHeapOther2() {
_c = new CreateOnHeap2;
}
~CreateOnHeapOther2() {
_c->destroy();
}
private:
CreateOnHeap2* _c;
};
example2中的创建方法很怪异,用运算符new分配对象却需要用自定义的函数destroy去释放,可以改成下面的实现方式
- example4 代码如下:
class CreateOnHeap3 {
protected:
CreateOnHeap3() { }
~CreateOnHeap3() { }
public:
static CreateOnHeap3* creatInstance() {
return new CreateOnHeap3() ;//调用保护的构造函数
}
void destroy() {
delete this ;//调用保护的析构函数
}
};
禁止在堆上创建对象
禁止用户直接实例化对象很简单,因为总是调用 new 来建立这种对象,你能够禁止用户调用 new。你不能影响 new 操作符的可用性(这是内嵌于语言的),但是你能够利用 new 操作符总是调用 operator new 函数这点,来达到目的。
class ForbidCreateOnHeap {
private:
static void *operator new(size_t size);
static void operator delete(void *ptr);
};
int main() {
ForbidCreateOnHeap c7; //ok
static ForbidCreateOnHeap c8; //OK
ForbidCreateOnHeap* c9 = new ForbidCreateOnHeap; //compile error
}
如果也想禁止堆对象数组,可以把operator new[]和operator delete[]也声明为private。
控制对象的个数
如果只允许产生一个对象,我们很容易可以想到使用单例模式,如果创建多个呢,可以使用一个static变量去记录已经创建的对象的个数。
class CObject
{
public:
CObject();
~CObject();
private:
static size_t m_nObjCount;
};
CObject::CObject()
{
if (m_nObjCount > N)
throw;
m_nObjCount++;
}
CObject::~CObject()
{
m_nObjCount--;
}
size_t CObject::m_nObjCount = 0;