《ObjectiveC2.0程序设计第8章继承》由会员分享,可在线阅读,更多相关《ObjectiveC2.0程序设计第8章继承(53页珍藏版)》请在金锄头文库上搜索。
1、Objective-C-2.0Objective-C-2.0程序设程序设计计- -第第8 8章章- -继承继承武汉大学国际软件学院Objective-C 2.0程序设计第第8章章 继承继承重载方法重载方法8.3通过继承扩展:添加新的实例变量通过继承扩展:添加新的实例变量8.4通过继承扩展通过继承扩展添加新方法添加新方法8.2一切从根类开始一切从根类开始8.1抽象类抽象类8.5武汉大学国际软件学院Objective-C 2.0程序设计8.1 一切从根类开始一切从根类开始 在第三章“类,对象和方法”中学过父类的概念。父类自身也可以有父类。没有父类的类位于类层次结构的最顶层,称为根类。在Object
2、ive-C中,允许定义自己的根类,但通常你不想这么做,而是想要利用现有的类。至此我们所定义的类都属于名为NSObject的根类的派生类,这个根类通常如下在接口文件中指定:interface Fraction: NSObject.end 类Fraction就是从类NSObject派生来的。因为NSObject是层次结构的最顶端(也就是,它上面没有任何类),因此称为根类。类Fraction称为子或子类(subclass)。 从术语的角度而言,可以将一个类称作子类和父类。相似的,还可以将类称为子类和超类。 要定义一个新类(不是一个新的根类),该类都会继承一些属性。例如,很明显父类的所有实例变量和方法
3、都成为新类定义的一部分。这意味着子类可以直接访问这些方法和实例变量,就像直接在类定义中定义了一样。武汉大学国际软件学院Objective-C 2.0程序设计8.1 一切从根类开始一切从根类开始 举一个例子,有助于解释继承这个概念。 下面是一个名为ClassA的对象的声明,它有个方法initVar:interface ClassA: NSObjectint x;-(void) initVar;end initVar方法简单地把100赋值给ClassA的实例变量:implementation ClassA-(void) initVarx = 100;end武汉大学国际软件学院Objective-C
4、 2.0程序设计8.1 一切从根类开始一切从根类开始 现在再定义一个名为ClassB的类:interface ClassB: ClassA-(void) printVar;end声明的第一行:interface ClassB: ClassA说明ClassB并非NSObject的子类,而是ClassA的子类。所以,尽管ClassA的父类或超类是NSObject,但是ClassB的父类确实ClassA。 根类没有超类,而ClassB没有子类。因此ClassA是NSObject的子类,而ClassB是ClassA的子类,也是NSObject的子类。同样,NSObject是ClassA的超类,也是Cl
5、assB的超类。interface ClassB: ClassA-(void) printVar;endimplementation ClassB-(void) printVarNSLog (”x = %i”, x);end武汉大学国际软件学院Objective-C 2.0程序设计8.1 一切从根类开始一切从根类开始 虽然在ClassB中没有定义任何实例变量,但是可以通过printVar方法输出实例变量x的值。这是由于ClassB是ClassA的子类,因此它继承ClassA的所有实例变量。 通过把它集中放在一个完整的程序例子中,看看它的工作方式。 代码清单8-1-/ Simple exampl
6、e to illustrate inheritance#import / ClassA declaration and definitioninterface ClassA: NSObjectint x;-(void) initVar;endimplementation ClassA-(void) initVarx = 100;end武汉大学国际软件学院Objective-C 2.0程序设计8.1 一切从根类开始一切从根类开始/ Class B declaration and definitioninterface ClassB : ClassA-(void) printVar;endimpl
7、ementation ClassB-(void) printVarNSLog (”x = %i”, x);endint main (int argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;ClassB *b = ClassB alloc init;b initVar; / will use inherited methodb printVar; / reveal value of x;b release;pool drain;return 0;输出:x=100武汉大学国际软件学院Objective
8、-C 2.0程序设计8.1 一切从根类开始一切从根类开始 记住,继承的概念作用于整个继承链。因此,如果如下所示定义一个父类是ClassB的新类ClassC:interface ClassC: ClassB;.end那么ClassC将继承ClassB的所有方法和实例变量,同时也一次继承ClassA的所有方法和实例变量,它依次继承NSObject的所有方法和实例变量。 一定要理解一下的事实:类的每个实例都拥有自己的实例变量,即使这些实例变量是继承来的。因此,对象ClassC与对象ClassB具有完全不同的实例变量。武汉大学国际软件学院Objective-C 2.0程序设计8.1 一切从根类开始一切
9、从根类开始 找出正确的方法找出正确的方法 向对象发送消息时,你可能想知道如何选择正确的方法来应用到该对象。规则其实很简单。首先,检查该对象所属的类,以查看在该类中是否明确定义了一个具有指定名称的方法。如果有,就是用这个方法。如果这里没有定义,就检测它的父类。如果父类有定义,就用这个方法,否则继续寻找。 知道发现下面两种情况中的一种,才会检测父类:发现包含指定的方法的类,或者一直搜索到根类也没有发现任何方法。如果是第一种情况,就会停止查找,如果是第二种情况,说明存在问题,就会生成类似下面的警告消息:warning: ClassB may not respond to -inity 在这个例子中,
10、你无意中向类ClassB传递了一条名为inity的消息,编译器告知你:该类型的类不能响应这种方法。同样,这是在检测ClassB的方法及知道根类的父类的方法之后确定的。武汉大学国际软件学院Objective-C 2.0程序设计第第8章章 继承继承重载方法重载方法8.3通过继承扩展:添加新的实例变量通过继承扩展:添加新的实例变量8.4通过继承扩展通过继承扩展添加新方法添加新方法8.2抽象类抽象类8.5一切从根类开始一切从根类开始8.1武汉大学国际软件学院Objective-C 2.0程序设计8.2 通过继承扩展通过继承扩展添加新方法添加新方法 继承通常用于扩展一个类。举个例子,假设你刚接受一项任务
11、:开发一些处理2D图像对象的类。现在,只考虑矩形。实际上,回顾第4章“数据类型和表达式”的练习7,从一下例子开始interface部分:interface Rectangle: NSObjectint width;int height;property int width, height;-(int) area;-(int) perimeter;end 当前的方法可以设置矩形的宽与高,返回它们的值并计算其面积和周长。再添加一个方法,允许你使用相同的消息来设置矩形的宽度和长度值,如下:-(void) setWidth: (int) w andHeight: (int) h;武汉大学国际软件学院O
12、bjective-C 2.0程序设计8.2 通过继承扩展通过继承扩展添加新方法添加新方法 假设将新类声明键入名为Rectangle.h的文件。实现文件Rectangle.m将如下面所示:#import “Rectangle.h”implementation Rectanglesynthesize width, height;-(void) setWidth: (int) w andHeight: (int) hwidth = w;height = h;-(int) areareturn width * height;-(int) perimeterreturn (width + height)
13、 * 2;end武汉大学国际软件学院Objective-C 2.0程序设计8.2 通过继承扩展通过继承扩展添加新方法添加新方法 代码清单8-2显示了一个测试它的main例程。 代码清单8-2-#import “Rectangle h”#import int main (int argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;Rectangle *myRect = Rectangle alloc init;myRect setWidth: 5 andHeight: 8;NSLog ( w = %i,
14、 h = %i”,myRect.width, myRect.height);NSLog (”Area = %i, Perimeter = %i”,myRect area, myRect perimeter);myRect release;pool drain;return 0;输出:Rectangle: w = 5, h = 8Area = 40, Perimeter = 26武汉大学国际软件学院Objective-C 2.0程序设计8.2 通过继承扩展通过继承扩展添加新方法添加新方法 处理矩形之后,假设现在需要处理正方形。可以定义一个名为Square的新类,并在其中定义同Rectangle类
15、相似的方法。或者,认识到正方形只是长方形的特例。 因此,简单的处理方法就是定义一个名为Square的新类,并使它成为Rectangle的子类。这样除了定义自己的方法和变量之外,可以使用Rectangle类中的所有方法和变量。现在可能要添加的唯一方法可能是将正方形的边设置特定的值。代码清单8-3显示了Square类的接口文件和实现文件。 代码清单8-3 Square.h接口文件-#import “Rectangle.h”interface Square: Rectangle-(void) setSide: (int) s;-(int) side;end武汉大学国际软件学院Objective-C
16、2.0程序设计8.2 通过继承扩展通过继承扩展添加新方法添加新方法 代码清单8-3 Square.m实现文件-#import “Square.h”implementation Square: Rectangle-(void) setSide: (int) sself setWidth: s andHeight: s;-(int) sidereturn width;end 注意此处所作的工作。你将Square定义为Rectangle的子类,这是在头文件Rectangle.h中声明的。这里不必添加任何实例变量,但是添加了两个名为setSide和side的新方法。武汉大学国际软件学院Objectiv
17、e-C 2.0程序设计8.2 通过继承扩展通过继承扩展添加新方法添加新方法 代码清单8-3 测试程序-#import “Square.h”#import int main (int argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;Square *mySquare = Square alloc init;mySquare setSide: 5;NSLog (”Square s = %i”, mySquare side);NSLog (”Area = %i, Perimeter = %i”,mySqu
18、are area, mySquare perimeter);mySquare release;pool drain;return 0;输出:Square s = 5Area = 25, Perimeter = 20武汉大学国际软件学院Objective-C 2.0程序设计8.2.1 Point类和内存分配类和内存分配 Rectangle类只存储矩形大小。在实际的图形应用中,可能需要保存各种附加消息,如:矩形的填充色,线条颜色,窗口中的位置等待。可以方便的扩展这些类来处理这些情况。现在,处理矩形原点的概念。假设“原点”是指笛卡尔坐标系(x,y)中矩形左下角的位置。 可以扩展Rectangle类,
19、将矩形原点(x,y)保存为两个不同的值。在开发图形应用程序的过程中,要处理很多坐标,因此要定义一个名为XYPoint的类。#import interface XYPoint: NSObjectint x;int y;property int x, y;-(void) setX: (int) xVal andY: (int) yVal;end武汉大学国际软件学院Objective-C 2.0程序设计8.2.1 Point类和内存分配类和内存分配 回到Rectangle类。希望能够存储矩形的原点,所以,必须想Rectangle类的定义添加另一实例变量origin:interface Rectang
20、le: NSObjectint width;int height;XYPoint *origin;.武汉大学国际软件学院Objective-C 2.0程序设计8.2.2 class指令指令 现在可以设置矩形的宽,高及原点。首先,完整的看一下接口文件Rectangle.h:#import class XYPoint;interface Rectangle: NSObjectint width;int height;XYPoint *origin;property int width, height;-(XYPoint *) origin;-(void) setOrigin: (XYPoint *
21、) pt;-(void) setWidth: (int) w andHeight: (int) h-(int) area;-(int) perimeter;end武汉大学国际软件学院Objective-C 2.0程序设计8.2.2 class指令指令 代码清单8-4 Rectangle.m添加的方法-#import “XYPoint.h”-(void) setOrigin: (XYPoint *) ptorigin = pt;-(XYPoint *) originreturn origin;end武汉大学国际软件学院Objective-C 2.0程序设计8.2.2 class指令指令 代码清单
22、8-4 XYPoint.h接口文件-#import interface XYPoint: NSObjectint x;int y;property int x, y;-(void) setX: (int) xVal andY: (int) yVal;end武汉大学国际软件学院Objective-C 2.0程序设计8.2.2 class指令指令 代码清单8-4 XYPoint.m实现文件-#import “XYPoint.h”implementation XYPointsynthesize x, y;-(void) setX: (int) xVal andY: (int) yValx = xVa
23、l;y = yVal;end武汉大学国际软件学院Objective-C 2.0程序设计8.2.2 class指令指令 代码清单8-4 Rectangle.h接口文件-#import class XYPoint;interface Rectangle: NSObjectint width;int height;XYPoint *origin;property int width, height;-(XYPoint *) origin;-(void) setOrigin: (XYPoint *) pt;-(void) setWidth: (int) w andHeight: (int) h;-(i
24、nt) area;-(int) perimeter;end武汉大学国际软件学院Objective-C 2.0程序设计8.2.2 class指令指令 代码清单8-4 Rectangle.m实现文件-#import “Rectangle.h”implementation Rectanglesynthesize width, height;-(void) setWidth: (int) w andHeight: (int) hwidth = w;height = h;(void) setOrigin: (XYPoint *) ptorigin = pt;(int) areareturn width
25、* height;(int) perimeterreturn (width + height) * 2;(XYPoint *) originreturn origin;end武汉大学国际软件学院Objective-C 2.0程序设计8.2.3 具有对象的类具有对象的类 代码清单8-5 -#import “Rectangle.h”#import “XYPoint.h”int main (int argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;Rectangle *myRect = Rectangle
26、 alloc init;XYPoint *myPoint = XYPoint alloc init;myPoint setX: 100 andY: 200;myRect setWidth: 5 andHeight: 8;myRect.origin = myPoint;NSLog (”Origin at (%i, %i)”,myRect.origin.x, myRect.origin.y);myPoint setX: 50 andY: 50;NSLog (”Origin at (%i, %i)”,myRect.origin.x, myRect.origin.y);myRect release;m
27、yPoint release;pool drain;return 0;代码清单的输出结果是什么?输出:Origin at (100, 200)Origin at (50, 50)武汉大学国际软件学院Objective-C 2.0程序设计8.2.3 具有对象的类具有对象的类 将XYPoint myPoint从源程序中(100,200)改为(50,50)显然也改变了矩形的原点。如果回顾setOrigin:方法的定义,也许就会明白:-(void) setOrigin: (XYPoint *) ptorigin = pt; 当当 使用一下表达式调用使用一下表达式调用setOrigin方法时,方法时,m
28、yRect.origin = myPoint; myPoint的值作为参数传递给该方法。这个值指向存储的值作为参数传递给该方法。这个值指向存储XYPoint对象的内存,对象的内存,如图如图8-5所示。所示。x 100y 200myPoint 图8-5 武汉大学国际软件学院Objective-C 2.0程序设计8.2.3 具有对象的类具有对象的类 存储在myPoint(它是一个指向内存的指针)中的值被复制到在该方法中定义的本地变量中。现在pt与myPoint都引用内存中相同的数据。如图8-6所示:x 100y 200myPoint pt图8-6武汉大学国际软件学院Objective-C 2.0程
29、序设计8.2.3 具有对象的类具有对象的类 在方法中将Origin变量设置为pt时,pt中存储的指针被复制到实例变量origin,如图8-7所示:myPointptmyrectx 100y 200w 5h 8origin图8-7武汉大学国际软件学院Objective-C 2.0程序设计8.2.3 具有对象的类具有对象的类 因为myPoint和存储在myRect中的origin变量引用内存中的同一区域,所以随后将myPoint的值改为(50,50)时,矩形的原点也被更改。 避免这一问题的办法就是修改setOrigin:方法,以便分配自己的点并将原点设置为该点:-(void) setOrigin:
30、 (XYPoint *) ptorigin = XYPoint alloc init;origin setX: pt.x andY: pt.y; 这个方法首次分配并初始化一个新XYPoint。消息表达式 origin setX: pt.x andY: pt.y;将新分配的XYPoint设置为该方法参数的X,Y坐标。武汉大学国际软件学院Objective-C 2.0程序设计8.2.3 具有对象的类具有对象的类 setOrigin:方法的改变意味着每个rectangle实例现在都有它的origin XYPoint实例。既然 它负责为XYPoint分配内存,所以还应该负责释放该内存。当一个类包含其他
31、对象时,有时你希望拥有部分或全部对象。以矩形为例,它有自己的原点很合理。 但是如何释放origin占用的内存呢?释放矩形内存,并不同时释放为原点分配的内存。一种方式是在main中插入以下一行: myRect origin release;这样可以释放由原点方法返回的XYPoint对象。但是必须在Rectangle对象释放自己的内存之前释放XYPoint对象,因为在对象释放内存后它包含的所有实例都是无效的。因此,正确的代码顺序应该如下所示: myRect origin release; / Release the origins memorymyRect release; / Release t
32、he rectangles memory武汉大学国际软件学院Objective-C 2.0程序设计8.2.3 具有对象的类具有对象的类 使用修改后的方法,重新编辑和运行代码清单8-5,将生成错误信息。这里的问题是由于修改后的方法中使用了XYPoint类的一些方法,所以现在编译器需要的信息多于class所能提供的。在这个例子中,返回并用import代替这个指令,如下:#import “XYPoint.h” 代码清单8-5的输出结果为:Origin at (100, 200)Origin at (100, 200)武汉大学国际软件学院Objective-C 2.0程序设计第第8章章 继承继承通过继
33、承扩展:添加新的实例变量通过继承扩展:添加新的实例变量8.4重载方法重载方法8.3抽象类抽象类8.5一切从根类开始一切从根类开始8.1通过继承扩展通过继承扩展添加新方法添加新方法8.2武汉大学国际软件学院Objective-C 2.0程序设计8.3 重载方法重载方法 前面一节提到过,不能通过继承删除或减少方法。但可以利用常在来更改继承方法的定义。 看着两个类:ClassA和ClassB。假定要为ClassB编写自己的initVar方法。你已经知道ClassB将继承定义在ClassA中的initVar方法,但是是否可以新建一个同名的方法来替代继承的方法呢?答案是可以的,只要定义一个同名的新方法即
34、可。使用和父类相同的名称定义的方法来代替或重载了继承的定义。新方法必须具有相同的返回类型,并且参数的数目与重载的方法相同。 代码清单8-6展示了简单的例子来说明这个概念。武汉大学国际软件学院Objective-C 2.0程序设计8.3 重载方法重载方法 代码清单8-6-/ Overriding Methods#import / ClassA declaration and definitioninterface ClassA: NSObjectint x;-(void) initVar;endimplementation ClassA-(void) initVarx = 100;end武汉大学
35、国际软件学院Objective-C 2.0程序设计8.3 重载方法重载方法/ ClassB declaration and definitioninterface ClassB: ClassA-(void) initVar;-(void) printVar;endimplementation ClassB-(void) initVar / added methodx = 200;-(void) printVarNSLog (”x = %i”, x);end武汉大学国际软件学院Objective-C 2.0程序设计8.3 重载方法重载方法int main (int argc, char *arg
36、v)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;ClassB *b = ClassB alloc init;b initVar; / uses overriding method in Bb printVar; / reveal value of x;b release;pool drain;return 0;输出:x=200武汉大学国际软件学院Objective-C 2.0程序设计8.3 重载方法重载方法 显然消息 b initVar 导致使用定义在ClassB中的initVar方法,而不是使用CLassA中所定义的方法,前
37、一示例也是如此。如图所示。 类NSObject ClassA ClassB 实例变量 x x 方法 initVar initVar printVar武汉大学国际软件学院Objective-C 2.0程序设计8.3.1 选择哪个方法选择哪个方法 前面曾讲到系统如何上溯类层析查找应用于对象的方法。如果在不同的类中有名称相同的方法,则根据作为消息的接受者的类选择正确的方法。代码清单8-7使用与前面的ClassA和ClassB相同的类定义。 代码清单8-7-#import / insert definitions for ClassA and ClassB hereint main (int argc
38、, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;ClassA *a = ClassA alloc init;ClassB *b = ClassB alloc init;a initVar; / uses ClassA methoda printVar; / reveal value of x;b initVar; / use overriding ClassB methodb printVar; / reveal value of x;a release;b release;pool drain;retu
39、rn 0;武汉大学国际软件学院Objective-C 2.0程序设计8.3.1 选择哪个方法选择哪个方法 编译该程序时会得到以下警告消息:warning: ClassA may not respond to -printVar观察ClassA的声明:/ ClassA declaration and definitioninterface ClassA: NSObjectint x;-(void) initVar;end注意没有声明printVar方法。该方法声明并定义在ClassB中。因此,尽管ClassB对象及其派生类可以通过继承使用此方法,但ClassA对象却不能使用此方法,这是由于此方法
40、是沿着层次定义的。武汉大学国际软件学院Objective-C 2.0程序设计8.3.1 选择哪个方法选择哪个方法 回到例子,为ClassA添加一个printVar方法,以便显示实例变量的值。/ ClassA declaration and definitioninterface ClassA: NSObjectint x;-(void) initVar;-(void) printVar;endimplementation ClassA-(void) initVarx = 100;-(void) printVarNSLog (”x = %i”, x);endClassB的声明与定义保持不变。现在
41、,再次尝试编译并运行该程序。x = 100x = 200武汉大学国际软件学院Objective-C 2.0程序设计8.3.2 重载重载dealloc方法和关键字方法和关键字super 既然知道如何重载方法后,那么返回代码清单8-5,学习释放origin所占内存的更好方法。setOrigin:方法现在为自己的XYPoint origin对象分配内存,并且你负责释放它的内存。代码清单8-6中使用的方法就是使用一下语句让main释放该内存: myRect origin release;所以不必担心释放所有单独的类成员,可以重载继承的dealloc方法(从NSObject继承的)并在其中释放origi
42、n的内存。注意:不重载release方法,而是重载dealloc方法。在后续章节中你将了解,release方法有时释放对象使用的内存,有时却不。只有在其他人引用某个对象时,release才释放该对象所占用的内存。这通过调用该对象的dealloc方法来完成。实际上是由dealloc来释放内存。武汉大学国际软件学院Objective-C 2.0程序设计8.3.2 重载重载dealloc方法和关键字方法和关键字super 如果觉得重载dealloc方法,必须确保不仅要释放自己的实例变量所占用的内存,而且要释放继承的变量所占用的内存。 为此,需要利用关键字super,它引用消息接受者的父类。可以向su
43、per传递消息来执行重载方法。这就是此关键字最常见的用途。所以,在方法内部使用消息表达式 super release;时,调用定义在父类中的(或是父类继承的)release方法。此方法是对消息的接受者调用的,换言之,是对self调用。 因此,为Rectangle类重载dealloc方法的策略是,首先要释放origin所占的内存,然后调用父类的dealloc方法完成这项任务。这就释放了Rectangle对象自身所占的内存。下面是这个新方法:-(id) deallocif (origin)origin release;return super dealloc;武汉大学国际软件学院Objective
44、-C 2.0程序设计8.3.2 重载重载dealloc方法和关键字方法和关键字super 定义dealloc方法没有返回值。通过查看头文件可以了解这点。在dealloc方法中,进行一项测试来查看释放origin之前它释放非零。很可能从未设置矩形的原点。这种情况下,它拥有默认值0。然后调用父类的dealloc方法,如果没有重载,则Rectangle类将继承此方法。 应该指出,还可以如下更简单的编写这个dealloc方法:-(id) deallocorigin release;return super dealloc;因为可以向nil对象发送消息。此外,要注意此时release原点,而不是deal
45、loc它。如果没有其他人使用原点,release就会在原点调用dealloc方法。 有了这个新方法,现在只需要释放分配了内存的矩形,而不需担心其中包含的XYPoint对象。代码清单8-5所示的两条release消息:myRect release;myPoint release;足以释放在程序中分配内存的所有对象,包括setOrigin所创建的XYPoint对象。武汉大学国际软件学院Objective-C 2.0程序设计8.3.2 重载重载dealloc方法和关键字方法和关键字super 还有一个问题,如果在程序执行期间将单个Rectangle对象的原点设置为不同的值,那么再分配和制定新的原点之
46、前,必须释放旧原点所占的内存。例如,在下面的代码中:myRect.origin = startPoint;.myRect.origin = endPoint;.startPoint release;endPoint release;myRect release;XYPoint startPoint的副本保存在myRect的成员origin中,它从未被释放,这是因为它被储存在其中的第二个原点(endPoint)所重写了。根据新的release方法,只当释放矩形自身时才能释放原点。武汉大学国际软件学院Objective-C 2.0程序设计8.3.2 重载重载dealloc方法和关键字方法和关键字s
47、uper 需要确保在设置矩形的新原点之前释放旧的原点。这可以在setOrigin:方法中如下进行处理:-(void) setOrigin: (XYPoint *) ptif (origin)origin release;origin = XYPoint alloc init;origin setX: pt.x andY: pt.y;武汉大学国际软件学院Objective-C 2.0程序设计第第8章章 继承继承通过继承扩展:添加新的实例变量通过继承扩展:添加新的实例变量8.4抽象类抽象类8.5一切从根类开始一切从根类开始8.1通过继承扩展通过继承扩展添加新方法添加新方法8.2重载方法重载方法8.
48、3武汉大学国际软件学院Objective-C 2.0程序设计8.4 通过继承扩展:添加新的实例变量通过继承扩展:添加新的实例变量 你不仅可以添加新的方法来有效的扩展类的定义,还可以添加新的实例变量。以上两种情况的影响是累加的。不能通过减少继承方法或实例变量,只能添加,对于方法来说,可以添加或者是重载。 回到ClassA和ClassB类并做一些修改。可以如下ClassB添加一个新的实例变量。interface ClassB: ClassAint y;-(void) printVar;end 尽管根据前面的声明,ClassB看起来可能只有一个实例变量y,实际上它可能有2个:从ClassA继承的x和
49、自己的y武汉大学国际软件学院Objective-C 2.0程序设计8.4 通过继承扩展:添加新的实例变量通过继承扩展:添加新的实例变量 代码清单8-8-/ Extension of instance variables#import / Class A declaration and definitioninterface ClassA: NSObjectint x;-(void) initVar;endimplementation ClassA-(void) initVarx = 100;end武汉大学国际软件学院Objective-C 2.0程序设计8.4 通过继承扩展:添加新的实例变量通
50、过继承扩展:添加新的实例变量/ ClassB declaration and definitioninterface ClassB: ClassAint y;-(void) initVar;-(void) printVar;endimplementation ClassB-(void) initVarx = 200;y = 300;-(void) printVarNSLog (”x = %i”, x);NSLog (”y = %i”, y);end武汉大学国际软件学院Objective-C 2.0程序设计8.4 通过继承扩展:添加新的实例变量通过继承扩展:添加新的实例变量int main (i
51、nt argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;ClassB *b = ClassB alloc init;b initVar; / uses overriding method in ClassBb printVar; / reveal values of x and y;b release;pool drain;return 0;输出:x=200y=300武汉大学国际软件学院Objective-C 2.0程序设计第第8章章 继承继承一切从根类开始一切从根类开始8.1通过继承扩展通过继承扩展添加新方法添加新方法8.2重载方法重载方法8.3抽象类抽象类8.5通过继承扩展:添加新的实例变量通过继承扩展:添加新的实例变量8.4武汉大学国际软件学院Objective-C 2.0程序设计8.5 抽象类抽象类 有时候,创建类只是使创建子类更容易。因此,这些类名为抽象(abstract)类,或等价的称作抽象超类。方法和实例变量定义在该类中,但不期望任何人从该类创建实例。