• 《objective-c基础教程》学习笔记(五)—— 继承方法


      在上一篇博文中,我们将原先的纯C语言代码,编写成了用Objective-C(后面直接缩写成OC)的写法。使得代码在易读性上有明显提升,结构也更清晰。同时,也对面向对象的概念有了进一步的介绍和加深。

      但是,通过上一个例子,我们发现代码的冗余还是很大。像Circle,Rectangle和Egg的定义和实现方法几乎代码都是基本相同,只有个别地方不同。那么,有什么好方法来优化这些代码呢?今天这篇博文的重点就是要介绍继承这个方法,它将会有效的解决上面说的这个问题。

      正如你从亲生父母那里继承一些特性(头发的颜色,鼻子的形状等)一样,面向对象中的继承表明一个类从另外一个类——它的父类或超类(另一种叫法)中获取了某些特性。也就是说,Circle,Rectangle和Egg是从Shape类继承而来的,因此它们将获得Shape类的属性。

      那么,首先先给大家介绍下,在OC中,继承的语法格式。其实,在之前几篇博文中已经看到。声明一个类的时候,@interface Circle :NSObject。这里的冒号,就是继承的标示符,冒号后面的NSObject就是要继承的类,也就是说是父类(使用Cocoa框架的时候,要继承)。注:在OC中,不支持多继承

      好了,介绍了基本的继承的知识。接下来,我们就开始动手修改代码吧。我们的思路是:先定义一个总的Shape父类,定义好方法和属性,然后继承父类。

     1 #import <Foundation/Foundation.h>
     2 /* 1. enum 枚举类型 */
     3 //定义绘制图形的类型: 圆形,矩形,椭圆形
     4 typedef enum{
     5     kCircle,
     6     kRectangle,
     7     kEgg
     8 } ShapeType;
     9 
    10 //定义绘制图形的颜色: 红色,绿色和蓝色
    11 typedef enum{
    12     kRedColor,
    13     kGreenColor,
    14     kBlueColor
    15 } ShapeColor;
    16 
    17 /* 2. struct 结构体 */
    18 //定义图形的基本属性
    19 typedef struct{
    20     int x, y, width, height;
    21 } ShapeRect;
    22 
    23 NSString *colorName (ShapeColor fillColor)
    24 {
    25     switch(fillColor)
    26     {
    27         case kRedColor:
    28             return @"red";
    29             break;
    30         case kGreenColor:
    31             return @"green";
    32             break;
    33         case kBlueColor:
    34             return @"blue";
    35             break;
    36     }
    37 }
    38 
    39 /* 3. 定义Shape父类*/
    40 @interface Shape: NSObject{
    41     ShapeColor fillColor;
    42     ShapeRect bounds;
    43 }
    44 -(void) setFillColor:(ShapeColor) fillColor;
    45 -(void) setBounds:(ShapeRect) bounds;
    46 -(void) draw;
    47 @end //Shape
    48 
    49 /* 实现Shape父类 */
    50 @implementation Shape
    51 -(void) setFillColor:(ShapeColor) c
    52 {
    53     fillColor = c;
    54 }
    55 -(void) setBounds:(ShapeRect) b
    56 {
    57     bounds = b;
    58 }
    59 -(void) draw{
    60 }
    61 @end

      虽然draw方法什么功能也没实现,但是还是需要定义。以便Shape的所有子类可以通过它去实现各自的方法。

      然后,我们分别定义Circle,Rectangle和Egg子类:

     1 /*定义Circle,继承Shape父类*/
     2 @interface Circle: Shape
     3 @end
     4 
     5 /*定义Rectangle,继承Shape父类*/
     6 @interface Rectangle: Shape
     7 @end
     8 
     9 /*定义Egg,继承Shape父类*/
    10 @interface Egg: Shape
    11 @end

      接下来,对子类的draw方法进行实现,代码如下:

     1 @implementation Circle
     2 -(void) draw
     3 {
     4     NSLog(@"drawing a circle at (%d %d %d %d) in %@",
     5           bounds.x,
     6           bounds.y,
     7           bounds.height,
     8           bounds.width,
     9           colorName(fillColor));
    10 }
    11 @end
    12 
    13 @implementation Rectangle
    14 -(void) draw
    15 {
    16     NSLog(@"drawing a rectangle at (%d %d %d %d) in %@",
    17           bounds.x,
    18           bounds.y,
    19           bounds.height,
    20           bounds.width,
    21           colorName(fillColor));
    22 }
    23 @end
    24 
    25 @implementation Egg
    26 -(void) draw
    27 {
    28     NSLog(@"drawing an egg at (%d %d %d %d) in %@",
    29           bounds.x,
    30           bounds.y,
    31           bounds.height,
    32           bounds.width,
    33           colorName(fillColor));
    34 }
    35 @end

      通过用继承方法的修改,代码冗余问题明显感觉好了很多。Main() 主函数则完全不用修改,就可以运行,运行结果和之前的一样:

      在上面的例子中,我们在子类中重新实现了draw的方法,这个过程叫重写方法。执行的时候,如果子类中有重新定义父类中的方法,那么就会先去执行子类方法,父类中的同名方法则会别忽略。如果子类方法找不到,再去执行父类中定义的方法。

      在OC中,也提供了既可以重写方法实现,又可以调用父类自身实现的方法。为了调用继承的方法在父类中出现,需要使用super作为方法调用的目标。当我们向super发送信息的时候,实际上是请求OC向该类的父类发送消息。下面就修改一个使用super关键字的例子:

     1 @implementation Circle
     2 -(void) setFillColor:(ShapeColor) c
     3 {
     4     if(c == kRedColor)
     5     {
     6         c = kGreenColor;
     7     }
     8     [super setFillColor: c];
     9 }
    10 -(void) draw
    11 {
    12     NSLog(@"drawing a circle at (%d %d %d %d) in %@",
    13           bounds.x,
    14           bounds.y,
    15           bounds.height,
    16           bounds.width,
    17           colorName(fillColor));
    18 }
    19 @end

      我修改了下Circle类的实现方法,对setFillColor方法进行了重新。假如调用的颜色是红色,则返回的是绿色。在函数的结尾处,使用super关键字,通知父类,将新的颜色存储在fillColor变量中。

      好了,今天对继承的介绍就先在这告一段落吧。晚安,各位!

  • 相关阅读:
    Element学习
    top level element is not completed
    IntelliJ IDEA 使用心得与常用快捷键
    MVC下的DAO接口类和SERVICE接口类区别?
    Emmet初探2
    Servlet和Android网络交互基础(3)
    A-Frame WebVR开发新手教程
    重温java中的String,StringBuffer,StringBuilder类
    Android 常见面试题
    <html>
  • 原文地址:https://www.cnblogs.com/jianglan/p/4122133.html
Copyright © 2020-2023  润新知