有关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();
来调用。
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();
来调用。
相关文章推荐
- 有关C++多态的一些测试
- C++---联合体(union)的一些测试
- c++中NEW对象的一些测试
- C++中与指针有关的一些概念
- C++中虚函数和多态的理解和测试程序
- 有关软件测试的一些知识点
- 有关C++中String的一些知识
- 关于C++多态的一些思考(编译期绑定和运行期绑定)
- 有关性能测试的一些脑图(个人收集)
- 有关C/C++的一些基础知识
- c++父类指针强制转为子类指针后的测试(帮助理解指针访问成员的本质)(反多态)
- VS2010 有关测试的一些使用
- 有关C++多态的讨论
- 有关 C++ 内存对齐的测试
- C/C++——一些与输入有关的istream类成员函数
- C/C++一些知识4(重载与多态、虚继承)
- C++学习笔记之:关于类的一些补充测试(new和new[]/private构造/explicit等)
- [C++] 测试硬件popcnt(位1计数)指令与各种软件算法,利用模板实现静态多态优化性能
- 有关C++ POD的一些问题记录
- C++的一些输入有关函数