【IOS 开发学习总结-OC-16】★★objective-c面向对象之——类的继承

类的继承

继承是面向对象的三大特征(封装,多态,继承)之一,也是实现软件复用的重要手段。objective-c 继承是单继承,每个子类只有一个父类。

objective-c 里子类继承父类的语法格式

@interface SubClassSuperClass
{
    // 成员变量定义
}
//方法定义部分
@end

被继承的类被称为父类。实现继承的类被称为子类。比如水果个橘子的关系,橘子继承了水果,水果是橘子的父类,橘子是水果的子类。子类是一种特殊的父类,也就是说父类包含的范围比子类包含的范围更大更宽泛。

继承关系,本质上是一种”有一般到特殊”的关系。所以,用继承来理解子类和父类的关系,其实是有些偏颇的。我个人感觉用延展来描述更合适,比如上面的例子,橘子类延展(延伸扩展)了水果类。

在子类延展父类时,子类可以继承得到的父类的如下东西:
1.全部成员变量。
2.全部方法(包括初始化方法)。

示例代码 :
FKFruit.h

#import <Foundation/Foundation.h>

@interface FKFruit : NSObject
@property (nonatomic , assign) double weight;
- (void) info;
@end

FKFruit.m

#import "FKFruit.h"

@implementation FKFruit
@synthesize weight;
- (void) info
{
    NSLog(@"我是一个水果!重%gg!" , weight);    
}
@end

FKApple.h

#import <Foundation/Foundation.h>
#import "FKFruit.h"

@interface FKApple : FKFruit
@end

FKApple.m

#import "FKApple.h"

@implementation FKApple
@end

FKAppleTest.m

#import "FKApple.h"

int main(int argc , char * argv[])
{
    @autoreleasepool{
        // 创建FKApple的对象
        FKApple* a = [[FKApple alloc] init];
        // FKApple对象本身没有weight属性
        // 因为FKApple的父类有weight属性,也可以访问Apple对象的weight属性
        a.weight = 56;
        // 调用FKApple对象的info方法
        [a info];
    }
}

编译运行结果:
2015-09-24 15:12:00.302 923[6965:357763] 我是一个水果!重56g!

类继承说法的纠偏

有的资料里介绍objective-c 的单继承时,可能会说 objective-c 类只有一个父类。这种说法不严谨。
应该说:objective-c 类只能有一个直接父类。但可以有无限个间接父类。比如:

@interface HXYFruit :HXYPlant {...} @end
@interface HXYApple :HXYFruit {...} @end

这其中,HXYApple的直接父类是HXYFruit,间接父类是HXYPlant。

NSObject 类 是所有类的父类

定义任何 OC 的类都需要指定一个直接父类,默认情况下会让自己的OC 类继承 NSObject 类,因此,NSObject 类是所有类的父类——直接父类或者间接父类。也是因为这样,所有 OC 对象都可以调用NSObject 类所定义的实例方法。这也是 KVC,KVO 机制能正常调用那些方法的原因。

重写父类的方法

多数情况下,子类都是以父类为基础进行延展,额外增加内容。但有种特殊情况:子类需要重写父类的方法。
比如,鸵鸟是鸟,但却不会飞,那么鸵鸟就需要重写鸟类中的方法。
示例程序:
FKBird.h

#import <Foundation/Foundation.h>

@interface FKBird: NSObject
- (void) fly;
@end

FKBird.m

#import <Foundation/Foundation.h>
#import "FKBird.h"

@implementation FKBird
// FKBird类的fly方法
- (void) fly
{
    NSLog(@"我在天空里自由自在地飞翔...");
}
@end

FKOstrich.h

#import <Foundation/Foundation.h>
#import "FKBird.h"

@interface FKOstrich: FKBird
- (void) callOverridedMethod;
@end

FKOstrich.m

#import <Foundation/Foundation.h>
#import "FKOstrich.h"

@implementation FKOstrich
// 重写父类的fly方法
- (void) fly
{
    NSLog(@"我只能在地上奔跑...");
}
- (void) callOverridedMethod
{
    // 在子类方法中通过super显式调用父类被覆盖的实例方法。
    [super fly];
}
@end

FKOstrichTest.m

#import "FKOstrich.h"

int main(int argc , char * argv[])
{
    @autoreleasepool{
        // 创建FKOstrich对象
        FKOstrich* os = [[FKOstrich alloc] init];
        // 执行FKOstrich对象的fly方法,将输出"我只能在地上奔跑..."
        [os fly];
        [os callOverridedMethod];
    }
}

编译运行结果:

2015-09-24 15:50:37.276 923[7359:376538] 我只能在地上奔跑...
2015-09-24 15:50:37.280 923[7359:376538] 我在天空里自由自在地飞翔...

这里就能看出,[os fly];不再执行父类中的 fly 方法,而是执行FKOstrich类中的方法。
方法重写/方法覆盖:
这种子类包含与父类同名方法的情况就被称为方法重写或方法覆盖。注意:方法重写一定要方法签名关键字完全相同,也就是说方法名和方法签名中形参标签都需要完全相同,否则就不算是方法重写。

★super关键字

如果需要在子类方法中调用父类被覆盖的实例方法,可以使用 super 关键字调用父类被覆盖的实例方法。比如上面代码中,

- (void) callOverridedMethod
{
    // 在子类方法中通过super显式调用父类被覆盖的实例方法。
    [super fly];
}

★**super关键字:**super是 objective-c提供的一个关键字,super 用于限定该对象调用它从父类继承得掉的属性或方法。
类方法的调用者只能是类本身,而不是对象,因此 super 关键字在类方法中也就失去了意义。 super 和 self 关键字一样,都不能出现在类方法中。

当子类继承父类的时,子类可以获得父类中定义的成员变量,因此子类接口父类接口部分的成员变量不能重名,不管父类中用什么访问控制符都不能定义重名变量。

需要特别指出的是,父类在类实现部分定义的成员变量对子类没有影响——因为类实现部分定义的成员变量限制在该类内部。反过来说也同样,子类中定义在类实现部分的成员变量,也不受父类接口部分定义的成员变量的影响。

当子类实现部分定义了与父类(接口部分)重名的成员变量,子类的成员变量就会隐藏父类的成员变量。因此,子类方法很难直接访问到父类的成员变量,此时可以通过调用父类的方法来访问父类中被隐藏的成员变量。
示例代码:
FKParent.h

#import <Foundation/Foundation.h>

@interface FKParent: NSObject
{
    int _a;
}
@property (nonatomic , assign) int a;
@end

FKParent.m

#import <Foundation/Foundation.h>
#import "FKParent.h"

@implementation FKParent
@synthesize a = _a;
- (id) init
{
    if(self = [super init])
    {
        self->_a = 5;
    }
    return self;
}
@end

FKSub.h

#import <Foundation/Foundation.h>
#import "FKParent.h"

@interface FKSub: FKParent
- (void) accessOwner;
@end

FKSub.m

#import <Foundation/Foundation.h>
#import "FKSub.h"

@implementation FKSub
{
    // 该成员变量将会隐藏父类的成员变量
    int _a;
}
- (id) init
{
    if(self = [super init])
    {
        self->_a = 7;
    }
    return self;
}
- (void) accessOwner
{
    // 直接访问的是当前类中的成员变量
    NSLog(@"子类中_a成员变量:%d" , _a);
    // 访问父类中被隐藏的成员变量
    NSLog(@"父类中被隐藏的_a成员变量:%d" , super.a);
}
@end

int main(int argc , char * argv[])
{
    @autoreleasepool{
        FKSub* sub = [[FKSub alloc] init];
        [sub accessOwner];
    }
}

编译运行结果为:

2015-09-24 17:42:13.881 923[7977:415250] 子类中_a成员变量:7
2015-09-24 17:42:13.882 923[7977:415250] 父类中被隐藏的_a成员变量:5

说明:可以看到子类实现部分定义与父类同名的成员变量,只是隐藏父类的成员变量,虽然程序只创建了一个 FKSub 对象,但该对象内部仍然有2块内存来保存_a的成员变量,一块保存父类中被隐藏的_a变量——可以通过父类中定义的方法访问;一块保存子类实现部分定义的_a成员变量,可以在子类方法中访问。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值