继承和派生
继承可以用来干什么:
- 可以在已有的类的基础上添加新的变量;
- 可以在已有的类的基础上添加新的功能(函数);
- 可以修改类的方法(不常用)::例如车是父类,衍生出汽车 大巴车两个子类;在父类中有一个开车的方法;但是对于两个字类来讲,开车的方法不同。所以会设计方法的重写(修改类的方法);
什么时候用继承? - 创建一个新类时,这个类和现有的类相似(只是多出一些变量或函数的时候)例如:同样是车的例子,我先有一个车的类,然后要定义一个轿车的类,发现轿车和车有相似(都是四个轮子,都是用方向盘的等等)
- 当你创建多个类时,发现有很多类似的成员函数或者成员变量。例如:我先定义了,汽车,跑车,大巴车三个类,发现他们都是四个轮子,都是交通工具,都是一个司机等等相同的成员变量或函数,那么就可以将这写相似的提取出来作为一个 车 类,然后这三个类再去继承他,这样可以节省代码。
继承权限
继承的声明是:
class 派i类名:<继承权限> 基类名{ };
继承默认的权限和封装一样为 private
public继承方式:
1)基类中所有 public 成员在派生类中为 public 属性;
2)基类中所有 protected 成员在派生类中为 protected 属性;
3)基类中所有 private 成员在派生类中不能使用。
protected继承方式
1)基类中所有 public 成员在派生类中为 protected 属性;
2)基类中所有 protected 成员在派生类中为 protected 属性;
3)基类中所有 private 成员在派生类中不能使用。
private继承方式
1)基类中所有 public 成员在派生类中均为 private 属性;
2)基类中所有 protected 成员在派生类中均为 private 属性;
3)基类中所有 private 成员在派生类中不能使用。
有几点说明:
- 基类成员在派生类中的访问权限不得高于继承方式中指定的权限。例如,当继承方式为 protected 时,那么基类成员在派生类中的访问权限最高也为 protected,高于 protected 的会降级为 protected,但低于 protected 不会升级。再如,当继承方式为 public 时,那么基类成员在派生类中的访问权限将保持不变。
也就是说,继承方式中的 public、protected、private 是用来指明基类成员在派生类中的最高访问权限的。 - 不管继承方式如何,基类中的 private 成员在派生类中始终不能使用(不能在派生类的成员函数中访问或调用)。
- 如果希望基类的成员能够被派生类继承并且毫无障碍地使用,那么这些成员只能声明为 public 或 protected;只有那些不希望在派生类中使用的成员才声明为 private。
- 如果希望基类的成员既不向外暴露(不能通过对象访问),还能在派生类中使用,那么只能声明为 protected。
注意:我们这里说的是基类的 private 成员不能在派生类中使用,并没有说基类的 private 成员不能被继承。实际上,基类的 private 成员是能够被继承的,并且(成员变量)会占用派生类对象的内存,它只是在派生类中不可见,导致无法使用罢了。private 成员的这种特性,能够很好的对派生类隐藏基类的实现,以体现面向对象的封装性
class Base
{
private:
int a;
protected:
int b;
public:
int c;
Base(int a,int b,int c):a(a),b(b),c(c){};
}
class Base1:protected Base
{
public:
void show()
{
cout<<"a"<<a<<endl;//error a是private不可访问
}
}
int main()
{
Base1 b;
b1.b;//error protected继承以后b变量还是protected属性
b1.c;//error protected继承以后c变量变成了protected属性
return 0;
}
继承中的构造与析构
私有继承-组合对象的区别
相同点:都可以表示,A中有B的关系
不同:私有继承中派生类可以访问基类的protected成员;
可以重写基类的虚函数
组合对象不可以,
尽可能使用组合对象,万不得已在使用私有继承
继承中的构造与析构调用原则
1、子类对象在创建时会首先调用父类的构造函数
2、父类构造函数执行结束后,执行子类的构造函数
3、当父类的构造函数有参数时,需要在子类的初始化列表中显示调用
4、析构函数调用的先后顺序与构造函数相反
继承和组合对象混搭时的构造与析构调用原则
1.先构造父类,再构造成员变量、最后构造自己
2.先析构自己,在析构成员变量、最后析构父类
成员覆盖问题
成员覆盖:
派生类中出现与基类中继承的成员变量名称相同的成员,会覆盖继承过来的成员(默认调用派生类中同名成员)
如何调用被覆盖成员:
1.类名::成员变量
2.对象名.类名::成员函数
派生类中的static关键字
1.基类定义的静态成员,将被所有派生类共享
2.根据静态成员自身的访问特性和派生类的继承方式,在类层次体系中具有不同的访问性质 (遵守派生类的访问控制)
3.访问方式 类名 :: 成员
对象.成员(对象可以是 该类定义的任何一个对象)
共享机制 : 任意对象共享 + 派生类共享
!!仍然要注意static定义的成员变量要在类外定义
多继承
多继承:
class 派生类名:<继承权限> 基类名,<继承权限> 基类名…
构造函数:
先构造基类后构造派生类;
基类构造顺序根据派生时顺序决定的;
多继承中的冲突
多继承中的名称冲突:
如果不同基类中出现相同的成员变量或者成员函数
那么在派生类中或外部调用时候 会出现二义性.
需要明确一下是调用那个类中的成员 用"类名::"处理
注意:在继承关系中,域解析符不能连用
多继承的二义性
如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性
原因,因为一个基类被继承多次的时候,会创建多个副本,出现名称冲突
解决:
虚继承(virtual)
当将一个基类声明为虚基类的时候,不管他在派生类中被继承多少次,该基类中的成员在该派生类中始终都只有一个副本。
声明方法:
class 派生类名:virtual <继承权限> 基类名
加入虚继承以后构造顺序
先构造虚继承的基类,然后是其他基类,最后是自己
注意!虚继承只会被构造一次,之后不会再被构造
class Base1
class Base2
class Derived1:public Base2,virtual public Base1
class Derived2:public Base2,virtual public Base1
class Top:public Derived1,virtual public Derived2
base1① base2② Derived1③ Derived2④ TOP⑤
构造顺序为1 2 4 2 3 5