Objective-C学习篇03—继承
大纲:
继承的基本概念
自定义初始化方法
便利构造器方法
重写description方法
一 继承基本概念
程序里的对象和"人类"的对象是一样的,高富帅继承了父母,自然就拥有了父母所有的资源,子类继承了父类同样就拥有了父类所有的属性和方法,当然,父类私有的除外.
我们在定义一个新的类的时候,常常会遇到要定义的新类是某个类的扩展或者是某个类的修正等这种情况.如果能够在已有的类的基础上定义新类,那么新类的定义将会变得十分简便.
类似于这种,通过扩展或者修改既有的类来定义新类的方法就叫做继承(inheritance).在继承关系中,被继承的类(原有的类)就成为父类(superclass),通过这种继承关系得到的新类就叫做子类(subclass).
上面也讲到,继承意味着子类可以得到父类所有的属性和方法,除此之外,子类还可以为新类:
1. 添加新的实例变量
2. 追加新的自己特有的方法
3. 重新定义父类中的方法
当然,如果子类中只追加新的实例变量而不变更方法则没有任何意义.可以说,继承的目的就是要让子类能做更多父类做不了的事(扩展方法).子类中重新定义父类的方法叫做重写.分为完全重写和不完全重写,这些在后面都会讲到.
继承的优点:1> 省略了大量重复的代码 2>建立起类与类之间的关系.
缺点在于类间耦合性太强
二 OC中的继承关系
1. 在OC中,一旦建立了继承关系,子类就可以使用父类中所有的实例变量和方法.(父类私有的除外)
2. OC中的继承是单继承关系,一个类只能有一个父类,但是一个类可以有n个子类.
3. OC中的继承关系一定是合理的
4. OC中继承是单根类继承,所有类的祖宗类都是NSObject,NSObject是所有类的基类或者根类
5. A 继承自 B 可以说,A是B的子类,或者说A类是由B类衍生的,衍生类
6. 使用继承的好处:如果一些类在定义的时候,发现他们有很多的实例变量或者方法是重复的(共同的特征),此时就可以把这些实例变量或者方法抽象出一个新的类作为这些类的父类,这样我们在定义一个类的时候,直接将要的定义的类继承自这个父类,就能省去很多重复的代码,只需要在子类中添加自己独有的特征和方法.
7. 父类中被@public和@protected修饰的实例变量,子类中可以直接访问,而被@provate(私有的)修饰的实例变量子类不能直接访问,只能通过方法访问
8. 子类在调用方法时优先去自己的类里面找,找到了就直接调用,找不到就去父类中找,找到就调用,找不到就直接向上找,直到最终找到NSObject,如果实现就调用,没有实现就Crash
9. 重写父类的方法,一种是完全重写,不完全重写时需要在方法中使用super调用父类对方法的实现
使用继承时要注意的问题
- OC中不允许子类和父类相同名称的实例变量,会引起混乱;
- OC中子类可以拥有和父类相同名称的方法,在子类调用时,优先去自己的内部找,找到就调用,没有就一层一层往上找.
- 子类的重写会覆盖掉父类以前的实现,因为子类重新实现了父类中的某个方法
代码演示:
首先,创建一个汽车Car类,让它继承自NSObject类
Car.h
@interface Car : NSObject
// 汽车的特征
{
@public
NSString *_color; //颜色
@protected
NSString *_brand; //品牌
@private
NSInteger _wheel; //轮子
}
// 车的行为
- (void)run;
- (void)carShock;
// 实例变量的setter getter方法
- (void)setColor:(NSString *)color;
- (NSString *)color;
- (void)setBrand:(NSString *)brand;
- (NSString *)brand;
- (void)setWheel:(NSInteger)wheel;
- (NSInteger)wheel;
@end
Car.m
@implementation Car
- (void)run {
NSLog(@"车在跑");
}
- (void)carShock {
NSLog(@"车震是什么感觉,没试过");
}
- (void)setColor:(NSString *)color {
_color = color;
}
- (NSString *)color {
return _color;
}
- (void)setBrand:(NSString *)brand {
_brand = brand;
}
- (NSString *)brand {
return _brand;
}
- (void)setWheel:(NSInteger)wheel {
_wheel = wheel;
}
- (NSInteger)wheel {
return _wheel;
}
@end
上面我们定义了一个汽车Car的类,,使它具有颜色,品牌,轮子的属性,具有跑和车震两种行为(方法).现在,我们给卡车Truck增加一个最大载货量的属性和输出自身信息的方法,同时又包含Car这些属性和方法,那么我们就要使用继承;
这个时候利用继承的思想,我们只需要新建一个类,让它继承自Car这个类,新类中写自己特有的方法和属性.
新建一个Truck类,继承自Car:
Truck.h
@interface Truck : Car
{
// NSString *_color; error 子类中不能定义和父类同名的实例变量
CGFloat _maxLoad; //最大载货量
}
- (void)setMaxLoad:(CGFloat)manLoad;
- (CGFloat)maxLoad;
// 描述卡车信息的方法
- (void)describeTruck;
- (void)run; // 子类中可以定义和父类同名的方法,这种形式叫做方法的重写//那么,为什么要进行方法的重写呢?因为父类提供的方法不能满足子类的需求// 重写父类的方法有两种,一种是完全重写父类的方法,另一种是不完全重写的方法
@end
Truck.m
@implementation Truck
// _maxLoad的setter getter方法
- (void)setMaxLoad:(CGFloat)manLoad {
_maxLoad = manLoad;
}
- (CGFloat)maxLoad {
return _maxLoad;
}
// 描述卡车信息的方法
- (void)describeTruck {
NSLog(@"%@ %@ %ld %.2f", _color, _brand, self.wheel, _maxLoad);
}
// 注意:由于 _wheel被private修饰,不能在子类中直接访问,需要用self
// 重写父类run的方法
// 如果在重写父类方法时,没有调用父类的方法实现就叫做完全重写
- (void)run
NSLog(@"卡车在奔跑");
}
// 重写车震的方法
- (void)carShock {
// super 编译器指令,用于调用父类的方法,适用于想保留父类中某些方法的情况
[super carShock];
NSLog(@"卡车不好震");
}
@end
回到main中.
// 创建一个大卡车的对象
Truck *truc = [[Truck alloc] init];
// color brand wheel是从父类继承过来的
truc.color = @"蓝色"; // 颜色
truc.brand = @"东风"; // 品牌
truc.wheel = ; // 轮子
// maxLoad是子类特有的
truc.maxLoad = 120.0;// 载重量
// 调用父类的方法
// [truc carShock];
[truc run];
// 调用描述卡车的方法
[truc describeTruck];
// 调用车震的方法
[truc carShock];
打印结果:
2015-11-26 22:46:44.741 OCLessonInherit-03[1759:364404] 卡车在奔跑
2015-11-26 22:46:44.742 OCLessonInherit-03[1759:364404] 蓝色东风 12 120.00
2015-11-26 22:46:44.742 OCLessonInherit-03[1759:364404] 没震过,不知道什么感觉
2015-11-26 22:46:44.742 OCLessonInherit-03[1759:364404] 卡车不好震
三 初始化方法
- 完整的初始化方法
- (id)init {
// 执行父类中的init方法
self = [super init]
if (self) {
// 初始化设置
_taxiMeter = @"计价器";
}
// 返回初始化完成的对象
return self;
}
初始化过程:
初始化时,先调用父类的[super init]方法(向上递归到NSObject类中的初始化方法),使用self接收结果,然后根据self中的值判断是否为nil,决定要不要初始自己的实例变量;如果为nil,说明父类的初始化方法失败了,就不再对自身实例变量初始化,如果不为nil,说明父类初始化方法成功了,再对自身实例变量进行初始化
2.自定义初始化方法
命名规范:
1. 一定是对象方法,以减号 - 开头
2. 返回值类型是 id 类型(最好写id类型) 或者是当前的类类型
3. 必须以 initWith 开头
4. 自定义初始化方法分为两种:完全自定义初始化 与 不完全初始化方法
示例:
不完全初始化方法:
// 只初始化姓名和年龄
- (id)initWithName:(NSString *)name age:(NSInteger)age {
if (self = [super init]) {
_name = name;
_age = age;
}
return self;
}
完全自定义初始化:
// 初始化全部的实例变量
- (id)initWithName:(NSString *)name age:(NSInteger)age height:(CGFloat)height {
if (self = [super init]) { _name = name;
_age = age;
_height = height;
}
return self;
}
3.便利构造器方法
命名规范
1. 遍历构造器方法一定是一个类方法,以加号开头(+)
2. 返回值类型一定是 id类型
3. 以类名小写开头 +With+实例变量名去掉下划线且首字母大写
注意:
4. 便利构造器又叫做工厂方法,用于快捷快速地创建对象
5. 便利构造器方法的实质: 在方法内部把一个创建好的对象作为方法的返回值
6. 便利构造器方法要和自定义初始化方法配套使用
示例(对应上面列举的两种自定义初始化方法):
+ (id)personWithName:(NSString *)name age:(NSInteger)age {
// 将一个创建好的对象作为便利构造器方法的返回值
return [[Person alloc] initWithName:name age:age];
}
+ (id)personWithName:(NSString *)name age:(NSInteger)age hight:(CGFloat)hight {
return [[Person alloc] initWithName:name age:age height:hight];
}
@end
main
Person *p = [[Person alloc] init];
NSLog(@"%@ - %ld - %.2f", p.name, p.age, p.height);
//调用自定义初始化方法
Person *p1 = [[Person alloc] initWithName:@"吴邪"];
NSLog(@"%@ - %ld - %.2f", p1.name, p1.age, p1.height);
Person *p2 = [[Person alloc] initWithName:];
NSLog(@"%@ - %ld - %.2f", p2.name, p2.age, p2.height); // 调用完全初始化方法
Person *p3 = [[Person alloc] initWithName: height:];
NSLog(@"%@ - %ld - %.2f", p3.name, p3.age, p3.height);
// 调用便利构造器方法
Person *p4 = [Person personWithName:@"杀阡陌"];
NSLog(@"%@ - %ld - %.2f", p4.name, p4.age, p4.height);
Person *p5 = [Person personWithName:];
p5.name = @"糖宝";
p5.height = 0.3;
NSLog(@"%@ - %ld - %.2f", p5.name, p5.age, p5.height);
Person *p6 = [Person personWithName: hight:1.65];
NSLog(@"%@ - %ld - %.2f", p6.name, p6.age, p6.height);
以下是完整的代码:
Person.h
#import "Car.h"
@interface Person : Car
{
NSString *_name;
NSInteger _age;
CGFloat _height;
}
- (void)setName:(NSString *)name;
- (NSString *)name;
- (void)setAge:(NSInteger)age;
- (NSInteger)age;
- (void)setHeight:(CGFloat)height;
- (CGFloat)height;
// 自定义初始化方法
- (id)initWithName:(NSString *)name;
- (id)initWithName:(NSString *)name age:(NSInteger)age;
- (id)initWithName:(NSString *)name age:(NSInteger)age height:(CGFloat)height;
// 写一个遍历构造器的类方法
+ (id)personWithName:(NSString *)name;
+ (id)personWithName:(NSString *)name age:(NSInteger)age;
+ (id)personWithName:(NSString *)name age:(NSInteger)age hight:(CGFloat)hight;
@end
#import "Person.h"
@implementation Person
- (void)setName:(NSString *)name {
_name = name;
}
- (NSString *)name {
return _name;
}
- (void)setAge:(NSInteger)age {
_age = age;
}
- (NSInteger)age {
return _age;
}
- (void)setHeight:(CGFloat)height {
_height = height;
}
- (CGFloat)height {
return _height;
}
// 自定义初始化方法
// 无论是哪种初始化方法,都要首先判断下父类有没有有初始化成功
- (id)initWithName:(NSString *)name {
if (self = [super init]) {
_name = name;
}
return self;
}
- (id)initWithName:(NSString *)name age:(NSInteger)age {
if (self = [super init]) {
_name = name;
_age = age;
}
return self;
}
- (id)initWithName:(NSString *)name age:(NSInteger)age height:(CGFloat)height {
if (self = [super init]) {
_name = name;
_age = age;
_height = height;
}
return self;
}
+ (id)personWithName:(NSString *)name {
// 便利构造器的实质就是在便利构造器方法中创建一个对象,然后把这个对象作为返回值返回
// 遍历构造器方法一定要和自定义初始化方法配合使用
Person *p = [[Person alloc] initWithName:name];
return p;
}
+ (id)personWithName:(NSString *)name age:(NSInteger)age {
// 将一个创建好的对象作为便利构造器方法的返回值
return [[Person alloc] initWithName:name age:age];
}
+ (id)personWithName:(NSString *)name age:(NSInteger)age hight:(CGFloat)hight {
return [[Person alloc] initWithName:name age:age height:hight];
}
@end
Objective-C学习篇03—继承的更多相关文章
- 深入js的面向对象学习篇(继承篇)——温故知新(三)
写这篇有关继承的文章时,突然想起,几天前的面试.因为习惯在学习知识的时候加上自己的理解,很喜欢用自己话来解释,于是乎当面试被问起继承原理时,噼里啪啦一大堆都是自己组织的话,(也可能是因为个人紧张.外加 ...
- 【从零开始自制CPU之学习篇03】锁存器与触发器
本篇学习了两种锁存器:SR Latch和D Latch,一种触发器:D flip flop SR Latch:SR—锁存器 初始状态下,S和R都为0,Q和Q‘随机有一个为1另一个 为0(取决于电流速度 ...
- pythonchallenge之C++学习篇-03
提示说一个小写字母两面精确地被大写字母包围,应该指的是周围没有四个而仅仅这两个像这样的:xXXXxXXXx的中间的那个应该是符合条件的 好了标题是re,提示该是使用正则表达式,网页源码里有待处理的字符 ...
- c++学习笔记之继承篇
title: c++学习笔记之继承篇 date: 2017-03-26 16:36:33 tags: [c++,继承,public,virtual,private,protected] categor ...
- javascript面向对象系列第三篇——实现继承的3种形式
× 目录 [1]原型继承 [2]伪类继承 [3]组合继承 前面的话 学习如何创建对象是理解面向对象编程的第一步,第二步是理解继承.本文是javascript面向对象系列第三篇——实现继承的3种形式 [ ...
- (转载)OC学习篇之---概述
前言 终于开启了OC的学习篇了,之前由于工作上的事,学习就一直搁浅了,不过最近由于各种原因,感觉必须要开启iOS的开发旅程了,不然就老了.因为之前一直是做Android的,所以学习iOS来就没那么费劲 ...
- Scrapy学习篇(十)之下载器中间件(Downloader Middleware)
下载器中间件是介于Scrapy的request/response处理的钩子框架,是用于全局修改Scrapy request和response的一个轻量.底层的系统. 激活Downloader Midd ...
- Scrapy学习篇(七)之Item Pipeline
在之前的Scrapy学习篇(四)之数据的存储的章节中,我们其实已经使用了Item Pipeline,那一章节主要的目的是形成一个笼统的认识,知道scrapy能干些什么,但是,为了形成一个更加全面的体系 ...
- OpenCV 学习笔记03 findContours函数
opencv-python 4.0.1 1 函数释义 词义:发现轮廓! 从二进制图像中查找轮廓(Finds contours in a binary image):轮廓是形状分析和物体检测和识别的 ...
随机推荐
- ROR入门之旅
mac上为了不在登录画面看到其他账户,我禁用了root账户,而每次用Terminal的时候,先获得sudo账户的权限: sudo -s mac本身就安装有ruby ruby -v 查看当前安装的rub ...
- struts2之防止表单重复提交
struts.xml配置文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts ...
- http请求方式和状态管理
1. HTTP协议 Internet的基本协议是TCP/IP协议(传输控制协议和网际协议),目前广泛使用的 FTP.HTTP(超文本传输协议).Archie Gopher都是建立在TCP/IP上面的 ...
- [LeetCode#154]Find Minimum in Rotated Sorted Array II
The question: Follow up for "Find Minimum in Rotated Sorted Array":What if duplicates are ...
- Light OJ 1011 - Marriage Ceremonies(状压DP)
题目大意: 有N个男人,和N个女人要互相匹配,每个男人和每个女人有个匹配值. 并且匹配只能是1对1的. 问所有人都匹配完成,最大的匹配值是多少? 状压DP,暴力枚举就OK了, 这个题目略坑,因为他 ...
- 生成树的计数(基尔霍夫矩阵):UVAoj 10766 Organising the Organisation SPOJ HIGH - Highways
HIGH - Highways In some countries building highways takes a lot of time... Maybe that's because th ...
- poj 2408 Apple Tree
http://poj.org/problem?id=2486 典型的回溯题目:特别是状态方程用三维的来标记是否要走回路. 题意:一颗树,n个点(1-n),n-1条边,每个点上有一个权值,求从1出发,走 ...
- oracle常用命令总结
声明:本文为博主在做项目中用到的一些常用命令,请勿转载,只为保存. oracle常用命令总结 创建表空间: --create tablespace vms--datafile 'e:\vms.dbf' ...
- SANSA 上上洛可可 贾伟作品 高山流水 香炉 香插香台香具 高端商务礼品 黑色【正品 价格 图片 折扣 评论】_尚品网ShangPin.com
SANSA 上上洛可可 贾伟作品 高山流水 香炉 香插香台香具 高端商务礼品 黑色[正品 价格 图片 折扣 评论]_尚品网ShangPin.com
- memcached分布式实现原理
摘要 在高并发环境下,大量的读.写请求涌向数据库,此时磁盘IO将成为瓶颈,从而导致过高的响应延迟,因此缓存应运而生.无论是单机缓存还是分布式缓存都有其适应场景和优缺点,当今存在的缓存产品也是数不胜数, ...