C++继承
1. C++继承原理
C++的继承可以理解为在创建子类成员变量之前先创建父类的成员变量,实际上,C语言就是这么模仿出继承功能的。
在内存中,父类的成员变量和子类的成员变量如图所示:
(1) C++子类对象的构造过程。先调用父类的构造函数,再调用子类的构造函数,也就是说先初始化父类的成员,再初始化子类的成员。
(2) 若父类没有默认的构造函数,子类的构造函数又未调用父类的构造函数,则无法编译。
(3) C++子类对象的析构过程。如果父类的析构函数不为虚函数,则只调用父类的析构函数,而不调用子类的析构函数,此时会产生内存泄露。如果父类的析构函数为虚函数,会先调用子类的析构函数,再调用父类的析构函数。且c++默认的析构函数不是虚函数。
2. 虚函数介绍
(1)父类指针可以指向子类对象,这个是自然而然的,因为子类对象的内存前面就是父类成员,类型完全匹配。
(2) 当父类指针指向子类对象,且子类重写父类某一函数时。父类指针调用该函数,就会产生以下的可能
① *该函数为虚函数:父类指针调用的是子类的成员函数。*
② *该函数不是虚函数:父类指针调用的是父类的成员函数。*
例子:
- 当只有子类的方法有virtual关键字,而父类方法没有时。调用的仍然是父类的成员方法。
- 当子类的方法没有有virtual关键字,而只有父类方法有时。调用的是子类的成员方法。因为当父子类成员函数的形式相同时,父类成员方法有virtual关键字,会自动给子类方法也加上。
3.虚函数的注意事项:
(1) 子父类的虚函数必须完全相同,为了防止开发人员一不小心将函数写错,于是C++11添加了override关键字。
(2)父类的析构函数必须为虚函数:这一点很重要,当父类对象指向子类对象时,容易使独属于子类的内存泄露。会造成内存泄露的严重问题。
例子:
4.虚函数实现多态的原理
(1) 动态绑定和静态绑定:
① 静态绑定:程序在编译时就已经确定了函数的地址,比如非虚函数就是静态绑定。
② 动态绑定:程序在编译时确定的是程序寻找函数地址的方法,只有在程序运行时才可以真正确定程序的地址,比如虚函数就是动态绑定。
(2) 虚函数是如何实现动态绑定的呢?
① 每个有虚函数的类都会有一个虚函数表,对象其实就是指向虚函数表的指针,编译时编译器只告诉了程序会在运行时查找虚函数表的对应函数。每个类都会有自己的虚函数表,所以当父类指针指向子类对象,引用的便是子类虚函数表,自然调用的就是子类的函数。
5.纯虚函数
纯虚函数介绍:
当一个基类无实际意义,其中的函数作用都是被覆写时,那么纯虚函数的语法就能够在此起到作用。
只要将一个虚函数写为纯虚函数,那么该类将被认为无实际意义的类,无法产生对象。纯虚函数也不用去写实际部分,写了编译器也会自动忽略。
需要注意的是,构造函数和析构函数不能省。
例子: