《深入探索C++对象模型》读书笔记


从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指向正确的虚函数表。


2 thoughts on “《深入探索C++对象模型》读书笔记

Leave a Reply

Your email address will not be published.


*