题目要求

为上周题目中的 Fruit和Apple 添加 构造函数与 析构函数, 并在构造函数与析构函数中打印控制台信息,观察构造和析枸调用过程。然后为Apple类重载::operator new和 ::operator delete,在控制台打印信息,并观察调用结果。
因为题目比较简单,不多说直接上代码

#include<iostream>
using namespace std;
class Fruit 
{
    int no;
    double weight;
    char key;
public:
    Fruit()
    {
        cout << "creat Fruit" << endl;
    }
    virtual~Fruit()
    {
        cout << "delete Fruit" << endl;
    }
    void print() {  }
    virtual void process() {  }
};
class Apple : public Fruit 
{
    int size;
    char type;
public:
    Apple()
    {
        cout << "creat Apple" << endl;
    }
    void* operator new(size_t siz)
    {
        Apple* p = (Apple*)malloc(siz);
        cout << "new object" << endl;
        return p;
    }
    void* operator new[](size_t siz)
    {
        Apple* p = (Apple*)malloc(siz);
        cout << "new OBJECT" << endl;
        return p;
    }
    void operator delete (void* p, size_t siz)
    {
        cout << "delete object" << endl;
        cout << "size=" << siz << endl;
        free(p);
    }
    void operator delete[](void* p, size_t siz)
    {
        cout << "delete OBJECT" << endl;
        cout << "size=" << siz << endl;
        free(p);
    }
    ~Apple()
    {
        cout << "delete Apple" << endl;
    }
    void save() {   }
    virtual void process() {   }
};
int main()
{
    /*Fruit s1;
    Apple a1;
    Apple* a1=new Apple;
    delete a1;
    Apple* a2 = new Apple[5];
    delete[] a2;
    Fruit *s1 = new Apple;
    delete s1;*/

    return 0;
}

当使用stack内存创建对象时,

Fruit s1;
Apple a1;

对构造函数和析构函数执行结果如图:

clipboard.png

可见对象是根据其在代码中的声明顺序创建的。并且在创建子类对象时,先调用父类的构造函数,再调用子类的构造函数,在删除对象时,先调用子类的析构函数,再调用父类的析构函数。当声明顺序为

Apple a1;
Fruit s1;

运行结果如下:

clipboard.png

可以看出,对象的存储在栈中遵循其先进后出原则,最先定义的最后被析构。
随后我们对new 和delete 操作符进行重载

Apple* a1=new Apple;
delete a1;

运行结果如下:

clipboard.png

可见对象的构造和析构遵循如下顺序:
构造时,先申请内存 再调用构造函数
析构时,先调用析构函数,再删除内存。
如果对象有父类,则构造函数和析构函数的调用顺序遵循上面的结论。
operater new[]和operator delete[]

Apple* a2 = new Apple[5];
delete[] a2;

对构造函数和析构函数的调用方式基本和上述相同唯一不同的是内存的申请和释放只有一次,随后多次执行构造和析构。
运行结果如下:

clipboard.png
最后再测试一下父类指针管理的对象:

Fruit *s1 = new Apple;
delete s1;

运行结果:

clipboard.png

由于在声明时,基类的析构函数已经声明为虚函数,因此在析构时对对象的动态绑定,虽然传入的是父类的指针,但是在实际调用的是子类的析构函数。


风斩冰华
27 声望12 粉丝

coding