[obj-c]继承(六)

前面第二贴的时候有
@interface Dog : NSObject
说到NSObject为Dog的父类。
而这就涉及到面向对象编程的一个重要原理,也就是继承。

在这里,可以称NSObject为根类。
根类的定义则是指最顶层的结构,没有父类的类。
而 Dog 则是所定义的类,属于NSObject根类的派生类。
换句话说可以说NSObject为父类,而Dog是他的子类。

附带代码来理解继承:_>testProduct_6
新建a类,父类为NSObject。
新建b类,父类为a类。
【建议:类名采用大写,本次仅为方便示例,不推荐这样命名】
QQ20140324-1
QQ20140324-2
QQ20140324-3

貌似忘记些内容,这里之前附带讲下 局部变量 和 static,extern
这两个忘记前面有没有详细说。所以在这里说下。

1、局部变量
局部变量是只能由声明它的函数或块中访问。
如图中value,可以看到编译器出现警告:use of undeclared identifier….
但是此时,只要将static int value = 0;拿到外面即可~~
QQ20140324-4

再来如下面代码:testStatic中的int i就是局部变量。
[objc]
//以下代码为a类中的

– (void) printValue : (int) tempInt{

NSLog(@"printValue _> : %d",tempInt);

}

– (void) testStatic{

static int i ;

i++;

[self printValue:i];

}
[/objc]

2、static
接着是static,在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量。
而static和其他基本数据类型的局部变量不同,在这里初始化是多余的,因为静态变量的初始值为0。

此外,静态变量只在程序开始执行时初始化一次,并且在多次调用方法时保存在这些数值。
可以试着 执行多次 testStatic ,并观察i的数值:
[objc]
2014-03-25 17:23:08.994 testProduct[9062:303] printValue _> : 1
2014-03-25 17:23:08.996 testProduct[9062:303] printValue _> : 2
2014-03-25 17:23:08.997 testProduct[9062:303] printValue _> : 3
[/objc]

3、extern
而extern声明的变量会在其它的地方被定义,这个地方可能是在同一份文件之中,或是在其它文件之中。
如下面代码:
[objc]
//先在b类中的写如下代码:
int x;
– (void) xpp{

x++;

}

//接着对a类的printValue,进行修改:
extern int x;
– (void) printValue : (int) tempInt{

NSLog(@"printValue _> : %d %d",tempInt,x);

}
[/objc]
然后先执行a类的printValue,再执行b类的xpp,再执行printValue,输出如下
[objc]
2014-03-25 17:36:14.749 testProduct[9167:303] printValue _> : 1 0
2014-03-25 17:36:14.751 testProduct[9167:303] printValue _> : 2 1
[/objc]

回到正题,继续写a类和b类:
[objc]
//a.h 部分

#import <Foundation/Foundation.h>

@interface a : NSObject
/**设置value值*/
– (void) setValue : (int) tempInt;

/**获取value值*/
– (int) getValue;

/**打印参数*/
– (void) printValue : (int) tempInt;

/**static例子*/
– (void) testStatic;

@end
[/objc]

[objc]
//a.m 部分

#import "a.h"

@implementation a

extern int x;
static int value = 0;
– (void) setValue : (int) tempInt{

value = tempInt;

}

– (int) getValue{

return value;

}

– (void) printValue : (int) tempInt{

NSLog(@"printValue _> : %d %d",tempInt,x);

}

– (void) testStatic{

static int i ;

i++;

[self printValue:i];

}

@end
[/objc]

下面为b类:
[objc]
#import "a.h"

@interface b : a {

int value3;
}

/**extern 例子*/
– (void) xpp;

@property int value2;

@end
[/objc]
[objc]
#import "b.h"

@implementation b
@synthesize value2;

int x;
– (void) xpp{

x++;

}

– (void) printValue : (int) tempInt{

NSLog(@"printValue B _> : %d",tempInt);

[super printValue:tempInt];

}

@end
[/objc]
不同于上面,b类用@property和@synthesize,
代替上面a类的setValue:和getValue方法【后面会详细说明】
在这里主要先看printValue:方法。

一、继承方法:
当b继承了a,他也就将有了a的一些方法和参数。
所以可以试着实例化b去用setValue:

二、覆写方法:
当b继承了a,他就不能通过继承删除或减少方法,
但是可以利用覆写来更改继承方法的定义。
如:
a类中,printValue:为输出tempInt,和b类的x。
b类中,由于继承的关系,printValue:方法被进行重写。
而作用则是输出tempInt,当然下面b类中,
使用到[super printValue:tempInt];
也就是调用父类中的printValue:方法。
所以b类的功能则是输出tempInt,并且还执行了a类的printValue:

关于super和self区别:
super是先在父类中找有没有printValue:
而self则是先找本类的。

由于写了这么多文字脑袋也有点犯迷糊,所以大家还是用代码实践比较清楚:
main.m内容如下:
[objc]
a *aClass = [[a alloc]init];
//static例子
for (int i = 0; i<3; i++) {
[aClass testStatic];
}
printf("\n");

//设置value为123,并打印出来
[aClass setValue:123];
[aClass printValue:[aClass getValue]];
printf("\n");

b *bClass = [[b alloc]init];
//extern例子
[bClass xpp];
//继承a方法setValue:
[bClass setValue:345];
//覆写a方法printValue:
[bClass printValue:[bClass getValue]];

printf("\n");
//设置value2的值
[bClass setValue2:123];
//点运算符访问属性,等价于上面的功能
bClass.value2 = 123;
[bClass printValue:bClass.value2];
[/objc]

关于点运算符访问属性。
如下面2个,可以使用点运算符编写以下等价表达式:
[objc]
bClass.value2 = 123;
[bClass setValue2:123];
[/objc]

由上面的2个类可以看出:

【引用下不知道哪里搜过来的一段话】
1、当只要定义一个非根类的新类,都会继承一些属性。
例如,父类的非私有实例变量和方法都会成为新类定义的一部分。
子类可以直接访问这些方法和实例变量,就像直接在类定义了这些子类一样。
子类中直接使用实例变量,必须现在接口部分声明。
2、在实现部分声明和synthesize的实例变量是私有的,子类中并不能够直接访问,
需要明确定义或合成取值方法,才能访问实例变量的值。
类的每个实例都拥有自己的实例变量,即时这些实例变量是继承来的。

额,貌似少了点什么….加入类c可能就比较清楚:
[objc]
#import "b.h"

@interface c : b

@end

[/objc]
[objc]
#import "c.h"

@implementation c

– (void) printValue : (int) tempInt{

//c没有定义任何实例变量,通过继承b的公有实例变量
NSLog(@"testValue3 _> : %d",value3);

}
@end
[/objc]
在这里,a\b\c 三个类关系就是这样的:
a为超类,a是b的父类,
b则是a的子类,b也是c的父类,
c则是b的子类,c则是a的孙类

main.m内容如下:
[objc]
c *cClass;
if (!cClass) {
cClass = [[c alloc]init];
}

[cClass printValue:0];
[/objc]
这里复习下if 结构和逻辑否定运算符!的使用
if (!cClass) 这个方法首先判断实例变量cClass是否为空

好吧这一次写的连我自己都觉得乱,以后有时间再进行修修补补的整理。
额,忘了还有个 抽象类

三、抽象类
抽象类[abstract class],
或叫抽象超类[abstract superclasses],是不允许实例化的类。
创建抽象类,只是为了更容易创建子类。
其声明方法存在而不去实现,它用于要创建一个体现某些基本行为的类,
并为该类声明方法,但不能在该类中实现该类的情况。
例如:NSOperation

81 thoughts on “[obj-c]继承(六)

Ilarpi进行回复 取消回复

电子邮件地址不会被公开。