继承是面向对象的三大特征之一,也是实现软件复用的重要手段。 Objective-C的继承具有单继承的特点,每个子类只有一个直接父类。

(1)继承的特点

Objective-C的继承通过“:父类”语法来实现 ,实现继承的子类被称为子类,被继承的类被称为父类,也称其为基类、超类。父类和子类的关系是一种“一般和特殊”的关系。例如,水果和苹果的关系,苹果继承了水果,苹果是水果的子类,苹果是一种特殊的水果。
因为子类是一种特殊的父类,因此,父类包含的范围总比子类包含的范围要大,所以可以认为父类是大类,而子类是小类。
Objective-C里子类继承父类的语法格式如下:

@interface SubClass: SuperClass {
	//成员变量定义
//方法定义部分

从上面的语法格式来看,我们在原来的类定义上增加了“:SuperClass”即表明该子类继承了SuperClass类
当子类扩展父类时,子类可以继承得到父类的如下东西:
(1)全部成员变量。
(2)全部方法(包括初始化方法)。

用下面的Fruit类的代码示范子类继承父类的特点:

#import <Foundation/Foundation.h>
@interface Fruit: NSObject { 
	double _weight;
- (void) setWeight: (double)weight;	
- (void) info;

下面是Fruit类的实现部分,实现部分负责实现info方法,程序如下:

#import "Fruit.h"
@implementation Fruit 
- (void) setWeight: (double)weight {
	_weight = weight;
- (void) info {
	NSLog(@"我是一个重%gg的水果!", self.weight);

接下来再定义该Fruit类的子类Apple,类接口部分如下:

#import <Foundation/Foundation.h>
#import "Fruit.h"
@interface Apple: Fruit

子类Apple的实现部分如下:

//由于Apple类本来只是一个没有定义任何属性和方法的空类,所以实现部分十分简单
#import "Apple.h"
@implementation Apple

下面写一个主函数程序来测试一下这个Apple类:

#import "Apple.h"
int main(int argc, char* argv[]) {
	@autoreleasepool {
		//创建Apple对象
		Apple* a = [[Apple alloc] init];
		//Apple对象本身没有自己的weight属性
		//因为Apple的父类有weight属性,所以也可以访问Apple对象的weight属性
    	[a setWeight:56];
    	//调用Apple对象的info方法
    	[a info];
	return 0;

上面程序的main()函数创建了Apple对象之后,可以访问Apple对象的weight属性和info方法,这表明Apple对象也具有weight属性和info方法,这就是继承的作用

由于Objective-C语言的继承具有单继承的特点,即每个子类只有一个直接父类。
所以下面的代码会引起编译错误:

//由于下面的代码会引起编译错误:
@interface SubClass: Base1, Base2, Base3 {
	//成员变量

另外,虽然Objective-C类只能有一个直接父类,但是却可以有无限个间接父类,例如:

//Plant是Fruit的直接父类
@interface Fruit: Plant {
	//成员变量
//Fruit是Apple的直接父类
@interface Apple: Fruit {
	//成员变量

上面的类定义中,Fruit是Apple的父类,Plant也是Apple的父类,区别是Fruit是Apple的直接父类,而Plant是Apple的间接父类

实际上,在定义任何Objective-C类时都需要指定一个直接父类,在默认情况下自定义的Objective-C类都需要继承NSObject类,因此,NSObject是所有类的父类,要么是其直接父类,要么是其间接父类,因此,所有的Objective-C对象都可以调用NSObject类所定义的实例方法

从子类角度来看,子类扩展了父类;但从父类角度来看,父类派生出了子类。

(2)重写父类的方法

子类扩展了父类,子类是一个特殊的父类。大部分时候,子类总是以父类为基础,额外增加新的成员变量和方法。但有些时候,子类需要重写父类的方法。例如,鸟类都包含了飞翔的方法,但其中鸵鸟是一种特殊的鸟类,因此,鸵鸟因该是鸟的子类,它也将从鸟类获得飞翔的方法,但是这个飞翔的方法明显不适合鸵鸟,因此,鸵鸟需要重写鸟类的方法。

下面的程序先定义了一个Bird类,该类的接口部分代码如下:

#import <Foundation/Foudation.h>
@interface Bird: NSObject
- (void) fly;

下面是Bird类的实现部分:

#import <Foundation/Foundation.h>
#import "Bird.h"
@implementation Brid
- (void) fly {
	NSLog(@"我可以在天空飞翔");

下面再定义一个Ostrich类,这个类扩展了Bird类,重写了Bird类的方法,Ostrich类的接口部分代码如下:

#import <Foundation/Foundation.h>
#import "Bird.h"
@interface Ostrich: Bird

从上面我们可以看到,当子类要重写父类方法时,子类接口部分并不需要重新声名所要重写的方法,只要在类实现部分直接重写该方法即可
下面是Ostrich类的实现部分代码:

#import <Foundation/Foundation.h>
#import "Ostrich.h"
@implementation Ostrich
//重写父类的fly方法
- (void) fly {
	NSLog(@"我只能在地上跑");

接下来写主函数来测试Ostrich类:

#import <Foundation/Foundation.h>
#import <Ostrich.h>
int main(int argc, cahr* argv[]) {
	@autoreleasepool {
		//创建Ostrich对象
		Ostrich* b = [[Ostrich alloc] init];		
		//执行Ostrich对象的fly方法,执行后输出“我只能在地上跑”
		[b fly];
	return 0;

从上面的程序可以看到执行[b fly]时,不再执行Bird类的fly方法,而是执行Ostrich类的fly方法
这种子类包含父类方法同名的现象被称为方法重写,也被称为方法覆盖
方法重写必须注意方法签名关键字要完全相同,也就是方法名和方法签名中的形参标签都需要完全相同,否则就不能算方法重写

(3)super关键字

super是Objective-C提供的一个关键字,super用于限定该对象调用它从父类继承得到的属性或方法

如果需要在子类方法中调用父类被覆盖的方法,则可以使用super关键字来调用父类被覆盖的方法。我们可以对上面的Ostrich类中添加一个方法,在这个方法中调用Bird被覆盖的fly方法,该方法代码如下:

-void)Method {
	//在子类方法中通过super显式调用父类被覆盖的fly方法
	[super fly];

通过Method方法的帮助,就可以让Ostrich对象既可以调用自己重写的fly方法,也可以调用Bird类中被覆盖的fly方法(调用Method方法即可实现)

super既可出现在类方法中,也可以出现在实例方法中。在类方法中使用super调用父类的方法时,被调用的父类方法只能是类方法;在实例方法中使用super调用父类的方法时,被调用的父类方法只能是实例方法

当子类继承父类时,子类可以获得父类中定义的成员变量,因此,子类接口部分不允许定义与父类接口部分重名的成员变量。

//如果在子类接口这样定义与父类接口部分重名的成员变量,程序就会报错
//父类接口部分代码如下:
#import <Foundation/Foundation.h>
@interface Base: NSObject {
	@private
	int _a;
//子类接口部分代码如下:
#import <Foundation/Foundation.h>
#import "Base.h"
@interface SubClass: Base {
	int _a;//与父类接口部分成员变量重名

因此,无论父类接口部分的成员变量使用何种访问控制符限制,子类接口部分定义的成员变量都不允许与父类接口部分定义的成员变量重名

而在类实现部分定义的成员变量将被限制在该类的内部,因此,父类在类实现部分定义的成员变量对子类没有任何影响。无论是接口部分还是实现部分,子类定义的成员变量都可以与父类实现部分定义的成员变量同名

反过来也一样,在子类实现部分定义的成员变量也不受父类接口部分定义的成员变量的影响。也就是说,即使在父类的接口部分定义了名为 _a 的成员变量,子类的实现部分依然可以定义名为 _a的成员变量。

当子类实现部分定义了与父类重名的成员变量时,子类的成员变量就会隐藏父类的成员变量。因此,子类方法很难直接访问到父类的成员变量,此时可通过调用父类的方法来访问父类

下面我们可以创造一种情况,代码如下:

//父类接口部分代码如下:
#import <Foundation/Foundation.h>
@interface Parent: NSObject {
	int _a;
- (void) setA: (int)a;//setter
- (int) a;//getter
//父类Parent的实现部分如下:
#import <Foundation/Foundation.h>
#import "Parent.h"
@implementation Parent
- (void) setA: (int)a {
	_a = a;
- (int) a {
	return _a;
//重写init初始化
- (id) init {
	if (self = [super init]) {
		self -> _a = 5;
	return self;
//接着定义一个Parent的子类,该子类的接口部分代码如下:
#import <Foundation/Foundation.h>
#import "Parent.h"
@interface Sub: Parent
- (void) accessOwner;
//接着写子类Sub的实现部分,该实现部分会定义一个名为_a的成员变量,该成员变量会隐藏父类的成员变量
#import <Foundation/Foundation.h>
#import "Sub.h"
@implementation Sub {
	//该成员变量会隐藏父类的成员变量
	int _a;
//重写init初始化
- (id) init {
	if (self = [super init]) {
		self -> _a = 7;
	return self;
- (void) accessOwner {
	//直接访问的是当前类中的成员变量
	NSLog(@"子类中_a成员变量的值为:%d", _a);
	//访问父类中被隐藏的成员变量
	NSLog(@"父类中被隐藏的_a成员变量的值为:%d", super.a);	
//下面是主函数部分:
#import <Foundation/Foundation.h>
#import "Sub.h"
int main(int argc, char* argv[]) {
	@autoreleasepool {
		Sub* c = [[Sub alloc] init];
		[c accessOwner];
	return 0;
最终的运行结果为:
子类中_a成员变量的值为:7
父类中被隐藏的_a成员变量的值为:5

从上方的代码中可以看出程序通过 super 关键字强制指定调用父类的 _a 属性(实际上就是获取 getter 方法返回值),通过这种方式可以访问到父类中被隐藏的成员变量。

从上面的运行结果可以看到,在子类实现部分定义与父类同名的成员变量,只是隐藏父类的成员变量,虽然程序只是创建了一个 Sub 对象,但该对象内部依然有两块内存来保存 a成员变量,其中一块内存保存父类中被隐藏的 _a 成员变量,可以通过父类中定义的方法来访问; 另一块内存保存子类实现部分定义的 _a 成员变量,可以在子类方法中直接访问。

 编写面向对象的程序的时候,和对象之间存在一定的关系  处理和对象之间的关系的时候,尤其需要注意OOP的两个方面:  一个就是继承,创建一个新的时候,通常需要定义新以区别于  其他和现有,使用继承可以定义一个具有父所有功能的新。  现在有两个:  @interface Circle:NSObject     ShapeColor fillCo 一个新可以从已有的派生出来,这个过程称为继承,新称为子,已有的称为父或超。 2.继承的特点: 实现代码重用:子可以重用父的实例变量和方法。 子可以增加实力变量和方法扩展父,但不能重载父的实例变量 所有型都有一个公共基:NSObject 3.NSObject      允许定义自己的根,但通常不这样做,而是利用现有的
一、概念:面向对象提供了继承语法,能大大简化代码。把公共的方法和实例变量写在父里,子字需要写自己独有的实例变量和方法即可。继承既能保证的完整,又能简化代码。二、继承的特点:OC 中只允许单继承。 没有父成为根,OC中的根是NSObject(祖宗)。 继承的内容:所有实例变量和方法。 如果子不满意父方法的实现,可以重写(overwrite)父的方法。三、方法调度机制:当代码
我们可以通过对父继承实现一定的扩展,继承主要有以下几种典型的用法: 1 代码复用。.两个有部分相同的代码,那相同的部分我们就没必要去复制粘贴,完全就可以把公共的部分放在父中,子继承,只需要实现一次相同的部分即可。 2.创建协议。父为子规定了一些方法,哪怕是空的,但我们可以默认为父为他的子创建了一种协议,当不同的实现同名的方法的时候,程序就可以采用多态的设计。 - (void) setYear: (int) iYear; - (void) primalSetData: (int)iYear :(int)iMonth :(int)iDay; - (void) setData: (int)Year iMonth:(int)iMonth iDay:(int)iDay;
今天学习了Objective-C中有关继承的知识。先纪录如下: 1)OOP编程中有两个技术 用于描述或对象与对象之间的关系;一个是继承 另一个是复合。 2)在Objective-C中每个子只能有一个超,这一点与c++不同。 3)方法调度程序       该调度程序的功能非常重要,当一个对象接收到一个消息后,调度程序会在接收对象的中查找与该消息对应的方法,如果没有找到调度程序就...
继承方法 1.保留父 对该方法的实现,(不用重写)2.案子重写之后的方式来实现,(重写,忽视父的实现)3.既有父对该方法的实现,又有子对该方法的实现. 继承的上层: 父继承的下层:子 继承是单向的,不能相互继承