C++ COM编程之接口背后的虚函数表
前言
学习C++的人,肯定都知道多态机制;多态就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。对于多态机制是如何实现的,你有没有想过呢?而COM中的接口就将这一机制运用到了极致,所以,不知道多态机制的人,是永运无法明白COM的。所以,在总结COM时,是非常有必要专门总结一下C++的多态机制是如何实现的。
多态
什么是多态?上面也说了,多态就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。现在通过代码,让大家切身的体会一下多态:
#include <iostream>
using namespace std;
class A
{
public:
void Print()
{
cout<<"I am A."<<endl;
}
};
class B : public A
{
public:
void Print()
{
cout<<"I am B."<<endl;
}
};
int main()
{
A *pAObj = new B();
pAObj->Print();
}
上面代码的运行结果是:I am A.这不是多态的行为。
好了,经过对上面代码的改造,就在A类的Print函数前面加入关键字virtual,具体代码如下:
#include <iostream>
using namespace std;
class A
{
public:
virtual void Print()
{
cout<<"I am A."<<endl;
}
};
class B : public A
{
public:
void Print()
{
cout<<"I am B."<<endl;
}
};
int main()
{
A *pAObj = new B();
pAObj->Print();
}
此时,代码的运行结果为:I am B.这个时候就表现出来了多态行为。好了,多了我也不说了,就通过这个简单的例子,你就能体会到多态的概念了。从下面才开始今天的主题。
虚函数表
多态机制的关键就是在于虚函数表,也就是vtbl。当我们定义一个类,类中包含虚函数时,其实也就定义了一张虚函数表,没有虚函数的类是不包含虚函数表的,只有该类被实例化时,才会将这个表分配到这个实例的内存中;在这张虚函数表中,存放了每个虚函数的地址;它就像一个地图一样,指明了实际所应该调用的函数。比如我定义一个类,如下:
class CIF
{
public:
CIF(){}
CIF(int i, int f) : m_iVar(i), m_fVar(f){}
virtual void IF1() { cout<<"I'm IF1"<<endl; }
virtual void IF2() { cout<<"I'm IF2"<<endl; }
virtual void IF3() { cout<<"I'm IF3"<<endl; }
void MemFunc(){ cout<<"I'm IF4"<<endl; }
private:
int m_iVar;
float m_fVar;
};
这样的一个类,当你去定义这个类的实例时,编译器会给这个类分配一个成员变量,该变量指向这个虚函数表,这个虚函数表中的每一项都会记录对应的虚函数的地址;如下图:
这个类的变量还没有被初始化时,就像上图那样,变量的值都是随机值,而指向虚拟函数表的指针__vfptr中对应的虚函数地址也是错误的地址;只有等我们真正的完成了这个变量的声明和初始化时,这些值才能被正确的初始化,如下图:
- 上一篇:C++设计模式之装饰模式
- 下一篇:C++ COM编程之什么是接口?