全局变量,继承,虚函数,构造函数和析构函数的调用过程

来源:互联网 发布:用js表示阶层1加阶层2 编辑:程序博客网 时间:2024/04/30 11:42


/*全局变量,继承,虚函数,构造函数和析构函数的调用过程。。。///百度里发现的一个好贴,不敢独自享用,分享一下。。。*/

#include <stdio.h>
class Value
{
public:
 Value(int  nVal)
 {
  m_nVal = nVal;
  printf("Call Value::Value(int nValue)\n");
 }
 ~Value()
 {
  printf("Call Value::~Value()\n");
 }
 Value& operator=(int nVal)
 {
  m_nVal = nVal;
  printf("Call Value::operator=\n");
  return *this;
 }
 void Dump()
 {
  printf("Value::m_nVal=%d\n",m_nVal);
 }
protected:
 int m_nVal;
};

class Base
{
public:
 Base(){  Init(); }
 virtual ~Base() {  Release();  }
 virtual void Init() { printf("Call Base::Init()\n"); }
 virtual void Release(){ printf("Call Base::Release()\n"); }
 virtual void Dump(){  printf("Call   Base::Dump()\n"); }
};


class Derive:public Base
{
public:
 Derive(){printf("Call Derive::Derive()\n");}
 ~Derive(){printf("Call   Derive::~Derive()\n");}
 virtual void Init(){m_Val=2;printf("Call Derive::Init()\n");}
 virtual void Release(){printf("Call Derive::Release()\n");}
 virtual void Dump(){m_Val.Dump();}
protected:
 static Value m_Val;
};


void DestroyObj(Base* pOb)
{
 pOb->Dump();
 delete pOb;
}

Value Derive::m_Val=0;

int main()
{
 Derive *pOb = new Derive;
 DestroyObj(pOb);
 
 return 0;
}
/*
这道题考察了好几个方面:
1.全局变量的生命周期
2.类中静态成员的生命周期
3.构造函数和析构函数中对虚函数的调用
4.虚析构函数

把这几方面搞清楚了这道题就很容易了

全局变量是需要在进入main()函数前即初始化的,所以在一个程序中一个全局变量的构造函数应该是第一个被调用的,比main()函数都要早。
同时他又必须在main()函数返回后才被销毁,所以他的析构函数是最后才被调用。
而一个类中的静态成员可以看成是一个有效范围受了限制的全局变量。他的生命周期与一个全局变量相同,但他只能在这个类的范围内使用。
然后是构造函数和析构函数。在构造函数和析构函数中调用虚函数的话会破坏虚函数的虚拟性(多态性),而只能当作普通函数调用
(在这两个函数执行时类的对象有可能是不完整的,无法确定继承的调用链),所以通常应尽量避免在构造函数和析构函数中调用虚函数。
一个类如果是作为基类让其他类来继承的,则他需要把析构函数声明为虚函数,
这样在delete一个派生类的对象时才能由多态性调用该派生类所对应的析构函数;否则调用的都是基函数的析构函数。

之后再看题目就很清楚了。Derive类中有一个静态成员,则该成员的构造函数应当最先被调用。之后进入main()函数,
new了一个Derive对象,则应顺次调用基类和派生类的构造函数,但基类的构造函数中调用了一个虚函数,这个函数只能被当成普通函数对待,
不具备多态性,所以实际调用的仍是基类的Init()函数而不是派生类的。后面继续调用派生类的构造函数。然后是DestroyObj()函数,
由多态性pOb->Dump()调用的是派生类的Dump()函数,所以输出了m_nVal的值。再然后是销毁对象,基类析构函数声明为虚函数,

  所以这里应依次调用派生类和基类的的析构函数。先是输出Derive::~Derive(),然后,基类的析构函数中又调用了一个虚函数,
  将它作为普通函数调用。。。main()函数终于执行完了,退出后销毁类Derive中的静态成员,调用他的析构函数。

另:如果把Value Derive::m_Val=0;语句屏蔽掉,相当于没有为他初始化,即没有分配空间,编译器会当成他是一个在其他文件中定义的变量
,所以编译时应该没问题,但是链接时会报错。
*/