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