Boolan C++ 第五周 new和delete

2017-02-24  本文已影响0人  wild_horse

一、new和delete

new和delete 是C++ 动态分配和释放内存的重要方式。当new一个对象时

string *sp=new string();

先分配足够大的内存空间,在调用相应的构造函数来构造对象,最后返回指向对象的指针。
当delete 一个对象时,先调用析构函数,再释放所占的内存空间

delete sp;

若程序想要自行控制内存分配可以定义自己的operator new和operator delete 函数。

//自定义operator new和operator delete
void *operator new(size_t size)
{
  if(void* mem=malloc(size))
    return mem;
  else
    throw bad_alloc();
}

void operator delete(void* mem) 
{
  free(mem);
}

重新定义operator new和operator delete 函数,下次使用new和delete ,编译器会首先寻找类内是否有重新定义的operator new和operator delete 函数,之后再查找全局作用域是否有重新定义的operator new和operator delete 函数,接着再调用标准库的operator new和operator delete 函数。
当类内自定义operator new和operator delete 函数时,默认为static函数,因为operator new发生在对象构造前,而operator delete发生在对象销毁后,不属于对象的生命周期内。
类型size_t 是标准库定义的一种类型,不必传入实参,编译器会为我们计算需要的内存大小,并自行传入size_t形参。
而在实现上C++在底层用的是C语言的malloc和free函数.

二、对象模型的this指针

class Fruit
{
   int no;
   double weight;
   char key;
public:
   void print() {   }
   virtual void process(){   }
};

class Apple: public Fruit
{
   int size;
   char type;
public:
   void save() {   }
   virtual void process(){   }
};

对于Apple类,拥有Fruit类的全部数据,我们可以用Apple对象对Fruit对象赋值,反之则不行。

Fruit f;
Apple a;
f=a;//编译通过
a=f;//不行,发生错误

从数据内存来看,Apple对象赋值给Fruit对象,相当于发生了数据阶段,把完整的Fruit类的数据赋给了f,这是成立的;若反过来,那么Apple类仅有Fruit类部分数据被覆盖,破坏数据的完整性,可能带来隐患,所以这是不行的。

Fruit* pf=new Apple;

用基类指针指向派生类对象,可以直接用指针操作,实际上控制的数据范围只在Apple对象的Fruit部分,当时带虚函数的类继承后,每个对象在起始位置都会存储一个指向虚函数表的指针,这样就实现了虚函数的挑战!也就是实现类的多态,利用的是派生类都含有基类完整的数据,在一定程度上忽略派生类的区别。
那么关键就是虚函数表真正指向的函数了。用来区分就是实际的this指针,也就是实际的内存是由什么类型所构建的。

事例

在这个事例中,用派生类对象调用基类方法,传入的this指针是指向派生类对象的。

CDocument::OnFileOpen(&myDoc);

所以当运行到Serialize()函数是,编译器查看的虚函数表是属于派生类的,跳转到派生类的Serialize函数,最终调用了派生类对象的自定义部分。

上一篇下一篇

猜你喜欢

热点阅读