虚表
出自:http://blog.csdn.net/haoel/article/details/1948051 作者:陈皓
对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。这里我们着重看一下这张虚函数表。C++的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。 这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
class
Base {
public :
virtual
void
f() { cout << "Base::f"
<< endl; }
virtual
void
g() { cout << "Base::g"
<< endl; }
virtual
void
h() { cout << "Base::h"
<< endl; }
};
typedef
void (*Fun)( void );
Base b;
Fun pFun = NULL;
cout << "虚函数表地址:"
<< ( int *)(&b) << endl;
cout << "虚函数表 — 第一个函数地址:"
<< ( int *)*( int *)(&b) << endl;
// Invoke the first virtual function
pFun = (Fun)*(( int *)*( int *)(&b));
pFun();
(Fun)*(( int *)*( int *)(&b)+0); // Base::f()
(Fun)*(( int *)*( int *)(&b)+1); // Base::g()
(Fun)*(( int *)*( int *)(&b)+2); // Base::h()
|
一般继承(无虚函数覆盖)
对于实例:Derive d; 的虚函数表如下
1)虚函数按照其声明顺序放于表中。
2)父类的虚函数在子类的虚函数前面。
一般继承(有虚函数覆盖)
对于派生类的实例,其虚函数表为
1)覆盖的f()函数被放到了虚表中原来父类虚函数的位置。
2)没有被覆盖的函数依旧。
多重继承(无虚函数覆盖)
对于子类实例中的虚函数表为
1) 每个父类都有自己的虚表。
2) 子类的成员函数被放到了第一个父类的表中。(所谓的第一个父类是按照声明顺序来判断的)
多重继承(有虚函数覆盖)
子类虚函数结构
1
2
3
4
5
6
7
8
9
10
11
|
Derive d;
Base1 *b1 = &d;
Base2 *b2 = &d;
Base3 *b3 = &d;
b1->f(); //Derive::f()
b2->f(); //Derive::f()
b3->f(); //Derive::f()
b1->g(); //Base1::g()
b2->g(); //Base2::g()
b3->g(); //Base3::g()
|
虚函数的调用
#include <iostream>
using namespace std;
calss A{
virtual void g()
{
cout << "A::g" << endl;
}
private:
virtual void f()
{
cout << "A::f" << endl;
}
};
class B : public A {
void g()
{
cout << "B::g" << endl;
}
virtual void h()
{
cout << "B::h" << endl;
}
};
typedef void( *Fun )( void );
int main()
{
B b;
Fun pFun;
for(int i = 0 ; i < 3; i++)
{
pFun = ( Fun )*( ( int* ) * ( int* )( &b ) + i ); //因为&b表示 A *指针,我们想取出虚表的第一个指针地址(四字节)(指向虚函数的一个地址值),
using namespace std;
calss A{
virtual void g()
{
cout << "A::g" << endl;
}
private:
virtual void f()
{
cout << "A::f" << endl;
}
};
class B : public A {
void g()
{
cout << "B::g" << endl;
}
virtual void h()
{
cout << "B::h" << endl;
}
};
typedef void( *Fun )( void );
int main()
{
B b;
Fun pFun;
for(int i = 0 ; i < 3; i++)
{
pFun = ( Fun )*( ( int* ) * ( int* )( &b ) + i ); //因为&b表示 A *指针,我们想取出虚表的第一个指针地址(四字节)(指向虚函数的一个地址值),
// 所以要先转换为 int * ,
//又因为对其*后,得到的是函数地址值,不知道其指针类型,所以先转换为基本指针类型,再转换为pFun型。
pFun();
}
}
输出结果:
B::g
A::f
B::h
pFun();
}
}
输出结果:
B::g
A::f
B::h