有那么多讲C++多态的文章,但是却没有一个能真正看明白的,神秘的多态机制,究竟是如何实现的,看黄老师来如何教你?
我们先看两个类:
class A
{
public:
A() { a = 111; }
virtual void fun1()
{
cout << " A::fun1" << endl;
}
virtual void fun2()
{
cout << " A::fun2" << endl;
}
int a;
};
class B:public A
{
public:
B() { b = 222; }
virtual void fun2()
{
cout << " B::fun2" << endl;
}
virtual void fun3()
{
cout << " B::fun3" << endl;
}
int b;
};
简单介绍下规则:
1. 首先对于含有virtual关键字的类(A 或 B), 该类的所有对象的内存的前四个字节(32位系统下),存放一个内存地址,根据这个地址可以访问到该类的虚函数表内存(表中的每一项都是一个函数地址 ,所以A中有两项 fun1 ,fun2 )。
2. 派生类(自己有virtual 或者 基类中有 virtual 关键字), 根据1规则,同样有一张虚函数表内存 ( 表中的每一项都是一个函数地址,按道理来说应该是四项 A类中的 fun1 ,fun2 , B类中的fun2, fun3 ,这个时候需要注意,派生类的fun2 会覆盖基类的fun2, 所以只有三项)
用图解释如下:
作为一个最喜欢扒内存的黄老师而言,利用代码测试其内存结构,便能一清二楚!!!
#include <iostream>
using namespace std;
typedef void(*PFUN)();
class A
{
public:
A() { a = 111; }
virtual void fun1()
{
cout << " A::fun1" << endl;
}
virtual void fun2()
{
cout << " A::fun2" << endl;
}
int a;
};
class B:public A
{
public:
B() { b = 222; }
virtual void fun2()
{
cout << " B::fun2" << endl;
}
virtual void fun3()
{
cout << " B::fun3" << endl;
}
int b;
};
int main()
{
//根据多态我们知道,肯定调用的是B的fun2
//A *p = new B;
//p->fun2();
cout << "---------------------------A的虚函数表--------------------------" << endl;
{
cout << "A类的大小 " << sizeof(A) << endl;
//测试A的虚函数表
A a;
int *pA = (int *)&a;//a内存空间的首地址
cout << "4字节vtable指针"<<endl;
int * vptr = (int *)(*pA); // a内存空间的 前4个字节 存放的内容是 虚函数表的地址
PFUN afun1 = (PFUN)vptr[0];
afun1();
PFUN afun2 = (PFUN)vptr[1];
afun2();
cout <<"4字节a成员"<< *(pA + 1)<<endl; //成员变量a的内容
}
cout << "---------------------------B的虚函数表--------------------------" << endl;
{
cout << "B类的大小 " << sizeof(B) << endl;
//测试B的虚函数表
B b;
int *pB = (int *)&b;//b内存空间的首地址
cout << "4字节vtable指针" << endl; //成员变量a的内容
int * vptr = (int *)(*pB); // b内存空间的 前4个字节 存放的内容是 虚函数表的地址
PFUN bfun1 = (PFUN)vptr[0];
bfun1();
PFUN bfun2 = (PFUN)vptr[1];
bfun2();
PFUN bfun3 = (PFUN)vptr[2];
bfun3();
cout << "4字节a成员" << *(pB + 1) << endl; //成员变量a的内容
cout << "4字节b成员" << *(pB + 2) << endl; //成员变量b的内容
}
}
测试结果与示意图一样: