您的位置:首页 > 编程语言 > C语言/C++

有关C++多态的一些测试

2006-03-06 11:19 323 查看
由于一直对C++的多态心存疑虑,今天想彻底弄明明一点,所以做了一些测试,将结果拿出来同大家一起分享。测试在VC6下进行,以下是测试时用的继承关系以及虚函数的重写情况(不能贴图,可惜,可能贴源码了):

class BaseA
{
public:
BaseA();
~BaseA();

virtual void printme();
virtual void printme1();
};
class BaseB : public BaseA
{
public:
BaseB();
~BaseB();

virtual void printme();
};
class BaseC :public BaseA
{
public:
BaseC();
~BaseC();
virtual void printme();
};
class BaseD:public BaseB,BaseC
{
public:
BaseD();
~BaseD();

virtual void printme();
virtual void dxx();
};
class BaseF : public BaseD
{
public:
BaseF();
~BaseF();
virtual void printme1();
};

1、如果继承体系里没有C类,即粗线的单重继承,则以下测试代码是可行的(先从类实例地址的开始处取得指向vtable的指针,vtable是一个指针数组,每一个值都指向一个虚函数,因此可以顺序递增去执行每一个方法):
void *getp (void* p)
{
return (void*)*(unsigned long*)p;
}
fun getfun (BaseD* obj, unsigned long off)
{
void *vptr = getp(obj);
unsigned char *p = (unsigned char *)vptr;
p += sizeof(void*) * off;
return (fun)getp(p);
}
void testv()
{
BaseF *p = new BaseF;
fun f = getfun(p, 0);
(*f)();
f = getfun(p, 1);
(*f)();
}
输出为:
is BaseD here
is BaseF here 1
虚函数表图如下:
---------图没贴上来-------------------

b1
BaseD
BaseB
BaseA
_vfptr
[0] BaseD::printme(void)
[1] BaseF::printme1(void)

其中:BaseF *b1 = new BaseF;

此时,如果你想直接调用A的printme1方法,可用如下方法:
b1->BaseA::printme();

2、如果在继承层次中加入C类,则有了多重继承,以下将是b1的虚函数图:
---------图没贴上来-------------------

b1 0x02193a10
BaseD
BaseB
BaseA
_vfptr 0x004380fc const BaseF::’vftable’{for’baseB’}
[0] 0x00401154 BaseD::printme(void)
[1] 0x004010af BaseF::printme1(void)
BaseC
BaseA
_vfptr 0x004380f0 const BaseF::’vftable’{for’baseC’}
[0] 0x00401172 [thunk]:BaseD::printme’adjustor{4}’(void)
[1] 0x0040116D[thunk]:BaseF::printme1’adjustor{4}’(void)

(此时用上面的代码手动调用虚函数将会出错,具体内存是如何分布的,我没有去深入研究了)

可以看到,每一个继承分支都有不同的虚函数表,此时,如果你想用:
b1->BaseA::printme();
来调用A的方法,编译将通不过,告诉你会有歧义。而必须用:
((BaseC *)b1)->BaseA::printme();
来调用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: