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

由于一直对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();

来调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值