1 封装
谈到封装,我觉得应该与对象结合起来看,他是将客观事物抽象成类,以类来进行来进行后续的代码创作,以类来进行代码的搭积木,在大型的项目里面就可以很条理的对代码进行查看和管理。同时将里面的功能设置成接口的形式,通过在类里面设置限制符,将某些接口暴露给外部,便于访问类,某些则设置成私有的形式,外部不能够进行访问,条理而又安全。
2 继承
继承最大的优势主要在于通过类层面的复用,可以很好的减少代码的冗余。同时自己又可以加入一些东西丰富类的功能,但是关于继承有一些东西还是需要进行注意的:
2.1 作用域
对于派生类和基类当中成员变量和成员方法,两个作用域是相互独立的,对于基类和派生类中有相同的成员变量或者成员方法的时候,这时就需要引入第二个注意点隐藏了。
2.2 隐藏
基类和派生类当中存在由相同的成员变量或者方法时,派生类会优先使用派生类里面的变量或者方法,对基类里面的方法或者变量则会进行隐藏,如果在派生类里面要使用,就需要加上基类名称这个作用域了(例如A::a)。
2.3 继承当中的友元问题
对于基类当中存在的友元函数,派生类是不会将其继承下来的,也就是说基类当中的友元函数是不能够访问派生类里面的内容的。
2.4 继承当中的静态函数
基类当中存在的静态变量,对于该基类的整个继承体系,该静态变量只有这一个
2.5 继承当中的菱形继承
在继承这个特性里面最难理解的或许就是菱形继承,这获取也是C++这门语言的一个弊端吧,所以在实际的编写当中是不建议使用菱形继承的。
如上图第一个所示的菱形继承,对于类D而言,如果要给它里面的a进行赋值,此时如果前面没有给出类域,此时就不知到底给那个a进行赋值,同时由于继承了两次的a,会给类D当中的代码带来冗余,因而可以看出这不是一个很好的继承方式。
要想解决上面菱形继承带来的问题,这里就需要引入虚拟继承的概念了,上图当中的第二个图就是普通的继承,这种继承的方式有点像我们常说无脑继承,把基类里面的东西全部拿下来,这样也就很容易出现我们上面见到的代码冗余和二义性的问题,这种就不适合于菱形继承了。上面的第三个图就是虚拟继承的原理了,类D当中虽然也继承了类B和类C的内容,但是对于相同的成员变量int a,类B和类C继承下来时,不是将a给直接带下来了,而是带下了虚机表指针,这个虚机表指针指向的位置也就是虚机表里面,具体的指向的内容是一个整数,这个整数的大小就是在类D当中对应类的虚基表指针与a指针的相对位置大小(如下图所示)。简单来说就是这里继承下来的不是实际的a,而是将a放在一个公共位置,继承里面有指向这个公共位置的指针,这时不管修改类B的a的值还是类C的a的值,实际都是修改这个公共位置a的值。
3 多态
建立在继承的基础之上
3.1 什么是多态
简单来说,就是不同的类实例出来的对象,在进行调用相同的函数时,可能会行使不同的功能,展现出来不同的“形态”。
3.2 形成多态的两个条件
- 被调用的函数必须是虚函数,且派生类对该虚函数已经进行了修改。
- 必须是通过基类的指针或者引用来进行调用虚函数。
3.3 多态的原理
如上图所示,画的就是多继承多态的原理(单继承只是这个简单版,原理都是一样的),每一个类里面都会包含一个虚基表指针数组,继承的时候也会继承下来,当派生类有虚函数和基类的虚函数一样的(名字相同,但是内容已经发生了重写),这时派生类就会在继承下来的那个类的虚机表当中,对这个虚机表指针进行修改,改成派生类里面的对应虚函数,这时当不同的类调用相同的函数时,就会产生不同的功能,展现不同的形态了。