继承(inheritance) 机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础.上进行扩展,增加功能。这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构。体现了由简单到复杂的认识过程。
多态性(polymorphism) 多态性是考虑在不同层次的类中,以及在同一类中,同名的成员函数之间的关系问题。函数的重载,运算符的重载,属于编译时的多态性。以虚基类为基础的运行时的多态性是面向对象程序设计的标志题。函数的重载,运算符的重载,属于编译时的多态性。以虚基类为基础的运行时的多态性是面向对象程序设计的标志
继承
C++通过类派生的机制来支持继承,被继承的类叫做基类或超类,新产生的来叫做派生类或子类。基类和派生类的集合叫做类继承层次结构。
使用方法:
class 派生类名 :访问限定符 基类名,…,访问限定符 基类名
编制派生类分为四步:
1、吸收基类成员:无论数据成员还是函数成员,除构造函数和析构函数外全盘接收。
2、改造基类成员:声明一个和某基类同名的新成员,派生类的新成员就屏蔽了基类同名成员叫做同名覆盖。
3、发展新成员:派生类新成员与基类的所有成员步同名,它的加入保证派生类在功能上有所发展,独有的新成员是继承和派生的核心特征 。
4、重写构造函数和析构函数。
访问控制,也叫继承方式,对基类成员的进一步限制。
- 公有继承(public)(意味着“是一个”的意思)
1、基类的public和protected成员的访问属性在派生类中保持不变,但基类的private成员不可直接访问。
2、派生类中的成员函数可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员。
3、通过派生类的对象只能访问基类的public成员。 - 私有继承(private)
1、基类的public和protected成员都以private身份出现在派生类中,但基类的private成员不可直接访问。
2、派生类中的成员函数可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员。
3、通过派生类的对象不能直接访问基类中的任何成员。 - 保护继承(protect)
1、基类的public和protected成员都以protected身份出现在派生类中,但基类的private成员不可直接访问。
2、派生类中的成员函数可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员。
3、通过派生类的对象不能直接访问基类中的任何成员
protected 成员的特点与作用:
1、对建立其所在类对象的模块来说,它与private成员的性质相同;
2、对于其派生类来说,它与public成员的性质相同;
3、既实现了数据隐藏,又方便继承,实现代码重用。
派生类和基类:
1、派生类的对象可以赋值给基类的对象,是把派生类对应从基类继承来的隐藏对象赋值给基类,反过来不行,因为派生类的新对象无值可赋;
2、可以将一个派生类的对象的地址赋给其基类的指针变量,但只能通过这个指针访问派生类中由基类继承过来的隐藏对象,不能访问派生类的新对象,同样也不能反着做。
3、派生类的对象可以初始化基类的引用,引用是别名,但这个别名只能包含派生类对象中由基类继承来的隐藏对象。
友元不具有继承性,静态成员只有一个,基类对象和派生类对象共享。
多态与虚函数
多态
多态性是面对对象程序设计的关键技术之一,利用多态性技术可以调用同一个函数的函数实现完全不同的功能。
虚函数
虚函数是一个类的成员函数,定义格式为:virtual 返回参数 函数名(参数列表); virtual仅可用于类内定义,如虚函数在类外定义不可加virtual。
当一个类的一个类成员函数被定义为虚函数时,则由该类派生出来的所有派生类中,该函数一直保有虚函数的特征。
类的成员函数应尽量设置为虚函数,但应注意:
- 派生类中定义的虚函数必须与基类的函数同名外,还必须同参数表,同返回类型。否则被认为是重载而不是虚函数。但基类中返回基类指针,派生类中返回派生类指针是允许的,这是一个例外。
- 只有类的成员函数才能被定义为虚函数。因为虚函数只适用于有继承关系的类对象。
- 静态成员函数不能设为虚函数。
- 实现动态多态性时,必须使用基类类型的指针或引用,使该指针指向该基类的不同派生类的对象,并通该指针指向虚函数,才能实现动态多态性。
- 内联函数不能作为虚函数。
- 析构函数可以定义为虚函数,但构造函数不能定义为虚函数。在基类中及其派生类中都动态分配内存空间时,必须把析构函数定义为虚函数,实现析构时的多态性。
- 虚函数的函数执行稍慢一些,每个派生类中均要保存相应虚函数的入口地址表,函数的调用机制也是间接实现。
- 如果定义在类外,virtual必须加在函数声明前面,不能再加在函数定义前面。
根据赋值兼容规则可以用基类的指针指向派生类对象,如果由该指针撤销派生类对象,则必须将析构函数说明为虚函数,实现多态性,自动调用派生类析构函数。我们总是要求将类设计成通用的,无论其他程序员怎样调用都必须保证不出错,所以必须把析构函数定义为虚函数。在动态分配内存时所有C+ +的标准库函数都采用这种格式。
纯虚函数和抽象类
纯虚函数
纯虚函数是指被指名为不具体实现的虚拟成员函数。它用于:在定义基类时,会遇到无法定义基类虚函数的情况,其实现依赖于它的不同派生类。
定义纯虚函数的一般格式:
virtual 返回参数 函数名(参数列表)= 0 ; "=0"本质上是将指向函数体的指针指向为NULL。
纯虚函数与虚函数的区别
- 类中如果声明了虚函数,这个函数是实现的,哪怕是空实现,作用是为了在子类里面可以覆盖这个函数,这样编译器就可以使用后期绑定来达到多态;而纯虚函数只是一个接口,是个函数的声明,要留到子类中才能实现。
- 虚函数在子类中是可以不重载的,但纯虚函数必须在子类中实现。
- 带纯虚函数的类叫做虚基类,它不能直接生成对象,只能被继承,并重写其纯虚函数后才能生成对象。
抽象类
含有纯虚函数的类叫抽象类,它是为了抽象和设计的目的而建立,处于继承层次结构的较高层。抽象类是不能产生对象的,在实际中为了强调一个类是抽象类,可以将其构造函数说明为保护的访问控制权限。
抽象类只描述这组子类共同的操作接口,而具体的实现留给子类。
抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类没有重新定义纯虚函数,则这个派生类依旧是一个抽象类。如果派生类给出了基类纯虚函数的实现,则该派生类就不是一个抽象类了,是一个可以建立对象具体类了。
抽象类的规定
- 抽象类只能作为其他类的基类,不能产生基类对象。
- 抽象类不能用作参数类型、函数返回类型或显示转换的类型。
- 可以定义指向抽象类的指针或引用,此指针可以指向它的派生类,进而实现多态性。
动态联编和虚继承
动态联编
联编是值计算机程序自身彼此关联的过程,是把一个标识符名和一个存储地址联系在一起的过程,也就是把一条消息和一个对象的操作相结合的过程。
如果使用基类的指针或引用,指明派生类对象,并使用该指针调用虚函数(成员选择符用"->"),则程序在运行时动态的选择该派生类的虚函数,称为动态联编。亦称滞后联编。
如果使用对象名和点成员选择符".",引用特定的对象来哦调用虚函数,则被调用的虚函数是在编译时确定的,称为静态联编。
虚继承
虚继承是面向对象编程中的一种技术,是指一个指定的基类,在继承体系结构中,将其成员数据实例共享给也从这个基类型直接或间接派生的其它类。
虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。
在C++中,多重继承是不推荐的,也并不常用,而一旦离开了多重继承,虚拟继承就完全失去了存在的必要,因为这样只会降低效率和占用更多的空间。
用法:class 子类 : virtual public 父类
多继承时很容易产生命名冲突,即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发生