C++实现一个只能在堆(栈)上生成对象的类
C++实现一个只能在堆(栈)上生成对象的类
2019-10-23 10:16:20 逆鳞 阅读数 51更多
目录
在C++中,类的对象创建可以静态创建在栈区, 如A a;还可以动态创建在堆区,如A* ptr=new A;这两种方式是不同的, 具体来
静态建立一个类的对象,是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象。使用这种方法,直接调用类的构造函数。
动态建立类对象,是使用new运算符将对象建立在堆空间中, 是程序员主动申请的堆空间. 这个过程分为两步,第一步是执行operator new()函数,在堆空间中搜索合适的内存并进行分配 ; 第二步是调用构造函数构造对象,初始化这片内存空间。这种方法,会间接调用类的构造函数。
只能在堆上生成对象的类
总的思路就是使其不能在栈上创建, 在堆上可以
思路一: 构造函数私有化
1. 不能让这个类在栈上创建, 由于在栈上创建对象要直接调用构造函数, 如果我们把构造函数私有化, 就 无法在栈上创建对象了
2. 那么我们又如何在堆上创建对象呢, 由于创建对象必定要调用构造函数, 在我们不定义其他构造函数时, 我们已经将两个默认构造函数已经私有, 在类外肯定是调用不到构造函数, 我们只有定义一个公有的静态成员函数 ,在其内部用new在堆区创建对象并返回其指针, (这里有很难以理解的一点, 在静态成员函数中用new 创建一个对象时, 也会调用构造函数, 我们知道, 静态成员函数不能调用成员函数, 那么new是如何调到构造函数的呢? 这得从静态成员函数为什么不能访问成员函数说起, 每一个对象都有一个隐含的this指针, 访问成员函数实际上时通过this指针调用的, 而在构造函数调用前还没有实例化出对象, 也就没有this指针, 所以构造函数不需要this指针调用, 静态成员函数也就可以调用构造函数了), 这点解释通了还值得注意的是, 还必须将拷贝构造私有化, 不然会出现 用堆上创建好的对象拷贝构造一个栈上的对象这种情况发生
上代码
class.h
-
#pragma once
-
class T1 {
-
T1(int val):b(val) {
-
}
-
T1(T1& x):b(x.b){
-
}
-
public:
-
int b;
-
static T1* newT1_p(int val = 0) {
-
return new T1(val);
-
}
-
static T1& newT1(int val = 0) {
-
return *new T1(val);
-
}
-
};
测试入口main.cpp
-
#include<iostream>
-
#include"class.h"
-
int main() {
-
T1* t1_p = T1::newT1_p(10);
-
cout << t1_p->b << endl;
-
T1& t1 = T1::newT1(20);
-
cout << t1.b << endl;
-
system("pause");
-
return 0;
-
}
运行结果 :
如果我们静态创建在栈上的话编译不过, 如下:
-
#include<iostream>
-
#include"class.h"
-
using namespace std;
-
int main() {
-
T1 t2;
-
T1 t3(10);
-
system("pause");
-
return 0;
-
}
运行结果: 编译未通过, 原因是构造函数私有化, 无法在类外访问
思路二: 析构函数私有化
将析构函数私有化, 在栈上也就不能直接创建对象了, 因为编译器在编译时会进行检测, 那没有析构函数也是不行的, 我们还需要实现一个函数来调用私有的析构函数, (这个思路就比构造函数私有好理解多了)
上代码
class.h
-
class T2 {
-
~T2() {
-
delete this;
-
}
-
public:
-
int b;
-
T2(int val = 0) :b(val) {
-
}
-
void Destroy() {
-
this->~T2();
-
}
-
};
测试入口 main.cpp
-
#include<iostream>
-
#include"class.h"
-
using namespace std;
-
int main() {
-
T2* t2_p = new T2(10);
-
t2_p = t2_p->Destroy();
-
cout << t2_p->b << endl;
-
system("pause");
-
return 0;
-
}
尝试在栈上创建
-
#include<iostream>
-
#include"class.h"
-
using namespace std;
-
int main() {
-
T2 a;
-
T2 b(10);
-
system("pause");
-
return 0;
-
}
只能在栈上生成对象的类
总体思路就是一个普通的类, 不让其在堆上创建对象, 在堆上创建对象必定要用到new ,那我们直接在这个类内部将new重载成一个私有的成员函数, 目的就是让在类外使用不到原来的操作符new, 这样在类外就无法在堆上创建这个对象了
上代码
class.h
-
#pragma once
-
class T3 {
-
void* operator new(size_t val) {}
-
public:
-
int a;
-
T3(int val = 0) :a(val) {
-
}
-
};
测试入口main.cpp
-
#include<iostream>
-
#include"class.h"
-
using namespace std;
-
int main() {
-
T3 a;
-
cout << a.a << endl;
-
T3 b(10);
-
cout << b.a << endl;
-
system("pause");
-
return 0;
-
}
尝试用new在堆上创建
-
#include<iostream>
-
#include"class.h"
-
using namespace std;
-
int main() {
-
T3* p1 = new T3;
-
T3* p2 = new T3(10);
-
system("pause");
-
return 0;
-
}
运行结果: 创建不成功