一、基类指针
二、虚函数
virtual:在父类的函数声明前,加这个关键字,该函数以及子类继承的函数就都是虚函数。子类函数声明前可以加,也可以不加。子类的虚函数函数名要与父类函数名一致,包括参数名也要一致。
override: 用在子类中,虚函数专用。在函数声明后,在()括号后加
这个关键字的作用就是在父类中找和他同名的虚函数,并将其覆盖掉。实际可以帮助你纠错,如果你子类写的虚函数与父类中的虚函数名字不一致,就会报错。
final:用在父类中,也是虚函数专用。在父类中的虚函数加了这个关键字,子类的虚函数就不能覆盖父类的虚函数。
调用虚函数,执行的是动态绑定。就是在程序运行的时候,在能知道子类执行的是哪个虚函数,编译时不知道。
当声明一个父类指针,通过new来给他初始化,通过这个指针来调用类中的函数,如果该函数不是虚函数,你new一个子类对象时,通过该指针只能调用父类的函数,不能调用子类的函数。如果该函数是虚函数,就可以通过指针调用子类的函数。
三、多态性
多态性针对的是虚函数的概念。
体现在具有继承关系的父类和子类之间,子类重新定义父类(重写)父类的成员函数(虚函数)
通过父类的指针,只有到程序运行时期,找到动态绑定到父类指针上的对象,这个对象可能是某个子类对象,也可能是父类对象。系统通过查内部的虚函数表,来确定该调用哪个虚函数。
四、纯虚函数
纯虚函数:在基类中没有定义该虚函数的实现,只有声明,但要求任何该派生类都必须要定义该虚函数自己的实现方法。
纯虚函数的定义方法:在虚函数后面加“=0”
virtual void func() = 0;//纯虚函数,没有函数体,只有声明。
注意:一旦一个类中有纯虚函数,就不能生成该类的对象了。不能实例化,这种类就叫抽象类。主要目的是用来统一管理子类对象。
记住2点:
1、有纯虚函数的类就叫抽象类,不能实例化对象,主要用来生成子类
2、子类中必须要有该纯虚函数的实现。
五、虚析构函数
在基类中的析构函数一般定义成虚函数。
int main
{
//human父类 Men子类
Men men;
Men *pmen = new Men;//这里先调用父类再子类的构造函数
delete pmen;//这里调用了子类和父类的析构函数
human *phuman = new Men;//这里先调用父类再子类的构造函数
delete phuman;//这里只调用了父类的析构函数,可能导致内存泄漏
}
结论:用基类指针new子类对象,在delete时,系统不会调用子类的析构函数,这里肯定有问题!
如何解决?
把基类的析构函数定义成虚函数即可
记住:在pubulic继承中,基类对派生类及其对象的操作,只能影响到哪些从基类继承下来的成员。如果想用基类对非继承成员进行操作,则要把基类中的这个函数定义成虚函数,析构函数也是这样。
另外就是基类中析构函数的虚属性也会继承给子类,虽然函数名不同
delete humen的时候,肯定调用基类的析构函数,但在父类中要调用子类的析构函数,那么父类humen的析构函数必须是virtual,也就是说C++中为了获得运行时的多态行为,所调用的函数成员必须是virtual
结论:
1、基类的析构函数必须写成virtual 析构函数
2、普通类可以没有析构函数,但基类必须要有析构函数,而且是虚析构函数
3、虚函数会增加内存开销