提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
一、封装性
把类中的某些属性或方法设置为私有,对外设置公有接口用于查看或修改私有属性或方法,减少耦合
二、继承性
类可以作为基类被继承,子类可以继承基类的属性和方法,有三种继承方式
注意:继承的方法不包括构造函数和析构函数,但是子类继承父类的属性需要调用父类的构造去初始化,所以,子类实例化是先调用父类的构造在调用子类的构造函数。
三.多态性
多态性指的是父类的接口可以有多种状态,具体被子类实现,先说几个概念:
1.虚函数:
父类可以在某些函数前加上virtual关键字设置为虚函数,如果虚函数没有定义只是声明,那么称其为纯虚函数,虚函数可以被子类重写,也可以不重写,拥有至少一个纯虚函数被称为纯虚类,其子类必须重写父类全部的虚函数。
如果定义了虚函数那么类中会在编译期生成一个虚函数表,用来存储指向虚函数的指针
2.虚表指针:
每个对象会存在虚表指针指向类中的虚函数表__vptr
这个指针存在每个实例的存储地址的最前面,如下图:
当子类继承含有虚函数的父类,子类中也会生成一个虚函数表,如果子类重写了对应的虚函数,那么表中的指向就会更改。
如下图b继承a,b重写了vfunc1,所以b的虚表中发生了变化;b自定义的函数也会放在虚表的后面
多态性的一个体现,就是当父类指针指向子类对象的时候,由于是动态绑定,运行时首先会调用父类的构造函数,在调用子类的构造函数,将虚表指针指向子类虚表
3.虚析构:
如果子类发生了重写那么该对象会调用重写的函数,没重写会调用父类的函数。当我们重写时子类的虚函数表会发生变化,这时我们释放父类的指针,那么我们只会释放父类的空间和虚函数表,而子类的虚函数发生了修改,不同于父类,所以子类的虚函数表并未被完全释放,这会造成内存泄漏。这时我们就需要虚析构即在父类析构函数前加上virtual关键字,这样再释放时会根据虚函数表先找到子类的析构函数然后调用父类的析构函数delete父类指针。
4.运行时多态,动态绑定技术
简单来说多态性具体指父类的指针可以指向子类的对象,通过子类对父类虚函数的重写,父类的接口会有不同的实现。
多态性又被叫做运行时多态,是一种动态绑定技术,相对于静态绑定,动态绑定在运行时将变量名和函数名转化为地址,而静态绑定在编译期就完成,而动态绑定是运用函数指针来完成的
例如我们创建线程池时,为线程绑定工作函数,我们传入函数指针,具体函数里调用其他函数而并没有直接将具体代码直接写在worker里而是另外写在了run函数里面(如下图),这样在修改时可以更换任务函数,利用worker调用,而多态性中父类的接口便是类似于例子中的worker函数,子类类似于run函数,父类指针指向子类对象。
多态与非多态的实质区别就是函数地址是早绑定还是晚绑定。如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态的,就是说地址是早绑定的。而如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定。
多态的具体用法:可用作传参或返回值,或者直接定义父类指针指向子类对象。
实例:工厂模式的使用,关于工厂模式可以看我前面的文章。
总结
封装性体现在将属性或方法私有,对外提供接口增强安全性,继承性出要体现在子类可以继承父类的属性和方法,提高代码的利用率,多态性主体现在虚函数的使用,有了虚函数子类便可以重写,使父类接口有多种实现。