C++:87---类继承(虚函数表:Virtual Table)
原创
©著作权归作者所有:来自51CTO博客作者董哥的黑板报的原创作品,请联系作者获取转载授权,否则将追究法律责任
一、虚函数表解析
- 虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。在这个表中,主要是一个类的虚函数的地址表,这张表解决了继承、覆盖(重写)的问题
- 在有虚函数的类中,虚函数表被分配在类实例的内存中,所以当用父类的指针来操作一个子类的时候,这张虚函数表就显得非常重要了
- 虚函数表类似于一张地图,指明了实际所应该调用的函数
- C++标准说明书中说到,编译器必须保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。这意味着通过对象实例的地址得到这张虚函数表,之后就可以遍历其中的函数指针,并调用相应的函数
- 关于虚函数表的设计还可以参阅《C++对象模型》
二、无继承下的虚函数表解析
#include <iostream>
using namespace std;
class Base
{
public:
virtual void func1() { cout << "Base::fun1" << endl;}
virtual void func2() { cout << "Base::fun2" << endl;}
virtual void func3() { cout << "Base::fun3" << endl;}
private:
int num1;
int num2;
};
typedef void (*Fun)();
int main()
{
Base b;
Fun pFun;
pFun = (Fun)*((int*)*(int*)(&b) + 0);
pFun();
pFun = (Fun)*((int*)*(int*)(&b) + 1);
pFun();
pFun = (Fun)*((int*)*(int*)(&b) + 2);
pFun();
return 0;
}
- 上面的代码可能编译不通过,由于编译器的原因
- 转换解析:
(Fun)*((int*)*(int*)(&b) + 0);
(int*)(&b);
(int*)(&b) + 0;
*(int*)(&b) + 0;
(int*)*(int*)(&b) + 0;
*((int*)*(int*)(&b) + 0);
(Fun)*((int*)*(int*)(&b) + 0);
- vfptr:虚函数表指针
- num1、num2:数据成员
三、单一继承(无重写(覆盖))
- 下面是单一继承中虚函数表的设计,并且派生类没有重写(覆盖)基类的虚函数
#include <iostream>
using namespace std;
class Base1
{
public:
Base1(int num) : num_1(num) { }
virtual void foo1() { cout << "Base1::foo1" << endl;}
virtual void foo2() { cout << "Base1::foo2" << endl;}
virtual void foo3() { cout << "Base1::foo3" << endl;}
private:
int num_1;
};
class Derived1 : public Base1
{
public:
Derived1(int num) : Base1(num) { }
virtual void faa1() { cout << "Derived1::faa1" << endl;}
virtual void faa2() { cout << "Derived1::faa2" << endl;}
};
- Derived1继承自Base1类,其虚函数表如下所示:
- 前面3个为基类Base1的虚函数
- 后面两个为Derived1自己的虚函数
四、单一继承(有重写(覆盖))
- 下面是单一继承中虚函数表的设计,并且派生类重写(覆盖)了基类的虚函数
#include <iostream>
using namespace std;
class Base1
{
public:
Base1(int num) : num_1(num) { }
virtual void foo1() { cout << "Base1::foo1" << endl;}
virtual void foo2() { cout << "Base1::foo2" << endl;}
virtual void foo3() { cout << "Base1::foo3" << endl;}
private:
int num_1;
};
class Derived2 : public Base1
{
public:
Derived2(int num) : Base1(num) { }
virtual void foo2() { cout << "Derived2::foo2" << endl;}
virtual void fbb2() { cout << "Derived2::fbb2" << endl;}
virtual void fbb3() { cout << "Derived2::fbb3" << endl;}
};
- Derived2继承自Base1类,其虚函数表如下所示:
- 第1个、第3个为基类Base1的虚函数
- 第2个本来是基类Base1的虚函数,由于其重写了基类的foo2()虚函数,因此需要更换为自己的虚函数指针
- 后面两个为Derived2自己的虚函数
- 当我们通过基类指针指向于派生类时,调用其中的函数就是根据这张虚函数表来调用的
Derived2 *p = new Base1(1);
p->foo2();
五、多重继承(无重写(覆盖))
- 下面是多重承中虚函数表的设计,并且派生类没有重写(覆盖)基类的虚函数
#include <iostream>
using namespace std;
class Base1
{
public:
Base1(int num) : num_1(num) { }
virtual void foo1() { cout << "Base1::foo1" << endl;}
virtual void foo2() { cout << "Base1::foo2" << endl;}
virtual void foo3() { cout << "Base1::foo3" << endl;}
private:
int num_1;
};
class Base2
{
public:
Base2(int num) : num_2(num) { }
virtual void foo1() { cout << "Base2::foo1" << endl;}
virtual void foo2() { cout << "Base2::foo2" << endl;}
virtual void foo3() { cout << "Base2::foo3" << endl;}
private:
int num_2;
};
class Base3
{
public:
Base3(int num) : num_3(num) { }
virtual void foo1() { cout << "Base3::foo1" << endl;}
virtual void foo2() { cout << "Base3::foo2" << endl;}
virtual void foo3() { cout << "Base3::foo3" << endl;}
private:
int num_3;
};
class Derived3 : public Base1, public Base2, public Base3
{
public:
Derived3(int num1, int num2, int num3) : Base1(num1), Base2(num2), Base3(num3) { }
virtual void fcc1() { cout << "Derived3::fcc1" << endl;}
virtual void fcc2() { cout << "Derived3::fcc2" << endl;}
};
- Derived2继承自Base1、Base2、Base3类,其虚函数表如下所示:
- Derived继承3个基类,其中为每一个基类都涉及了一张虚函数表
- 为每一个基类都涉及了一张虚函数表的目的是:为了解决不同的父类类型的指针指向同一个子类实例,而能够调用实际的函数。例如:
Base2 *pBase2 = new Derived3();
pBase2->foo2();
六、多重继承(有重写(覆盖))
- 下面是多重承中虚函数表的设计,并且派生类重写(覆盖)了基类的虚函数
#include <iostream>
using namespace std;
class Base1
{
public:
Base1(int num) : num_1(num) { }
virtual void foo1() { cout << "Base1::foo1" << endl;}
virtual void foo2() { cout << "Base1::foo2" << endl;}
virtual void foo3() { cout << "Base1::foo3" << endl;}
private:
int num_1;
};
class Base2
{
public:
Base2(int num) : num_2(num) { }
virtual void foo1() { cout << "Base2::foo1" << endl;}
virtual void foo2() { cout << "Base2::foo2" << endl;}
virtual void foo3() { cout << "Base2::foo3" << endl;}
private:
int num_2;
};
class Base3
{
public:
Base3(int num) : num_3(num) { }
virtual void foo1() { cout << "Base3::foo1" << endl;}
virtual void foo2() { cout << "Base3::foo2" << endl;}
virtual void foo3() { cout << "Base3::foo3" << endl;}
private:
int num_3;
};
class Derived4 : public Base1, public Base2, public Base3
{
public:
Derived4(int num1, int num2, int num3) : Base1(num1), Base2(num2), Base3(num3) { }
virtual void foo1() { cout << "Derived4::foo1" << endl;}
virtual void fdd() { cout << "Derived4::fdd" << endl;}
};
- Derived2继承自Base1、Base2、Base3类,其虚函数表如下所示:
- Derived继承3个基类,其中为每一个基类都涉及了一张虚函数表
- 并且将重写的虚函数替换为自己的虚函数指针