类的继承

来源:互联网 发布:儿童摄影后期制作软件 编辑:程序博客网 时间:2024/05/16 01:29

类的继承

继承是面向对象的三大特征之一,也是实现软件复用的重要手段。OC的继承具有单继承的特点,每个子类只有一个直接父类。
OC的继承通过父类的语法来实现,实现继承的类被称为子类,被继承的类被称为父类(有的也称基类、超类);继承关系的本质是一种“由一般到特殊”的关系,子类继承父类,子类是一种特殊的父类。从这个意义上看,扩展比继承更贴切。当子类扩展父类时,子类可以继承得到父类的如下东西:1、全部成员变量;2、全部方法(包括初始化方法)。
实例如下:

#import <Foundation/Foundation.h>


@interface FKFruit :NSObject

@property(nonatomic,assign)double w;

-(void)foo;

@end

#import "FKFruit.h"


@implementation FKFruit

@synthesize w;

-(void)foo

{

    NSLog(@"i am a apple %gg",w);

}

@end


#import <Foundation/Foundation.h>

#import "FKFruit.h"

@interface FKApple :FKFruit

@end


#import "FKApple.h"


@implementation FKApple


@end


#import <Foundation/Foundation.h>

#import "FKApple.h"

int main(int argc,constchar * argv[]) {

    @autoreleasepool {

        FKApple* a=[[FKApplealloc]init];

        a.w=56;

        [a foo];

    }

    return 0;

}


上面程序的main()函数创建了FKApple对象之后,可以访问FKApple对象的属性和方法,这就是继承的作用。OC语言摒弃了C++中难以理解的多继承特性,即每个类最多只有一个直接父类(可以有无限多个间接父类)。定义OC的类时都需要指定一个直接父类,NSObject是所有类的直接父类或间接父类。因此,所有类都可调用NSObject类定义的实例方法。这也是前面介绍KVC时能调用那些方法的秘密。
重写父类的方法:
大部分时候,子类总是以父类为基础,额外增加新的Field和方法。但是,有时候我们需要重写父类,例如,鸟类都包含了飞翔的方法,其中鸵鸟是一种特殊的鸟类,它是鸟的子类却不会飞,为此,鸵鸟需要重写鸟类的方法。代码如下:

#import <Foundation/Foundation.h>


@interface FKBird :NSObject

-(void)fly;

@end

#import "FKBird.h"


@implementation FKBird

-(void)fly

{

    NSLog(@"我在天空中自由的飞翔");

}

@end


#import <Foundation/Foundation.h>

#import "FKBird.h"

@interface FKOstric :FKBird


@end


#import "FKOstric.h"


@implementation FKOstric

-(void)fly

{

   NSLog(@"我只会跑");

}

@end

#import <Foundation/Foundation.h>

#import "FKOstric.h"

int main(int argc,constchar * argv[]) {

    @autoreleasepool {

       FKOstric* a=[[FKOstricalloc]init];

        [afly];

    }

   return0;

}


FKOstrich类继承了FKBird类,重写了FKBird的fly方法从上面FKOstric的接口部分可以看出,当子类要重写父类方法时,子类接口部分并不需要声明需要重写的方法,只要在类实现部分重写即可。这种子类包含与父类同名方法的现象被称为方法重写,也被称为方法覆盖。方法的重写必须注意子类与父类的方法签名关键字要完全相同。
super关键字:
如果需要在子类方法中调用父类被覆盖的实例方法,可使用super关键字来调用父类被覆盖的实例方法,这里我们强调用super关键字来调用父类被覆盖的实例方法,正如self不能出现在类方法中一样,super也不能出现在类方法中。
我们为上面的FKOstrich类添加一个方法,在这个方法中调用FKBird被覆盖的fly方法。
-(void)callOverrideMethod
{
【super fly】;
}
当子类继承父类时,子类可以获得父类中定义的成员变量。因此子类的接口部分不允许定义与父类接口部分重名的成员变量,无论采用哪种访问权限控制符。由于在类实现部分定义的成员变量对子类没有任何影响,所以无论是在子类的接口部分还是实现部分定义的成员变量,都可以与父类实现部分定义的成员变量成名。当子类实现部分定义了与父类重名的成员变量,子类的成员变量就会隐藏父类的成员变量。因此子类方法很难直接访问到父类的成员变量,此时可以通过调用父类的方法来访问父类中被隐藏的成员变量。代码如下

#import <Foundation/Foundation.h>

@interface FKPerent :NSObject

{

   int _a;

}

@property (nonatomic,assign)int a;

@end

上面的FKPerent父类定义了一个名为_a的成员变量,并为该成员变量定义了名为a的属性(该属性将对应于一组setter和getter方法);


#import "FKPerent.h"

@implementation FKPerent

@synthesize a=_a;

-(id)init

{

    if(self=[superinit])

    {

       self->_a=5;

    }

    return self;

}

@end

上面程序中使用了@property定义名为a的属性,并指定这个名为a的属性操作_a的成员变量;

#import <Foundation/Foundation.h>

#import"FKPerent.h"

@interface FKSub : FKPerent

-(void)acc;

@end


#import "FKSub.h"

@implementation FKSub

{

   int  _a;

}

-(id)init

{

   if(self=[superinit])

   {

      self->_a=7;

   }

    return self;

}

-(void)acc

{

    NSLog(@"子类中_a:%d",_a);

    NSLog(@"父类中_a:%d",super.a);

}

@end

上面为FKSub子类定义实现部分,实现部分会定义一个_a的成员变量,该成员变量将会隐藏父类的成员变量。

#import <Foundation/Foundation.h>

#import "FKSub.h"

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        FKSub* sub=[[FKSub allocinit];

        [sub acc];   

    }

    return 0;

}

从上面的代码可以看出,程序通过super关键字强制指定调用父类的a属性,通过这种方式可以访问到父类中被隐藏的成员变量从上面的运行结果可以看到:子类实现部分定义与父类同名的成员变量,只会隐藏父类的成员变量,但该对象内部依然有两块内存来保存_a的成员变量,一块内存保存在父类中被隐藏的_a成员变量,可以通过父类中定义的方法来访问;一块是保存在实现部分定义的_a成员变量,可以再子类方法中直接访问。

























































































































0 0
原创粉丝点击