在C++Builder中,VCL风格对象的运行时类型,是派生类的类型,并在调用基类构造函数期间不变。因此,如果基类构造函数调用一个虚拟的方法,当派生类重载它时,派生类的方法将被调用,基类的不被调用。如果这个虚拟方法依赖于派生类构造函数体或初始化列表中的任何东西,方法仍在派生类构造函数之前被调用。例如CreateParams是一个虚拟的成员函数,它在TWinControl的构造函数中间接地被调用。如果从TWincontrol派生一个类并重载CreateParams,以便它依赖于构造函数中的任何东西,在CreateParams被调用以后,这些代码才被处理。这种状况适用于一个基类的任何派生类。如C从B派生,B从A派生。创建C的一个实例,若B重载A类中的方法,但C没有,A也将调用B重载的方法。
注意:要记住象CreateParams一样的虚拟方法不是被构造显式调用的,而是间接被调用的。
例子:调用虚拟方法
下例比较重载了虚拟方法的标准C++和VCL风格的类。这个例子说明来自基类构造函数的那些虚拟的方法的调用怎么处理这两种情况。MyBase和MyDerived是标准的C++类。MyVCLBase和MyVCLDerived是从TOBject派生而来的VCL风格类。虚拟方法test()在派生类中被重载,但是仅在基类构造函数中被调用,派生类构造函数不调用。
上面这段话是从书上抄来的,所以很拗口。代码如下:
注意:要记住象CreateParams一样的虚拟方法不是被构造显式调用的,而是间接被调用的。
例子:调用虚拟方法
下例比较重载了虚拟方法的标准C++和VCL风格的类。这个例子说明来自基类构造函数的那些虚拟的方法的调用怎么处理这两种情况。MyBase和MyDerived是标准的C++类。MyVCLBase和MyVCLDerived是从TOBject派生而来的VCL风格类。虚拟方法test()在派生类中被重载,但是仅在基类构造函数中被调用,派生类构造函数不调用。
上面这段话是从书上抄来的,所以很拗口。代码如下:
//标准的C++风格
class MyBase
{
public:
MyBase()
{
test();
}
virtual void test()
{
ShowMessage( "标准C++基类函数" );
}
};
class MyDerivaed:public MyBase
{
public:
virtual void test()
{
ShowMessage("标准C++子类函数" );
}
};
//VCL风格的类
class MyVCLBase:public TObject
{
public :
__fastcall MyVCLBase()
{
test();
}
virtual void __fastcall test()
{
ShowMessage( "VCL++ 父类中的函数" );
}
};
class MyVCLDerived:public MyVCLBase
{
public:
int i;
MyVCLDerived()
{
i=2;
}
virtual void _fastcall test()
{
ShowMessage( "VCL C++ 这是子类中的函数" +AnsiString(i));
}
};
void __fastcall TForm1::Button7Click(TObject *Sender)
{
MyDerivaed base;//产生对话框1
MyVCLDerived *pdv = new MyVCLDerived;//调用子类重载函数,产生对话框2
}
运行结果:
对话框1显示 "标准C++基类函数"
对话框2显示 "VCL C++ 这是子类中的函数0“.
对话框2说明了在创建子类对象时,先调用基类构造函数,再调用自身的构造函数。这一点与标准C++是一样的。但不同的时,当MyVCLDerived的基类构造函数调虚函数test时,调用的不是基类中的test函数(在被重载的前提下),是子类MyVCLDerived中的test函数。还有一点值得注意的是,虽然子类的重载的test函数中用到了子类成员变量i,结果显示:这个变量i在子类构造函数执行前被调了,所以i的值为0。