类的继承
保持已有类的特性而构造新类的过程称为继承;
实现设计与代码的重用.
在已有类的基础上新增自己的特性而产生新类的过程称为派生
当新的问题出现,原有程序无法解决(或不能完全解决)时,需要对原有程序进行改造
派生类的构成
吸收基类成员
- 默认情况下派生类包含了全部基类中除构造和析构函数之外的所有成员;
- C++11规定可以用using语句继承基类构造函数。
改造基类成员
- 如果派生类声明了一个和某基类成员同名的新成员,派生的新成员就隐藏或覆盖了外层同名成员
添加新的成员
- 派生类增加新成员使派生类在功能上有所发展
继承方式
区别
派生类成员和派生类对象对基类成员的访问权限
三种继承方式的共同点:
- 派生类中的成员函数:可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员(唯一的限制);
- 对基类的private成员的唯一访问方式就是调用基类自身的私有成员访问接口,接口是public或者protected成员.
公有继承(public)
- 在派生类中身份不变;
- 通过派生类的对象:只能访问基类public成员。
私有继承(private)
- 全部私有化;
- 通过派生类的对象:不能直接访问从基类继承的任何成员。
保护继承(protected)
- public成员被保护起来;
- 通过派生类的对象:不能直接访问从基类继承的任何成员。
protected 成员的特点与作用
- 对建立其所在类对象的模块来说,它与 private 成员的性质相同。
- 对于其派生类成员函数来说,它与 public 成员的性质相同。
- 既实现了数据隐藏,又方便继承,实现代码重用。
- 适应于基类和派生类均为同一团队所设计时;
继承的实用性总结:
- 对于派生类内部来说:基类私有成员被保护了,其他的都能看;
- 对于派生类对象来说:
- 能使用基类public成员------>public继承时;
- 不能使用基类public成员---->private和protected继承时;
类型转换
公有派生类对象可以被当作基类的对象使用,反之则不可。
- 派生类的对象可以隐含转换为基类对象;
- 派生类的对象可以初始化基类的引用;
- 派生类的指针可以隐含转换为基类的指针。
通过基类对象名、指针只能使用从基类继承的成员。
指向基类类型的指针,你给它派生类对象的地址,只会从派生类中寻找基类传下来的那些成员,派生类的新成员会被忽略。
派生类的构造函数
派生类的构造函数需要给基类的构造函数传递参数;
p.s.当基类有默认构造函数时,也可以不传参数;
派生类名::派生类名(形参表):
基类名1(参数), 基类名2(参数), ..., 基类名n(参数),
本类成员(含对象成员)初始化列表
{
//其他初始化
};
class Derived: public Base2, public Base1, public Base3 {
public:
Derived(int a, int b, int c, int d): Base1(a), member2(d), member1(c),
Base2(b)
//此处的次序与构造函数的执行次序无关
{ }
private:
Base1 member1;
Base2 member2;
Base3 member3;
}
派生类复制构造函数
给基类传派生类对象的引用;
Line::Line(const Line &p): Point(p) {…}
访问从基类继承的成员
当派生类与基类中有相同成员时:
- 通过派生类对象使用的是派生类中的同名成员;(同名隐藏)
- 如要通过派生类对象访问基类中被隐藏的同名成员,应使用基类名和作用域操作符(::)来限定
// Derived 继承自 Base1 和 Base2
Derived d;
Derived *p = &d;
d.fun();
d.Base1::fun();
p->Base2::fun();
二义性问题
- 如果从不同基类继承了同名成员,但是在派生类中没有定义同名成员,“派生类对象名或引用名.成员名”、“派生类指针->成员名”访问成员存在二义性问题;
- 解决方式:用类名限定
Derived d;
d.Base1::fun0();
d.Base2::fun0();
虚基类
解决的问题
当派生类从多个基类派生,而这些基类又共同基类,则在访问此共同基类中的成员时,将产生冗余,并有可能因冗余带来不一致性
作用
- 主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题
- 为最远的派生类提供唯一的基类成员,而不重复产生多次复制
在第一级继承时就要将共同基类设计为虚基类
class B...
class B1:virtual public B
class B2:virtual public B
class b:public B1,public B1
- 建立对象时所指定的类称为最远派生类;
- 所有派生类要在初始化列表中给虚基类传参数;(没传则用默认构造函数)
- 在建立对象时,只有最远派生类的构造函数调用虚基类的构造函数,其他类对虚基类构造函数的调用被忽略。
b(int var) : B(var), B1(var), B2(var)