从C语言发展而来的C++增加了类的概念以及其带来的面向对象编程思维。OO四大特性我认为最重要的是多态性,因为多态势必牵涉到继承,要继承必须先抽象和封装好基类。
而编译器为了支持多态,在程序员书写的源代码背后做了不少手脚。多态的核心在于延迟绑定,即执行的时候才知道该调用哪个函数(C++为了效率,编译时就已确定函数指针)。C++中为了实现延迟绑定,多了一层间接性,即引入了Virtual table和Virtual table pointer(分别简记为vtbl,vptr)。正是因为多了上述的vptr使得upcasting到基类的指针或者引用可以动态的调用子类的函数体。
C++的处事之道在于:如果不是必需的额外负担,一概以效率为先。因此只有涉及到virtual关键字(虚成员函数,虚继承)的类才会有vtbl。当然,也只有使用了virtual关键字才能享受OO多态带来的一系列好处。
Vtbl和vptr对程序员是不可见的,由编译器全权负责。在对象创建的时候(默认构造函数,拷贝构造函数),以及拷贝赋值的时候(copy-assignment operation)编译器必需生成适当的代码来正确设置vptr。
当程序员使用多态机制调用函数时,编译器必需用vptr来改写程序员的代码,使之通过vptr来间接调用“正确的”成员函数。当涉及多继承和虚继承时,还有复杂的this指针调整。
下面通过实例来看。
首先是未使用virtual关键字的普通类,此时的函数调用和C类似,直接绑定函数地址。此时编译器不会生成vtbl和vptr,所以没有任何多态特性。
class c_style
{
public:
int c;
void who_am_I ()
{
cout<<“c style \n”;
}
class cc_style:c_style
{
void who_am_I ( )
{
cout<<“cc style\n”;
}
}
int main()
{
c_style c,*pc;
cc_style cc;
pc=&cc;
c.who_am_I(); //c style
cc.who_am_I(); //cc style
pc->who_am_I(); //c style
}
使用virtual关键字,编译器会在后台生成vtbl并且为每个对象设置vptr。
class Animal
{
int name;
bool isAnimal()
{
return true;
}
virtual void sound()
{
Cout<<”\n”;
}
}
class Dog:public Animal
{
bool hasFur;
void sound()
{
Cout<<”dog dog dog\n”;
}
virtual Void eat()
{
Cout<<”eat meat and vegetable\n”;
}
}
class Wolf:public Dog
{
void sound()
{
Cout<<”wolf wolf wolf\n”;
}
void eat()
{
Cout<<”eat meat only\n”;
}
}
int main()
{
Animal animal,*pa;
Dog dog,*pdog;
Wolf wolf;
pa = &wolf;
pdog = &wolf;
pa->sound(); // wolf wolf wolf (触发多态机制)
pdog->eat(); // eat meat only (触发多态机制)
}
如图所示,每个对象的虚函数表各不相同。向上转型时编译器负责保证vptr指向正确的虚函数表。
wordpress 玩不转,格式一塌糊涂了。
搞个代码高亮插件吧~
搞定了的话,也教教我 😛