从真实开发经历来讲,只允许在栈上或者堆上创建对象的情况比较少,当然也有可能是我用C++开发的时间并不长。
Case 1 只在栈上创建
1、不考虑子类
C++使用new来申请对象空间,要想只让其在栈上申请,要么让其在堆上无法申请,要么让其无法释放。
所以,让new操作符或者delete操作符无法使用就可以了。
class Base
{
public:
protected:
private:
void* operator new(size_t t) {};
void operator delete(void *) {};
};
int main()
{
Base* b = new Base;
Base d;
return 0;
}
此时new操作会报一个语法错误(IDE为vs2015),这里我们还可以看到编译器首先去检查的是操作符delete而不是new,所以只需要让操作符delete无法使用就足够了。
在C++11以后的标准,我们还可以用delete(当然不是释放内存用的)关键字来实现。
class Base
{
public:
void operator delete(void *) = delete;
protected:
private:
};
int main()
{
Base* b = new Base;
Base d;
return 0;
}
此时操作符的编译错误是。
这里还有一个有意思的地方,可以看到两个new的声明是不一样的,而第二个还有一个+3重载,这个问题留着下回再讲:-)。
2、考虑子类
由于基类已经无法在堆上申请所需空间,对于子类而言,由于其先要为基类申请空间。因此,子类必然不能在堆上创建对象。
Case 2 只在堆上申请
1、不考虑子类
要想只在堆上申请,当然只有让其不能自动在栈上创建对象,所以可以让对象无法执行构造函数或者析构函数。
class Base
{
public:
protected:
private:
Base(){};
~Base(){};
};
int main()
{
Base b;
return 0;
}
这时候,申明一个对象会报错。注意这儿是先检查构造函数,而不是析构函数,跟new、delete可不一样。
当然,此时也不能直接使用new操作符在堆上申请,所以我们取巧一下。
class Base
{
public:
static Base* create(size_t t = 1)
{
return new Base[t];
}
static void destroy(Base* b)
{
delete[] b;
}
protected:
private:
Base(){};
~Base(){};
};
int main()
{
Base* d = Base::create(10);
Base::destroy(d);
return 0;
}
在用new创建对象的时候最好用申请数组的方式,同时将长度参数默认设置为1,那样会更具有通用性一些。
注意此时不能用delete关键字去禁用构造函数或者析构函数,因为在创建对象的时候,无论如何总要调用构造函数,在释放对象的时候,总要调用析构函数。
2、考虑子类
如果是要让子类不受基类影响,可以把构造函数或者析构函数设为保护对象,对于子类而言,基类的保护成员是可以访问的。
class Base
{
public:
static Base* create(size_t t = 1)
{
return new Base[t];
}
static void destroy(Base* b)
{
delete[] b;
}
protected:
~Base(){};
private:
};
class Derive :public Base
{
};
int main()
{
Base* b = Base::create(10);
Base::destroy(b);
Derive* d = new Derive;
delete d;
Derive d2;
return 0;
}
如果是要像基类一样只允许在堆上创建对象,那就得像基类一样再实现一遍create,destroy咯。
class Base
{
public:
static Base* create(size_t t = 1)
{
return new Base[t];
}
static void destroy(Base* b)
{
delete[] b;
}
protected:
~Base(){};
private:
};
class Derive :public Base
{
public:
static Derive* create(size_t t = 1)
{
return new Derive[t];
}
static void destroy(Derive* b)
{
delete[] b;
}
protected:
~Derive() {};
};
int main()
{
Derive* d = Derive::create(10);
Derive::destroy(d);
return 0;
}