1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include "stdio.h"
class A
{
public :
virtual void Test()
{
printf( "A test\n" );
}
};
class B: public A
{
public :
void func()
{
Test();
}
virtual void Test()
{
printf( "B test\n" );
}
};
class C: public B
{
public :
virtual void Test()
{
printf( "C test\n" );
}
};
void main()
{
C c;
((B *)(&c))->func();
((B)c).func();
}
|
该程序的执行结果
C test
B test
解释一: (( B *)(& c ))-> func (); 是多态行为
(( B ) c ). func (); 不是多态行为。 参见 effective c++ P170 “令客户通过public non-virtual成员函数间接调用private virtual函数,称之为non-virtual interface(NVI)手法。”
解释二:
相信:((B)c).func();这句大家都懂,无非就是静态调用嘛(要启用动态调用需要由基类的指针或引用来发起,而且调用的函数得是虚函数); 既然调用前c对象被强制转换为B类型,那么调用的自然是B类中的对应函数了。 对于:((B*)(&c))->func(); 首先,func函数在类B中并不是虚函数,所以语句中调用的func是B类中的函数;其次,在func中调用了虚函数,也就是此时发生了动态调用(调用func是是静态的),相当于在B类的func中发生了如下调用:((B *)(&c))->Test();满足动态调用的要求,调用的是C类的test函数。
解释三: 这是 向上造型 的两类,第一类是指针和引用,不产生切割,如本题的 ((B *)(&c))->func();;第二类是直接转换对象类型,会产生切割,如本题的((B)c).func();
产生切割时,把子类多余的不部分去除了,并把虚表指针vptr重新指向父类的虚函数表。因为vptr变了,所以输出B test
解释四: C c;声明了一个C类的对象c。
((B *)(&c))->func(); 用B类的指针指向C类对象,此时func()是B类中的,由于Test()声明为虚函数,所以根据实际对象找到虚函数表,得到C中的虚函数输出"Ctest".
((B)c).func();
将c转化为B 类,(相当于把一个范围大的强制转化为范围小的如double 类型转化为int
),此时c不再是C类,而就是一个B 类的对象。
|