C++虚函数机制

      典型的编译器对每个包含虚函数的类创建一个表(称为VTABLE).
      在VTABLE中,编译器放置特定类型的虚函数地址。在每一个带有虚函数的类中,编译器秘密地放置一个指针,称为vpointer(缩写为VPTR),指向这个VTABLE。当通过基类指针做虚函数调用时(也就是做多态调用时),编译器静态地插入能取得这个VPTR并在VTABLE表中查找函数地址的代码,这样就能调用正确的函数并引起晚捆绑的发生。
      为每个类设置VTABLE,初始化VPTR,为虚函数调用插入代码,所有这些都是自动发生的,所以不必担心,利用虚函数,即使在编译器还不知道这个对象的特定类型的情况下,也能调用这个对象中的正确的函数。

      VPTR的状态是由被最后调用的构造函数确定的。这也是为什么构造函数调用是按照从基类到最晚派生类的顺序的一个理由。

      虚函数不是相当高效的。
虚函数和构造函数:
             当创建一个包含虚函数的对象时,必须初始化它的VPTR以指向相应的VTABLE。这必须在对虚函数进行任何调用之前完成。
             设置VPTR是构造函数的工作。编译器在构造函数的开头部分秘密地插入能初始化VPTR的代码。
             有些构造函数看起来很小,所以我们可能会将它们设置为内联函数,但注意,它们实际上可能并不小,因为编译器隐藏了一些动作。如果做大量的内联构造函数,代码长度会增长,在速度上没有任何好处。

编译器的隐藏动作:
             编译器会插入一些隐藏代码到我们的构造函数中。这些隐藏的代码不仅必须初始化VPTR,而且还必须检查this的值(以免operator new 返回零)和调用基类的构造函数。

      对于在构造函数中 调用一个虚函数的情况,被调用的只是这个函数的本地版本,也就是说,虚机制在构造函数中不能工作。
      在析构函数中,只有成员函数的“本地”版本被调用,虚机制被忽略。假设在析构函数中使用虚机制,那么因为析构函数从“外层”被调用,所以实际上被调用的函数可能操作在已被删除的对象上了。因此编译器决定在编译时只调用这个函数的“本地”版本。对于构造函数也是如此。但是在构造函数中是因为信息还不可用,而在析构函数中是因为信息(也就是VPTR)虽然存在,但是不可靠。

构造函数是不能为虚函数的。但是析构函数能够而且常常必须是虚的。
       每一个析构函数知道它所在的类从哪一个类派生出来,但是不知道从它派生出哪些类。
       不把析构函数设置为虚函数是一个隐匿的错误,如果它不是虚的,用一个基类型指针指向一个派生类的对象,当delete这个指针时,将只会调用基类的析构函数,而不会调用派生类的析构函数,这可能会引起内存泄露。

纯虚析构函数的纯虚性的唯一效果是阻止基类的实例化。如果有其他的纯虚函数,则它们会阻止基类的实例化,但是如果没有,则可以用纯虚析构函数来完成这个任务。

你可能感兴趣的:(C++,c,工作,C#)