🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
继承性是面向对象的重要概念之一, 子类能够继承父类的某些方法和成员变量。  作用域限定符为private的成员变量是不可以被继承的。  子类还可以重写父类的方法。  当然,这一切要从根类开始: 没有父类的类,位于类层次结构的最顶层,称为根(Root)类。 NSObject是层次结构的最顶端(也就是它上面没有任何类),因此称为根类。 如果使用术语,可以将类称为子类和父类。同样,也可以将类称为子类和超类。 需要注意的是,要在子类中直接使用实例变量,必须先在接口部分声明。 在实现部分声明和合成(synthesize)的实例变量是私有的,子类中并不能够直接访问, 需要明确定义或合成取值方法,才能访问实例变量的值。 继承的概念作用于整个继承链。 一定要理解以下事实:类的每个实例都拥有自己的实例变量,即使这些实例变量是继承来的。 找出正确的方法: 首先,检查该对象所属的类,以查看在该类中是否明确定义了一个具有指定名称的方法。 如果有,就使用这个方法。如果没有定义,就检查它的父类。 如果父类中有定义,就使用这个方法,否者,继续找寻。 直到找到根类也没有发现任何方法。 通过继承来扩展:添加新方法 继承通常用于扩展一个类。 @class指令: @class XYPoint; 或 ~~~ #import "XYPoint.h" ~~~ 使用@class指令提高了效率,因为编译器不需要引入和处理整个XYPoint.h文件(虽然它很小), 只需要知道XYPoint是一个类名。 如果需要引用XYPoint类的方法(在实现部分中),@class指令是不够的,因为编译器需要更多的消息。 说的通俗点:只引用了类就用@class不然就用#import。 在默认情况下,合成的设值方法只是简单地复制对象指针,而不是对象本身。 你可以合成另一种设值方法,而不是制作对象的副本。 为了了解继承性, 我们看看这样的一个场景:  一位刚学习面向对象的小菜,自从当上了班长,他就有的忙了,因为录入档案,需要描述和处理个人信息, 于是他定义了类Person: ~~~ @interface Person: NSObject { NSString* name; int age; NSDate birthDate; } -(NSString*) getInfo; @end ~~~ 新的校花School Beauty类: 一周以后, 小菜又遇到了新的需求, 他的几个表妹非要把各自学校的校花介绍给我他,烦恼呀! 需要描述和处理校花信息, 于是他又定义了一个新的类Beauty。  ~~~ @interface Beauty: NSObject { NSString* name; int age; NSDate birthDate; NSString* school; } -(NSString*) getInfo; @end ~~~ #### 小结 Beauty和Person两个类的结构太接近了,  后者只比前者多出一个属性school , 却要重复定义其它所有的内容。 Objective-C提供了解决类似问题的机制, 那就是类的继承。  @interface Beauty: Person { NSString* school; } 方法重写或者说是覆写方法: 不能通过继承删除或减少方法,但可以利用覆写来更改继承方法的定义。 新方法必须具有相同的返回类型,并且参数的数目与覆写的方法相同。 如果在不同的类中有名称相同的方法,则根据作为消息的接收者的类选择正确的方法。 #### 为什么要创建子类? 有如下3个理由: 1)希望继承一个类的方法,也许加入一些新的方法和或实例变量。 2)希望创建一个类的特别的版本。 3)希望通过覆写一个或多个方法来改变类的默认行为。 抽象类: 有时,创建类只是为了更容易创建子类。 因此,这些类名为抽象(abstract)类,或等价地称为抽象超类(abstract superclasses)。 在该类中定义方法和实例变量,但不期望任何人从该类创建实例。 注意: 子类不能继承父类中作用域限定符为@private的成员变量。  子类可以重写父类的方法,及命名与父类同名的成员变量。  下面再通过一个矩形类和正方形类的实例说明方法重写问题: Rectangle.h文件: ~~~ #import       @interface Rectangle: NSObject {       int width;       int height;   }      -(Rectangle*) initWithWidth: (int) w height: (int) h;   -(void) setWidth: (int) w;   -(void) setHeight: (int) h;   -(void) setWidth: (int) w height: (int) h;   -(int) width;   -(int) height;   -(void) print;   @end   ~~~ Rectangle.m文件: ~~~ #import "Rectangle.h"      @implementation Rectangle      -(Rectangle*) initWithWidth: (int) w height: (int) h {       self = [super init];          if ( self ) {           [self setWidth: w height: h];       }          return self;   }      -(void) setWidth: (int) w {       width = w;   }      -(void) setHeight: (int) h {       height = h;   }      -(void) setWidth: (int) w height: (int) h {       width = w;       height = h;   }      -(int) width {       return width;   }      -(int) height {       return  height;   }      -(void) print {       NSLog(@"width = %i, height = %i", width, height );   }   @end   ~~~ Square.h文件: ~~~ #import "Rectangle.h"      @interface Square: Rectangle   -(Square*) initWithSize: (int) s;   -(void) setSize: (int) s;   -(int) size;   @end   ~~~ Square.m文件: ~~~ #import "Square.h"      @implementation Square   -(Square*) initWithSize: (int) s {       self = [super init];          if ( self ) {           [self setSize: s];       }          return self;   }      -(void) setSize: (int) s {       width = s;       height = s;   }      -(int) size {       return width;   }      -(void) setWidth: (int) w {       [self setSize: w];   }      -(void) setHeight: (int) h {       [self setSize: h];   }   @end   ~~~ 调试用的main函数: ~~~ #import    #import "Square.h"   #import "Rectangle.h"      int main (int argc, const charchar * argv[]) {              Rectangle *rec = [[Rectangle alloc] initWithWidth: 10 height: 20];       Square *sq = [[Square alloc] initWithSize: 15];          NSLog(@"Rectangle: " );       [rec print];                  NSLog(@"Square: " );       [sq print];              [sq setWidth: 20];       NSLog(@"Square after change: " );       [sq print];          [rec release];       [sq release];                  return 0;   }   ~~~ 运行结果: ~~~ Rectangle: width = 10, height = 20 Square: width = 15, height = 15 Square after change: width = 20, height = 20 ~~~