C++

来源:互联网 发布:js object转array 编辑:程序博客网 时间:2024/06/05 09:30

C++多态性

1:用virtual关键字声明的函数叫做虚函数,存在虚函数的类都有一个虚函数表叫做虚表,类的对象有一个指向虚表开始的虚指针,类与虚表对应,对象与虚指针对应。

2:多态性是一个接口多种实现,父类型的指针指向其子类的实例,然后通过父类的指针调用子类的成员函数,父类的指针有多种形态。

3:多态用虚函数实现,结合动态绑定,纯虚函数是虚函数再加上=0,抽象类指至少含一个纯虚函数的类。

编译的角度:

C++编译器在编译的时候,要确定每个对象调用的函数(要求此函数为非虚函数)地址,这就是早期绑定,当我们将子类的对象赋值给基类的指针时,C++编译器进行类型转换,此时编译器认为子类对象保存基类对象地址,调用基类对象的成员函数。

原因是编译器在编译的时候,就已经确定了对象函数的调用地址,要解决这个问题就要用迟绑定技术,就会在运行时确定对象类型以及正确调用的函数,就要在基类中声明函数时使用virtual关键字,就是虚函数,一旦某个函数在基类中声明为virtual,那么在所有派生类中该函数都是virtual

编译器在编译的时候,发现基类中虚函数,会为每个包含虚函数的类创建一个虚表(vtable),是一维数组存放每个虚函数地址,若基类创建虚函数,子类和基类都会分别创建一个虚表,如图


编译器为每个类的对象提供了一个虚表指针(即vptr),这个指针指向所属元素的虚表,在程序运行时根据对象的类型去初始化vptr,从而让vptr指向所属类的虚表,每个对象调用的虚函数都是通过虚表指针索引的,虚表指针初始化发生在构造函数进行虚表的创建,在构造子类对象时,要先调用父类的构造函数,此时编译器只看到父类,它初始化父类的虚表指针,该虚表指针指向父类的虚表,当执行子类构造函数时,子类对象的虚指针初始化,指向自身的虚表。

对于虚函数调用来说,每个对象内部都有一个虚表指针,该虚表指针被初始化为本类的虚表,在程序中无论对象类型如何转换,但该对象内部得到虚表指针是固定的,此时调用不是在编译时而是在运行时确定,所以才能实现动态的函数调用。

 

C++成员函数的覆盖、重载和隐藏

函数重载特征:

(1)相同的范围(在同一类内)

(2)相同函数名

(3)参数不同

(4)virtual可有可无

覆盖:派生类覆盖基类成员函数

(1)不同的范围(分别位于子类和父类)

(2)相同的函数名

(3)参数相同

(4)基类函数必须有virtual

隐藏指的是指派生类的函数屏蔽了与其同名的基类函数:

(1)如果基类函数与派生类函数同名,但是参数不同,此时无论有无virtual,基类的函数将被隐藏(注意区分重载)。

(2)如果基类函数与派生类函数同名,并且参数也相同,但是基类函数没有virtual关键字,基类函数将被隐藏(注意区分覆盖)。

 

C++ static的作用

(1)隐藏:同时编译多个文件时,所有未加static的全局变量和函数具有全局可见性,其他源文件也可以访问,如果加了static,就会对其他源文件隐藏就不能在调用,利用这一特性就可以在不同文件中定义同名函数和同名变量,而不必担心命名冲突,static可以作用于变量和函数的前缀,对于函数来讲作用只有隐藏,对于变量还有其他作用。

(2)保持变量内容的持久。存储在静态存储区的全局变量可以在程序刚开始运行时就完成初始化,也是唯一的一次初始化。全局变量和static变量都存储在静态存储区,只不过和全局变量比起来,static可以控制全局变量的可见范围。

(3)变量默认初始化为零。实际上全局变量也具有此属性,因为在静态存储区所有的内存的字节默认值都为0x00,有些时候可以减少程序员的工作量,比如在初始化一个元素个数多的数组,若定义为静态的,就省去了一开始全部置零的操作。

最后对static的三个作用总结就是:首先static最主要的功能就是隐藏,其次因为static存放在静态存数区,所以它具备持久性和默认值0

 

 

 


0 0
原创粉丝点击