operator new之被Drived Class继承

来源:互联网 发布:矩阵的点乘 编辑:程序博客网 时间:2024/05/06 12:55

对于operator new操作符有一个容易被忽略的特性:

operator new成员函数会被derived class继承!


定制operator new的一个常见理由就是为了针对所在class的对象分配行为提供最优化,而不是为了其derived class。


下面先讲解下CBase *base = new CBase();的都执行了哪些接口:

step1:

如果定制了CBase::operator new,则调用CBase::operator new

如果没有定制CBase::operator new,则调用系统提供的::operator new

调用形式为:

void* buf = operator new( sizeof(CBase) )

buf用来存储CBase对象

step2:

调用构造函数CBase()在step1申请的buf堆空间上创建CBase对象初始化buf内存。

step3:如果delete base

如果定制了CBase::operator delete,则调用CBase::operator delete

如果没有定制CBase::operator delete,则调用系统标准操作符::operator new

调用形式为:

operator delete( buf );  //buf时step1申请的为了保存CBase对象的堆内存buf


由上可知,如果CBase定制了operator new,权限为public或protected可以被CDerived类继承。

则下面讲解下CDerived *derived = new CDerived();都执行了哪些接口

step1:

调用CBase::operator new

调用形式为:

void* buf = CBase::operator new( sizeof (CDerived) );

buf用来存储CDerived对象

step2:

调用构造函数CDerived()在step1申请的buf堆空间上创建CDerived对象初始化buf内存。

step3:如果delete derived

如果定制了CBase::operator delete,则调用CBase::operator delete

如果没有定制CBase::operator delete,则调用系统标准操作符::operator new

调用形式为:

operator delete( buf );  //buf时step1申请的为了保存CDerived对象的堆内存buf


以上行为都可以通过程序来测试,并验证其正确性,验证代码如下所示:

#include <stdio.h>#include <stdlib.h>#include <string>#include <iostream>class CBase{public:CBase(){}~CBase(){}void setAge(int age){m_age = age;}void* operator new(std::size_t size){if (size == 0){size = 0;}printf("%s:%d:CBase:%s, (new size, class size):(%zu, %zu)\n", __FILE__, __LINE__, __FUNCTION__, size, sizeof(CBase));void* buf = malloc(size);printf("%s:%d:CBase:%s, buf:%p\n", __FILE__, __LINE__, __FUNCTION__, buf);return buf;}void operator delete(void* buf){if (buf == NULL){return;}printf("%s:%d:CBase:%s, buf:%p\n", __FILE__, __LINE__, __FUNCTION__, buf);free(buf);return;}private:int m_age;};class CDerived : public CBase{public:CDerived(){printf("%s:%d:CDerived:%s, sizeof(class CDerived):%zu\n", __FILE__, __LINE__, __FUNCTION__, sizeof(CDerived));}~CDerived(){printf("%s:%d:CDerived:%s\n", __FILE__, __LINE__, __FUNCTION__);}void setWeight(int w){m_weight = w;}private:int m_weight;};int main(){printf("\n===============new CBase()======================\n");CBase* base = new CBase();delete base;printf("================================================\n\n");printf("***************new CDerived()**********************\n");CDerived* derived = new CDerived();delete derived;printf("***************************************************\n\n");return 0;}

测试结果如下所示:


可知new CDerived()时先调用了基类的CBase::operator new操作符,入参为自己的类大小sizeof(CDerived),

然后调用了自己的构造函数CDerived(),在delete derived时调用了自己的析构函数~CDerived(),最后调用了基类的CBase::operator delete来释放保存derived的堆内存buf。


如果CDerived不定制自己的operator new,如果用CBase的operator new来分配保存自己对象derived的堆内存,在delete时还是调用CBase的operator new来释放保存自己对象derived的堆内存。

这就是CBase定制的operator new只是特定大小sizeof(CBase)的对象申请空间,如果CBase的operator new被一直继承下去,有可能会被用来为CDerived对象分配对象内存。

这是不符合operator new刚开始的设计目的的。


可以使用“内存申请错误”的调用行为改用标准的操作符::operator new,修改后的代码如下所示:

#include <stdio.h>#include <stdlib.h>#include <string>#include <iostream>class CBase{public:CBase(){}~CBase(){}void setAge(int age){m_age = age;}void* operator new(std::size_t size){<span style="color:#ff0000;">if (size != sizeof(CBase)){void *buf = ::operator new(size);printf("%s:%d:CBase:%s, buf:%p\n", __FILE__, __LINE__, __FUNCTION__, buf);return buf;}</span>if (size == 0){size = 1;}printf("%s:%d:CBase:%s, (new size, class size):(%zu, %zu)\n", __FILE__, __LINE__, __FUNCTION__, size, sizeof(CBase));void* buf = malloc(size);printf("%s:%d:CBase:%s, buf:%p\n", __FILE__, __LINE__, __FUNCTION__, buf);return buf;}void operator delete(void* buf){if (buf == NULL){return;}printf("%s:%d:CBase:%s, buf:%p\n", __FILE__, __LINE__, __FUNCTION__, buf);free(buf);return;}private:int m_age;};class CDerived : public CBase{public:CDerived(){printf("%s:%d:CDerived:%s, sizeof(class CDerived):%zu\n", __FILE__, __LINE__, __FUNCTION__, sizeof(CDerived));}~CDerived(){printf("%s:%d:CDerived:%s\n", __FILE__, __LINE__, __FUNCTION__);}void setWeight(int w){m_weight = w;}private:int m_weight;};int main(){printf("\n===============new CBase()======================\n");CBase* base = new CBase();delete base;printf("================================================\n\n");printf("***************new CDerived()**********************\n");CDerived* derived = new CDerived();delete derived;printf("***************************************************\n\n");return 0;}

测试结果如下所示:



(完)

0 0