C++:让一个类只能在堆/栈上创建对象

C++:让一个类只能在堆/栈上创建对象

在C++中,类的对象创建有两种形式,一是静态创建,如A a;另一种是动态创建,如A *p=new A;

静态创建一个类对象,是由编译器为对象在栈空间中分配内存。

动态创建对象,是使用new运算符将对象创建在堆空间中。

动态创建又分为两步:

  1. operate new()函数在堆空间找到合适内存并分配

  2. 调用构造函数构造对象,初始化内存空间

operate new()

在说创建对象前,先聊一下operate new()的重载。

如果不想使用系统原始的内存分配方式时,可以自定义内存分配方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
//size_t sz系统会自动计算提供,不需要传参
void * operator new(size_t sz)
{
cout << "void * operator new(size_t)" << endl;
void * p = malloc(sz);
return p;
}

void operator delete(void * p)
{
free(p);
cout << "void operator delete(void*)" << endl;
}

只能生成栈对象

new创建的对象会在栈空间,那么把new和delete放在private中,不允许调用即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <string.h>
#include <iostream>
using namespace std;

//一个类只能生成栈对象,不能生成堆对象
// 将operator new/delete放入Private区域

class Student
{
public:
Student(int id, const char * name)
: _id(id)
, _name(new char[strlen(name) + 1]())
{
strcpy(_name, name);
cout << "Student(int, const char *)" << endl;
}

~Student()
{
delete [] _name;
cout << "~String()" << endl;
}

private:
void * operator new(size_t sz);
void operator delete(void * p);
private:
int _id;
char * _name;
};

int main(void)
{
//Student * pstu = new Student(1001, "Mary");//error
Student student(1002, "Jackie");//ok
student.print();

return 0;
}

只能生成堆对象

类对象只能创建在堆上,即不能静态创建对象。

构造函数私有貌似能解决这个问题,想想上面说的new实际上两步,第二步要使用构造函数进行初始化,故并不可行。

这里很巧妙,把该类的析构函数私有化。因为如果静态创建对象,编译器在对象使用完后会自动调用析构函数释放空间,但是析构函数为私有的,导致编译器无法调用析构函数,所以如果析构函数是私有的,编译器不会在栈空间上为类分配内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <string.h>
#include <iostream>
using namespace std;

//要求:一个类只能生成堆对象,不能生成栈对象
// 将该类的析构函数放入private区域
class Student
{
public:
Student(int id, const char * name)
: _id(id)
, _name(new char[strlen(name) + 1]())
{
strcpy(_name, name);
cout << "Student(int, const char *)" << endl;
}

void destroy()
{
//this->~Student();
delete this;
}

private:
~Student()
{
delete [] _name;
cout << "~String()" << endl;
}

private:
int _id;
char * _name;
};

int main(void)
{
Student * pstu = new Student(1001, "Mary");//正确
pstu->print();
pstu->destroy();

//delete pstu;//错误 在类之外

//Student student(1886, "Rookie");//error
//student.print();

}

参考资料