多态和虚函数
取一个对象地址(指针或者引用),并将其作为基类的地址来处理,这被称为向上类型转换(upcasting),因为继承树的绘制方式是以基类为顶点的。
virtual 关键字只用在定义函数的时候,不用在函数实现的时候。
基类中定义了虚函数,派生类中无论是否说明,同原型函数都自动成为虚函数。
调用方式:通过基类指针或引用,执行时会根据指针指向的对象的类,决定调用哪个函数。
虚函数遵循的规则
如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,那么即使加上了virtual关键字,也是不会进行动态联编的。
只有类的成员函数才能说明为虚函数,因为虚函数仅适合于有继承关系的类对象,所以普通函数不能说明为虚函数。
静态成员函数不能是虚函数,因为静态成员函数的特点是不受限于某个对象。
即使虚函数在类的内部定义,在编译的时候系统仍然将它看做是非内联的。
构造函数不能是虚函数,因为构造的时候,对象还是一片未定型的空间,只有构造完成后,对象才是具体类的实例。
析构函数可以是虚函数,而且通常声名为虚函数。
动态联编只能通过指针或引用标识对象来操作虚函数。如果采用一般类型的标识对象来操作虚函数,则将采用静态联编方式调用虚函数。
如果有一个或者多个虚函数,编译器都只会在这个结构中插入一个(且单个)的指针(VPTR)。因此一个类中有一个虚函数和两个虚函数他们的长度没有区别。我是说用sizeof测这个类的长度的话。
每当创建一个包含虚函数的类或者从包含有虚函数的类派生一个类时,编译器就为这个类创建一个唯一的VTABLE。
虚函数表( VTABLE ),内含该类之中有作用的虚函数的地址,然后每个对象有一个vptr,指向虚函数表的所在。
每当创建一个包含有虚函数的类或者包含有虚函数的派生类时,编译器就为这个类创建一个VTABLE.
如果在派生类中没有对这基类中声明为Virtual的成员函数进行重新定义,编译器就是用基类的这虚函数的地址然后编译器在这个类中放入VPTR.
VPTR必须被初始化为相应的VTABLE的起始地址。(在构造器中)
绑定
函数体与函数调用相联系称为捆绑(binding)
捆绑在程序运行前(由编译器和连接器)完成时,称为早捆绑(静态联编)(静态绑定)(早期绑定)。
在运行时捆绑称为晚捆绑(动态联编)(动态绑定),动态捆绑,或运行时捆绑。
晚捆绑是通过某种机制来确定运行时对象的类型并调用合适的成员函数体代码。
实现晚捆绑,C++要求在基类中声明这个函数时用virtual关键字。定义时不需要。