首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

关于virtual函数,该如何解决

2012-03-28 
关于virtual函数昨天在网上看到一篇关于this指针的文章,结果不但没看懂,还暴露出我对虚函数的疑惑.如下:#i

关于virtual函数
昨天在网上看到一篇关于this指针的文章,结果不但没看懂,还暴露出我对虚函数的疑惑.如下:

#include <iostream>
using   namespace   std;

class   CBase
{
public:
        virtual   void   one()
        {
                cout   < <   "Base   Class\n ";
        }
        CBase()
        {
                this   ->   one();
        }
};

class   CParent   :   public   CBase
{
public:
        CParent()
        {
        }
        virtual   void   one()
        {
                cout   < <   "Parent   Class\n ";
        }

};

CParent   example;

int   main()
{
        return   0;
}
结果输出是:Base   Class  

我的疑问是:程序执行CParent   example;句时,先调用CBase类的构造函数CBase(),那末它就会执行this-> one()句,而因为CParent类中改写了函数函数one(),那么它必调用的是CParnet的虚函数one()吧?所以输出应该是:Parent   Class啊。

/////////////////////////////////////////////////
下面我加一个函数ABC来说明这一点啊。
#include   "stdafx.h "
#include   <vector>
#include   <iostream>

using   namespace   std;

class   CBase
{
public:
        virtual   void   one()
        {
                cout   < <   "Base   Class\n ";
        }
        CBase()
        {
                this-> one();
        }

  void   ABC()
  {
    cout < < "CBase   ABC " < <endl;
    this-> one();
  }
};

class   CParent   :   public   CBase
{
public:
        CParent()
        {
        }
        virtual   void   one()
        {
                cout   < <   "Parent   Class\n ";
        }

};

 

 

int   main(int   argc,   char*   argv[])
{
//   printf( "Hello   World!\n ");
//   CBase   *example;
  CParent   parent   ;
  parent.ABC();
  return   0;
}


//输出结果:
Base   Class
CBase   ABC
Parent   Class

看,调用ABC时输出的就是Parnet   Class,为什么呢?

[解决办法]
楼上的说法似乎也有点道理.关于VTABLE什么时候创建的以前我还真没想过.应该是在构造函数调用之后.
[解决办法]
还有种解释,因为Parent Clas调用构造函数初始化之前先调用Base Class的构造函数,这时Parent Class的对象并没有生成,所以也不存在VTable之类的东西,当然这时只能调用Base的One函数了.


[解决办法]
从对象的角度看:在Base()调用时,基类对象部分构造完成,派生类对象部分尚未构建,此时的对象呈现基类特性。
从虚表的角度看:在Base()调用时,对象的虚表被设为基类的虚表,所以会调用基类的函数;
在CParent()调用后,对象的虚表被reset为派生类的虚表,所以会调用派生类的函数。
[解决办法]
C++ Primer 3rd Edition 17.5.8节

如果在基类的构造函数中调用了一个虚拟函数,而基类和派生类都定义了该函数的实例,
将会怎么样?应该调用哪一个函数实例?如果可以调用虚拟函数的派生类实例,并且它访问
任意的派生类成员,那么调用的结果在逻辑上是未定义的。而程序可能会崩溃。
为了防止这样的事情发生,在基类构造函数中调用的虚拟实例总是在基类中活动的虚拟
实例。实际上,在基类构造函数中,派生类对象只不过是一个基类类型的对象而已。
对于派生类对象,在基类析构函数中也是如此;派生类部分也是未定义的,但是这一
次不是因为它还没有被构造,而是因为它已经被销毁。

热点排行