Version 3.0
继承第八章
2
回顾
友元函数
友元类
操作符重载
3
目标
继承
访问控制
继承中的构造函数和析构函数
函数覆盖
4
继承继承是允许重用现有类来构造新类的特性基类方法和属性派生类基类方法
+
附加方法
5
优点
代码的可重用性-类库
重定义基类的成员函数
向派生类添加新成员
不需要了解核心技术的细节
6
单一继承 2-1
将类之间的相似性质联系起来
单一继承是从现有基类创建新类的过程
7
单一继承 2-2
处理某企业中雇员的程序
Employee
Manager
基类派生类派生自
使用 一个箭头从派生类指向基类
表示派生类引用基类的函数和数据,而基类没有访问派生类 的权限
8
基类和派生类
派生类的声明必须指定基类的名称
class Manager,public Employee
任何类都能用作基类
基类分为两种类型
– 直接基类
– 间接基类
9
直接基类和间接基类
直接基类
class A
{ };
class B,public A //A是 B的直接基类
{ };
间接基类
class A
{ };
class B,public A
{ };
class C,public B //A是 B的间接基类
{ };
10
继承的类型继承多级继承单一继承多重继承层次继承
11
单一继承
A
B
class A
{…};
class B,public A
{…};
12
多级继承
A
B
C class A{…};
class B,public A
{…};
class C,public B
{…};
13
层次继承
A
B C
D E
class A
{…};
class B,public A
{…};
class C,public A
{…};
class D,public C
{…};
class E,public C
{…};
14
多重继承
class A
{…};
class B
{…};
class C,public A,public B
{…};
A B
C
15
访问控制 3-1
派生类的函数
– 能够访问基类的保护和公有成员
派生类的对象
– 公有派生的类的对象能够访问基类的公有成员
– 私有和保护派生的类的对象不能访问基类的任何成员
16
访问控制 3-2
基类成员 公有继承 私有继承 保护继承公有 公有 私有 保护保护 保护 私有 保护私有 不被继承 不被继承 不被继承
17
访问控制 3-3
派生类不能访问基类的私有成员
公有继承不改变基类成员的访问级别
基类的另外两种访问级别使得所有继承的成员与基类成员(私有基类的私有成员或保护基类的保护成员)属于相同的访问级别
18
可访问性
基类的成员函数或数据何时能够被派生类的对象使用
– 无论类成员是私有、公有还是保护,它们总是能够由自身的成员函数访问
– 在类的外部定义的对象只能访问类的公有成员
19
访问基类成员
在继承中,
– 如果基类的成员是公有,那么派生类成员能够访问基类的成员
– 派生类成员不能访问基类的私有成员
20
protected访问控制说明符
保护部分类似于私有部分
– 只能被其所属类的成员访问
– 不能被类外部的对象或函数访问
– 区别只有在派生类中才会表现出来
21
基类成员的访问规则访问控制说明符 从自身类访问 从派生类访问 从类外访问
public 可以 可以 可以
protected 可以 可以 不可以
private 可以 不可以 不可以
22
访问控制说明符的规则
类成员总是能够被它们自己的类的方法访问
继承类能访问基类的公有或保护成员
公有成员可以在任何地方被访问
23
继承中的构造函数 3-1
先调用基类的构造函数,然后调用派生类的构造函数
class Base{
protected,
int a;
public:
Base(){a = 0;} //默认构造函数
Base(int c){ a = c;} //单参数构造函数
};
class Derived,public Base{
public:
Derived(),Base(){} //默认构造函数
Derived(int c),Base(c){} //单参数构造函数
};
24
继承中的构造函数 3-2
当声明派生类的对象时,
Derived obj;
它将会首先调用基类的构造函数,然后调用派生类的构造函数
基类构造函数是在派生类构造函数之后指定的,使用冒号分隔
Derived(),Base(){}
25
继承中的构造函数 3-3
在派生类的构造函数调用中显式选择基类的构造函数
Derived obj1(20);
调用基类中的相应构造函数
Derived(int c),Base(c);
26
继承中的析构函数
调用顺序与构造函数的调用顺序相反
首先调用派生类的析构函数,然后调用基类的析构函数
– 只有派生类的构造函数通过动态内存管理分配了内存空间时才需要定义析构函数
– 如果派生类的构造函数没有动态内存分配,那么派生类的析构函数可以是一个空函数
27
调用成员函数 2-1
派生类的成员函数可以和基类中的成员函数同名
– 用基类的对象调用函数时,将调用基类的函数
– 使用派生类的对象时,将调用派生类的函数
派生类的成员函数要调用基类的同名函数,
必须使用作用域解析操作符
28
调用成员函数 2-2
class Base
{
protected:
int ss;
public:
Base(){};
Base(int a)
{
ss = a;
}
int func()
{
return ss;
}
};
class Derived,public Base {
public:
Derived(){};
Derived(int b) {
ss = b;
}
int func() {
return Base::func();
}
};
void main() {
Base b1(10); //基类的对象
b1.func(); //调用基类的 func()
Derived a1; //派生类的对象
a1.func(); //调用派生类的
func()
}
29
函数 覆盖
派生类的函数覆盖基类的同名函数
– 通过派生类的对象调用时,执行派生类的函数
– 用基类的对象调用时,执行基类的函数
30
总结
继承
访问控制
继承中的构造函数和析构函数
函数覆盖