标签:效率 实现 rtu nbsp 初始化 自动 替换 函数指针 虚函数
C++中多态的实现原理
当类中声明虚函数时,编译器会在类中生成一个虚函数表
虚函数表是一个存储类成员函数指针的数据结构
虚函数表是由编译器自动生成与维护的
virtual成员函数会被编译器放入虚函数表中
存在虚函数时,每个对象中都有一个指向虚函数表的指针(vptr指针)
C++内存模型中,会将对象中的成员变量和成员方法分开存储,同时在成员函数中第一个参数的位置添加一个this指针。
类对象中的普通成员变量,struct变量具有相同的内存布局和字节对齐方式。
类对象中的静态成员变量,存储在全局数据区(我也不知道存在内存的什么位置,不知道是不是和那些常量以及字符串存储在同一位置)
类中的成员方法,存储在代码段中,同时在静态联编的时候,会将同一个类中的函数重载进行函数名称的替换(具体方式应该是函数名称+参数类型)。
但是,如果一个类中加了virtual关键字,C++编译器会有另外一种方式来进行上面描述的安排,会在struct中添加一个vptr指针(这就是为什么在使用virtual关键字之后在使用sizeof操作符会多4个字节的原因)
如果一个类中使用virtual关键字,在用类定义对象的时候,会在对象中添加一个vptr指针属性(这个操作是编译器自动进行的,对于程序员是不可见的),
C++将虚函数做成虚函数表,存储了多个虚函数的入口地址,然后将对应的虚函数指针放置到虚函数表中。
C++编译器不需要区分是子类对象还是父类对象,区分这个函数是虚函数还是普通函数,如果是普通函数就进行普通函数的调用(如果不是虚函数,那就表明是静态联编)。
父类对象中有一个vptr指针,子类中也有一个vptr指针,在确定一个函数是虚函数的时候,根据vptr指针找虚函数表,父类有个虚函数表,子类也有一个虚函数表,然后再找函数的入口地址,就实现了一个迟绑定的效果,也就是只有在运行的时候c++编译器采取判断。
构造函数中调用虚函数,能实现多态么?
vptr指针的分布初始化:
初始化子类的vptr指针是分布完成的。当直行父类的构造函数时(往往是先直行父类的构造函数在执行子类的构造函数),这个时候vptr指针指向的是父类的虚函数表,然后当直行子类的构造函数的时候,vptr指针指向的是子类的虚函数表,最后才完成vptr指针的初始化。
是否可将类函数中的每一个普通函数都声明为虚函数?可以,但是会影响到使用的效率不建议这么做。
通过虚函数表vptr确定调用的函数是在运行的时候直行的,因此需要通过寻址操作才可以找到真正应该调用的函数,而普通函数在编译阶段就可以确定要调用的函数,因此在效率上而言,虚函数需要寻址这一步,因此会慢一点。
说这么多,为的是说明C++编译器其实并没有区分是子类对象还是父类对象,而是通过vptr的形式进行区分的。
多态的理解
效果:同样一个调用语句,有不同的调用形态,
实现条件:继承,有virtual重写,有父类指针指向子类对象
多态实现的理论基础:动态联编和静态联编,根据实际对象类型来调用重写的函数。
多态的重要意义是设计模式的基础,是框架的基石。
函数指针做函数参数,多态的原理也是函数指针做函数参数,实现一个回调的效果。
多态的原理具体实现。
子类指针步长和父类指针步长是不同的概念
多态时用父类指针指向子类对象,和将父类指着进行++操作是两个不同的概念,++操作每次跳过的内存块大小是两个不同的概念。
纯虚函数和抽象类
纯虚函数是在一个基类中说明的虚函数,在基类中没有定义,要求任何继承的类多有自己的版本。纯虚函数为各个派生类定义了一个公共接口,
纯虚函数的类型 virtual 类型 函数名(参数列表)=0
一个具有纯虚函数的类成为抽象类(这个概念和java中的差不多)
纯虚函数只定义,没有函数体,就是为了让派生类来继承。
虚函数类是不能创建对象的,不过可以创建对象指针,这个就是多态啊。
抽象类不能作为返回类型,抽象类不能作为参数,不过可以声明抽象类的引用。
最根本的原因在于,抽象类不能进行实例化,不过由于C++编译器支持多态,因此,可以作为函数返回值或者是函数参数。
标签:效率 实现 rtu nbsp 初始化 自动 替换 函数指针 虚函数
原文地址:http://www.cnblogs.com/andyniu/p/7827339.html