C++之new和delete重载
2016-06-06 19:35
441 查看
首先要知道new和delete是一种运算符,而malloc和free是一种系统调用函数,因此new和delete是可以重载的。
先来举个例子看一下new与delete 和 malloc与free的区别:
很明显的可以看出new和delete会分别自动调用构造器和析构器,而malloc和free则不会。
一、new 和delete重载
new和delete既可以作为全局函数重载,也可以作为局部成员函数重载。先看全局函数重载:
输出结果:
首先在A类中加入了一个int型的数据成员,那么sizeof(A) = 4, 这里对new的重载函数的参数中有个size_t类型,这实际是个unsigned int类型, size就是用来表示需要分配的空间大小,内部的机制会知道应该分配4个字节的空间给类A的对象,至于是如何知道的,这个就对我们隐蔽了(所以对new的重载并不是真正的重载,内部的东西我们还是不知道的),通过对new和delete的重载也可以发现其实函数体中就是利用malloc和free去实现的。
现在加入一个double型的指针:
结果是这样的:
可以看到就算new一个double也是用的我们重载的new和delete,这就是全局函数重载的覆盖性,特别的广,只要用到new和delete全是从全局函数去操作,因为影响范围太广,所以一般不建议这么做,那么就要进行局部成员函数重载。像这样:
把重载函数放到类中,当成成员函数,运行结果就是这样的:
可以看到这样就不会影响到其他类型的new和delete了。
一、new[] 和delete[]重载
new[]和delete[]与new和delete的重载很相似,只不过多了个[]而已,这里直接用局部的,全局的就不再举例了:
运行结果:
可以看到构造了5次,也析构了五次,重点要说的是为什么这里的size = 24, 却不是20呢。这还得从malloc说起:
这里为p开辟了100字节的空间,然后释放,只通过free(p)系统怎么知道应该释放多少空间呢,其实底层,在为p开辟空间的时候既存储了p,也存储了100这是值,那么在释放的时候就知道对p释放100空间了。new[]这个地方也是一样的,不仅存储了本身开辟的空间,同时也存储了一个指针,所以size = (4 * 5) + 4 = 24字节。
三、new重载的优点
new重载有个特别有优势的地方,我们知道类的数据成员一般都是最先在构造器中初始化的,用new重载之后,可以把数据成员的舒适化放在new中,比构造器中的初始化还早,还是使用上面的例子,这里只单独给出new的重载:
结果是这样的
可以看到数据成员的的确确被初始化了。
四、总结
最后再总结一下重载格式:
先来举个例子看一下new与delete 和 malloc与free的区别:
class A{ public: A(){ cout << "constuctor" << endl; } ~A(){ cout << "distuctor" << endl; } }; int main() { A *a = new A; delete a; cout << "--------------------" << endl; A *b = (A*)malloc(sizeof(A)); free(b); return 0; }
很明显的可以看出new和delete会分别自动调用构造器和析构器,而malloc和free则不会。
一、new 和delete重载
new和delete既可以作为全局函数重载,也可以作为局部成员函数重载。先看全局函数重载:
class A{ public: A(){ cout << "constuctor" << endl; } ~A(){ cout << "distuctor" << endl; } int data; }; void* operator new(size_t size){ cout << "size = " << size << endl; cout << "void* operator new(size_t size)" << endl; void *p = malloc(size); return p; } void operator delete(void* p){ cout << "void operator delete(A* p)" << endl; free(p); } int main() { A *a = new A; delete a; return 0; }
输出结果:
首先在A类中加入了一个int型的数据成员,那么sizeof(A) = 4, 这里对new的重载函数的参数中有个size_t类型,这实际是个unsigned int类型, size就是用来表示需要分配的空间大小,内部的机制会知道应该分配4个字节的空间给类A的对象,至于是如何知道的,这个就对我们隐蔽了(所以对new的重载并不是真正的重载,内部的东西我们还是不知道的),通过对new和delete的重载也可以发现其实函数体中就是利用malloc和free去实现的。
现在加入一个double型的指针:
int main() { A *a = new A; delete a; double *p = new double; delete p; return 0; }
结果是这样的:
可以看到就算new一个double也是用的我们重载的new和delete,这就是全局函数重载的覆盖性,特别的广,只要用到new和delete全是从全局函数去操作,因为影响范围太广,所以一般不建议这么做,那么就要进行局部成员函数重载。像这样:
class A{
public:
A(){
cout << "constuctor" << endl;
}
~A(){
cout << "distuctor" << endl;
}
void* operator new(size_t size){
cout << "size = " << size << endl;
cout << "void* operator new(size_t size)" << endl;
void *p = malloc(size);
return p;
}
void operator delete(void* p){
cout << "void operator delete(A* p)" << endl;
free(p);
}
int data;
};
int main() { A *a = new A; delete a; double *p = new double; delete p; return 0; }
把重载函数放到类中,当成成员函数,运行结果就是这样的:
可以看到这样就不会影响到其他类型的new和delete了。
一、new[] 和delete[]重载
new[]和delete[]与new和delete的重载很相似,只不过多了个[]而已,这里直接用局部的,全局的就不再举例了:
class A{ public: A(){ cout << "constuctor" << endl; } ~A(){ cout << "distuctor" << endl; } void* operator new(size_t size){ cout << "size = " << size << endl; cout << "void* operator new(size_t size)" << endl; void *p = malloc(size); return p; } void operator delete(void* p){ cout << "void operator delete(A* p)" << endl; free(p); } void* operator new[](size_t size){ cout << "size = " << size << endl; cout << "void* operator new(size_t size)" << endl; void *p = malloc(size); return p; } void operator delete[](void* p){ cout << "void operator delete(A* p)" << endl; free(p); } int data; }; int main() { A *a = new A[5]; delete []a; double *p = new double[5]; delete []p; return 0; }
运行结果:
可以看到构造了5次,也析构了五次,重点要说的是为什么这里的size = 24, 却不是20呢。这还得从malloc说起:
char *p = (char*)malloc(100); free(p);
这里为p开辟了100字节的空间,然后释放,只通过free(p)系统怎么知道应该释放多少空间呢,其实底层,在为p开辟空间的时候既存储了p,也存储了100这是值,那么在释放的时候就知道对p释放100空间了。new[]这个地方也是一样的,不仅存储了本身开辟的空间,同时也存储了一个指针,所以size = (4 * 5) + 4 = 24字节。
三、new重载的优点
new重载有个特别有优势的地方,我们知道类的数据成员一般都是最先在构造器中初始化的,用new重载之后,可以把数据成员的舒适化放在new中,比构造器中的初始化还早,还是使用上面的例子,这里只单独给出new的重载:
void* operator new(size_t size){ cout << "size = " << size << endl; cout << "void* operator new(size_t size)" << endl; void *p = malloc(size); memset(p, 0, size); ((A*)p)->data = 100; //数据成员的初始化 return p; } int main() { A *a = new A; cout << a->data << endl; delete a; return 0; }
结果是这样的
可以看到数据成员的的确确被初始化了。
四、总结
最后再总结一下重载格式:
void* operator new(size_t size); void* operator new[](size_t size); void operator delete(类名* 对象名); void operator delete[](类名* 对象名);
相关文章推荐
- C/C++语言中const的用法
- 第一张节作业
- C与C++混合是出现连接错误,错误代码:1853
- C++多继承
- 【c++程序】栈的基本用法
- C++第7次作业
- 员工信息管理系统程序
- [C++ 面试基础知识总结] 变量和基本类型
- [C/C++]map自定义比较函数
- C++作业7
- C++中虚函数工作原理和(虚)继承类的内存占用大小计算
- C++:用CreateDirectory创建文件目录
- 【C语言】13-指针和字符串
- C++作业7
- C++ operator关键字(重载操作符)
- 设计模式打怪升级之装饰器模式
- ACM:蓝桥杯:素数距离问题
- c++中函数的介绍(第七章)
- C++实验7——特殊三位数
- C语言求二叉树的高