1.首先讲解一下什么是类对象的静态分配和动态分配。
类对象的静态分配:例如 A a;这个方式是由编译器在编译阶段完成的,主要是通过直接移动栈顶指针,挪出适当的空间,然后在这个 内存空间上调用构造函数形成一个栈对象。也就是说直接调用类的构造函数来生成一个类对象。
类对象的动态分配:例如:A* a = new A();编译器对于类对象的内存分配是在运行时动态分配的,使用new产生的对象会建立在堆区。这个过程分为两步进行:
(1)执行函数operator new()函数,找到合适的内存进行分配。
(2)调用构造函数,初始化这片内存空间。
2.接下来说说如何只能静态分配和如何只能动态分配。
如何只能静态分配(也就是不能产生堆对象)?
只能静态分配,也就是说不能使用new和delete来产生或者释放空间内存,由于operator new()和oper delete()可以重载,将这两部分设置为private即可。
例如:
class test{
private:
void operator new()(size_t t){}
void operator delete(void *p){}
public:
test(){}
~test(){}
};
如何只能动态分配(也就是说不产生栈对象)?
刚开始的想法是,将构造函数设置为private,但是你这样也会导致无法动态生成堆对对象。考虑将析构函数设置成private,那么问题来了,在静态分配过程中,析构函数的不能调用会影响构造函数的调用吗?答案是肯定的,这是因为编译器再为其分配栈对象的时候,会先检查类的析构函数的可访问性(当然也包括其他的非静态函数),如果析构函数在类外无法访问,那么拒绝在栈空间为类对象分配内存。
class test{
public:
test(){}
private:
~test(){}
};
int main()
{
test t;
}
上边的这部分代码编译不通过,是因为将test的析构函数设置为私有的。因此从析构函数入手是正确的,但是这样也使得无法该类无法继承,因此考虑将其设置为protected,这样既可以继承,也可以禁止产生栈对象。
总结:如果只想静态产生类对象,那么僵new和delete操作符设置为私有的;如果只想动态产生类对象,那么将析构函数设置为私有的(不能继承)或者是保护(可继承)。