黑马程序员:Objective-C中的继承与复合


----------- android培训java培训、java学习型技术博客、期待与您交流! ------------



今天学习了Objective-C中有关类继承的知识。先纪录如下:

1)OOP编程中有两个技术 用于描述类与类或对象与对象之间的关系;一个是继承另一个是复合。

2)在Objective-C中每个子类只能有一个超类,这一点与c++不同。

3)方法调度程序

    该调度程序的功能非常重要,当一个对象接收到一个消息后,调度程序会在接收对象的类中查找与该消息对应的方法,如果没有找到调度程序就进入超类中查找,如还是没有则根据继承规则继续向上游查找,如果到类继承关系的最顶层(NSObject类)还没有找到该消息的方法时就报运行时错误(编译时会报警告)。

4)self与 super

    a) self是一个隐含的指针,指向接收消息的对象的指针。消息所调用的方法使用该指针参数查找它们要使用的实例     变量。

    b)super来之哪里呢?它不是参数也不是实例变量,而是由Objective-C编译器提供的某种神奇的功能。向super发消息时,实际上是在请求Objective-C向该类的超类发送消息。如果超类中没有定义的消息,Objective-C将按照继承的通常规则在继承链中查找。

5)每个类都是NSObject的子类,而NSObject中定义了isa实例变量,所以每个类的对象(实例)第一实例变量就是isa,不过它是隐藏的。

 

在Objective-C中复合是如何实现的?它是通过在类中声明一个指向另一个类对象的指针作为实例变量,从而将这两个类进行复合。

1)使用new创建对象的时候,实际发生了两个步骤;第一个步骤,为对象分配内存,也就是说对象获得存储其实例变量的内存块;第二步,就是自动调用init方法,初始化对象使其处于可用状态。没有被初始化的指针都使nil.

 

 

 头文件内容如下:

#import <Foundation/Foundation.h>
 
@interface Engine:NSObject
@end //Engine
 
@interface Tire:NSObject
@end // Tire
 
@interface Car:NSObject
{
Engine*carEngine;
Tire *carTire[4];
}
-(void)print;
@end //Car


   

源文件内容如下:

#import "carPart.h"
 
@implementation Engine
-(NSString *)description
{
return(@"I am a Engine!");
}
@end //Engine
 
@implementation Tire
-(NSString *)description
{
return(@"I am a Tire!");
}
@end //Tire
 
@implementationCar 
//注意init方法的返回值类型是id,即是一个指向对象的指针,该函数在用new创建对象时自动被调用
-(id) init
{
//需要先调用超类的init函数,并将结果赋给self;init调用会依据继承关系一直回调用到类关系的顶层。
if(self = [super init])
{
carEngine =[Engine new];
 
carTire[0] = [Tire new];
carTire[1] = [Tire new];
carTire[2] = [Tire new];
carTire[3] = [Tire new];
}
 
//别忘了返回初始化后的对象指针
return self;
 
}
 
-(void)print
{
//注意双引号字符串前必须加@符号
NSLog(@"%@",[carEnginedescription]);
NSLog(@"%@",[carTire[0] description]);
NSLog(@"%@",[carTire[1] description]);
NSLog(@"%@",[carTire[2] description]);
NSLog(@"%@",[carTire[3] description]);
}
@end //Car
 
int main(int argc, constchar *argv[])
{
Car * carPart =[Car new];
[carPartprint];
}
 


 

2)我们看到上面的程序发现,该结构比较死,如果我们能随时可以更换发动机和轮胎那么我们程序的机构就更灵活了。也许你发现了,这样修改是否像策略模式呢!

 

在这里使用存取方法来实现上述想法。

a)存取方法:用来读出或改变对象特定属性的方法。

存取方法分为setter getter方法,一般setter方法前都是用"set"作为前缀;getter方法前不能有"get"前缀setter方法的命名基础是“set”属性名;而 getter方法命名的基础就是属性名

b)cocoa中有“get”前缀的方法是有特殊意义的,如果“get”前缀出现在cocoa方法名称中,这就意味着该函数的返回值是通过该函数的参数返回的。

c)setter方法和getter方法一般上成对出现的,当然可以不成对出现,如对于只读特性只有getter方法,对于密码特性只有setter方法。

d)在Objective-C中所有对象之间的交互都是通过指针实现的。

修改后的程序如下:

 头文件内容如下:

 

/*
 * Composition2.h
 * Composition2
 *
 * Created by yan li on 8/26/09.
 * Copyright 2009 cat. All rights reserved.
 *
 */
 
#import <Foundation/Foundation.h>
 
@interface Engine:NSObject
@end //Engine
 
@interface Tire:NSObject
@end // Tire
 
@interface Car:NSObject
{
Engine*carEngine;
Tire *carTire[4];
}
-(Engine*)carEngine;
-(void)setCarEngine:(Engine*)engine;
 
-(Tire*)carTireAtIndex:(int)index;
-(void)setCarTire:(Tire*)tire 
     AtIndex:(int)index;
 
-(void)print;
@end //Car
 


源文件内容如下:

 

//#import <Foundation/Foundation.h>
#import "Composition2.h"
 
@implementation Engine
-(NSString *)description
{
return(@"I am a Engine!");
}
@end //Engine
 
@implementation Tire
-(NSString *)description
{
return(@"I am a Tire!");
}
@end //Tire
 
@implementationCar 
/*//注意init方法的返回值类型是id,即是一个指向对象的指针,该函数在用new创建对象时自动被调用
-(id) init
{
//需要先调用超类的init函数,并将结果赋给self;init调用会依据继承关系一直回调用到类关系的顶层。
if(self =[super init])
{
carEngine =[Engine new];
 
carTire[0] =[Tire new];
carTire[1] =[Tire new];
carTire[2] =[Tire new];
carTire[3] =[Tire new];
}
 
//别忘了返回初始化后的对象指针
return self;
 
}*/
-(Engine*)carEngine
{
return carEngine;
}
 
-(void)setCarEngine:(Engine*)engine
{
carEngine =engine;
}
 
-(Tire*)carTireAtIndex:(int)index
{
if(index > 3 || index < 0)
{
NSLog(@"index error");
exit(1);
}
return (carTire[index]);
}
 
//注意下面这个函数的名称的写法,比较独特以后会详细介绍
-(void)setCarTire:(Tire*)tire AtIndex:(int)index
{
//一下if 语句是防御性编程
if(index > 3 || index < 0)
{
NSLog(@"index error");
exit(1);
}
carTire[index]= tire;
}
-(void)print
{
//注意双引号字符串前必须加@符号
NSLog(@"%@",[carEngine description]);
NSLog(@"%@",[carTire[0] description]);
NSLog(@"%@",[carTire[1] description]);
NSLog(@"%@",[carTire[2] description]);
NSLog(@"%@",[carTire[3] description]);
 
}
@end //Car
 
int main(int argc, constchar *argv[])
{
Car * carPart = [Carnew];
 
// 在Car对象的调用代码中,使用对象属性setter方法随时修改对象的属性。
Engine *engine = [Enginenew];
[carPart setCarEngine:engine];
 
int i;
//循环控制数要确认好
for(i = 0; i< 4; i++)
{
Tire *tire =[Tire new];
[carPartsetCarTire:tire AtIndex:i];
}
 
[carPartprint];
 
return 0;
}


----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

详情请查看:http://edu.csdn.net/heima

 

 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值