OC--继承封装和多态
一、封装
为了增加信息的安全度,不让外界对对象直接访问或赋值,我们需要封装,把信息封装到一个方法里,提供一个方法给外界设置成员变量值
封装的好处
* 过滤不合理的值
* 屏蔽内部的赋值过程
* 让外界不必关注内部的细节
set方法
1.作用: 提供一个方法给外界设置成员变量值,可以在方法里面对参数进行相应过滤
2.命名规范:
1> 方法名必须以set开头
2> set后面跟上成员变量的名称,成员变量的首字母必须大写
3> 返回值一定是void
4> 一定要接收一个参数,而且参数类型跟成员变量类型一致
5> 形参的名称不能跟成员变量名一样
*/
- (void)setAge:(int)newAge;
*/
get方法
1.作用:返回对象内部的成员变量
2.命名规范:
1> 肯定有返回值,返回值类型肯定与成员变量类型一致
2> 方法名跟成员变量名一样
3> 不需要接收任何参数
成员变量的命名规范
* 成员变量都以下划线 _ 开头
* 可以跟get方法的名称区分开
* 可以跟其他局部变量区分开,一看到下划线开头的变量,肯定是成员变量
代码示例:
#import <Foundation/Foundation.h>
// 声明
@interface Car : NSObject
{
int _wheels; // 轮子个数
}
/*set方法*/
- (void) setWheels:(int)wheels;
/*get方法*/
- (int) wheels;
@end
@implementation Car
// set方法的实现
- (void) setWheels:(int)wheels
{
// 对外面传进来的轮子数进行过滤
if (wheels<=0)
{
wheels = 1;
}
_wheels = wheels;
}
// get方法的实现
- (int) wheels
{
return _wheels;
}
@end
类方法和对象方法对比
1) 对象方法
* 以减号-开头
* 只能让对象调用,没有对象,这个方法根本不可能被执行
* 对象方法能访问实例变量(成员变量)
2) 类方法
* 以加号+开头
* 只能用类名调用,对象不能调用
* 类方法中不能访问实例变量(成员变量)
* 使用场合:当不需要访问成员变量的时候,尽量用类方法
3) 类方法和对象方法可以同名
类方法的好处和使用场合
1> 不依赖于对象,执行效率高
2> 能用类方法,尽量用类方法
3> 场合:当方法内部不需要使用到成员变量时,就可以改为类方法
代码示例:
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
int age;
}
// 类方法都是以+开头
+ (void)printClassName;
- (void)test;
+ (void)test;
@end
@implementation Person
+ (void)printClassName
{
// error:instance variable 'age' accessed in class method
// 实例变量age不能在类方法中访问
//NSLog(@"这个类叫做Person-%d", age);
}
- (void)test
{
NSLog(@"111-%d", age);
//[Person test];
}
+ (void)test
{
// 调用自身会引发死循环
//[Person test];
NSLog(@"333");
}
@end
int main()
{
//[Person printClassName];
[Person test];
//Person *p = [Person new];
//[p test];
/*
-[Person printClassName]: unrecognized selector sent to instance 0x7fa520c0b370
*/
// 系统会认为现在调用的printClassName是个对象方法
//[p printClassName];
return 0;
}
Self的用法
1>.概念:指向当前对象(方法调用者)
* 谁调用了当前的方法,self就代表谁
* self出现在对象方法中,self就代表对象
* self出现在类方法中,self就代表类
2>.可以利用”self->成员变量名”访问当前对象内部的成员变量
3>.[self 方法名] 可以调用其他对象方法的类方法
常见错误
* 低级错误:用self去调用函数
* 类方法中用self调用对象方法,对象方法中用self调用类方法
* self死循环
代码示例:#import <Foundation/Foundation.h>
@interface Person : NSObject
- (void)test;
+ (void)test;
- (void)test1;
+ (void)test2;
- (void)haha1;
+ (void)haha2;
@end
@implementation Person
- (void)test
{
NSLog(@"调用了-test方法");
// 会引发死循环
//[self test];
}
+ (void)test
{
NSLog(@"调用了+test方法");
// 会引发死循环
//[self test];
}
- (void)test1
{
[self test]; // -test
}
+ (void)test2
{
[self test]; // +test
}
- (void)haha1
{
NSLog(@"haha1-----");
}
void haha3()
{
}
+ (void)haha2
{
// haha3();
[self haha3];
// [self haha1];
}
@end
int main()
{
[Person haha2];
//Person *p = [Person new];
//[p test1];
return 0;
}
二、继承
继承的使用场合
1、 当两个类拥有相同属性和方法的时候,就可以相同的东西抽取到同一个父类中
2、 当A类拥有B类中的部分属性和方法时,可以考虑让B类继承A类
继承的好处
1、 抽取重复代码
2、 建立了类之间的关系
3、 子类可以拥有父类所有的成员变量和方法
重写:子类重新实现父类中的某个方法,覆盖父类的实现方法
注意:
1、 父类必须声明在子类的前面
2、 不允许子类和父类拥有相同的成员变量
3、 调用某个方法时,优先去当前类找,如果没有,去父类找
允许子类和父类拥有相同的方法,执行时优先从自己的类中找,如果没有就去父类找
组合
组合:xxx 拥有 xxx (上一个有相同属性的类名 * )
继承:xxx 是 xxx
代码示例:#import <Foundation/Foundation.h>
/********Animal的声明*******/
@interface Animal : NSObject
{
int _age;
double _weight;
}
- (void)setAge:(int)age;
- (int)age;
- (void)setWeight:(double)weight;
- (double)weight;
@end
/********Animal的实现*******/
@implementation Animal
- (void)setAge:(int)age
{
_age = age;
}
- (int)age
{
return _age;
}
- (void)setWeight:(double)weight
{
_weight = weight;
}
- (double)weight
{
return _weight;
}
@end
/********Dog*******/
// Dog 继承了Animal,相当于拥有了Animal里面的所有成员变量和方法
// Animal称为Dog的父类
// Dog称为Animal的子类
@interface Dog : Animal
@end
@implementation Dog
@end
int main()
{
Dog *d = [Dog new];
[d setAge:10];
NSLog(@"age=%d", [d age]);
return 0;
}
Super的用法
1、 直接调用父类中的某个方法
2、 super处于对象方法中,就调用父类的对象方法:- (void)方法名
3、 super处于类方法中,就调用父类的类方法 + (void)方法名
4、 使用场合:子类重写父类的方法时想保留父类的一些行为方法
代码示例:
/*
僵尸
跳跃僵尸、舞王僵尸、铁桶僵尸
*/
#import <Foundation/Foundation.h>
// 僵尸
@interface Zoombie : NSObject
- (void)walk;
+ (void)test;
- (void)test;
@end
@implementation Zoombie
- (void)walk
{
NSLog(@"往前挪两步******");
}
+ (void)test
{
NSLog(@"Zoombie+test");
}
- (void)test
{
NSLog(@"Zoombie-test");
}
@end
// 跳跃僵尸
@interface JumpZoombie : Zoombie
+ (void)haha;
- (void)haha2;
@end
@implementation JumpZoombie
+ (void)haha
{
[super test];
}
- (void)haha2
{
[super test];
}
- (void)walk
{
// 跳两下
NSLog(@"跳两下");
// 走两下(直接调用父类的walk方法)
[super walk];
//NSLog(@"往前挪两步----");
}
@end
int main()
{
//[JumpZoombie haha];
JumpZoombie *jz = [JumpZoombie new];
[jz haha2];
return 0;
}
三、多态:
没有继承就没有多态
父类指针指向子类对象 Amimal *a = [Dog new];实际是建立一个Dog对象
好处:如果参数中使用的是父类类型,可以传入父类,子类对象
局限性:父类类型的变量不能直接调用子类特有的方法。必须强转为子类类型变量,
才能直接调用子类特有的方法
#import <Foundation/Foundation.h>
// 动物
@interface Animal : NSObject
- (void)eat;
@end
@implementation Animal
- (void)eat
{
NSLog(@"Animal-吃东西----");
}
@end
// 狗
@interface Dog : Animal
- (void)run;
@end
@implementation Dog
- (void)run
{
NSLog(@"Dog---跑起来");
}
- (void)eat
{
NSLog(@"Dog-吃东西----");
}
@end
// 猫
@interface Cat : Animal
@end
@implementation Cat
- (void)eat
{
NSLog(@"Cat-吃东西----");
}
@end
// 这个函数是专门用来喂动物
//void feed(Dog *d)
//{
// [d eat];
//}
//
//void feed2(Cat *c)
//{
// [c eat];
//}
//
// 如果参数中使用的是父类类型,可以传入父类、子类对象
void feed(Animal *a)
{
[a eat];
}
int main()
{
// NSString *d = [Cat new];
// [d eat];
/*
Animal *aa = [Dog new];
// 多态的局限性:父类类型的变量 不能 用来调用子类的方法
//[aa run];
// 将aa转为Dog *类型的变量
Dog *dd = (Dog *)aa;
[dd run];
*/
//Dog *d = [Dog new];
//[d run];
/*
Animal *aa = [Animal new];
feed(aa);
Dog *dd = [Dog new];
feed(dd);
Cat *cc = [Cat new];
feed(cc);
*/
/*
// NSString *s = [Cat new];
Animal *c = [Cat new];
NSObject *n = [Dog new];
NSObject *n2 = [Animal new];
// 多种形态
//Dog *d = [Dog new]; // Dog类型
// 多态:父类指针指向子类对象
Animal *a = [Dog new];
// 调用方法时会检测对象的真实形象
[a eat];
*/
return 0;
}
创建字符串的方式 NNString *名称 = @”字符串内容”;
NNString *name = @"jack";
输出用%@,名称 示例:
NSLog(@”你好 %@”,name);
创建字符串的另一种新式
int age = 15;
NNString *name = @"jack";
NNString *str = [NNStringstringWithFormat:@”My age is %d and my name is %@”,age ,name];
NSLog(@”----%@----”);
求字符串长度(字数,既个数) length:[ 名称 length ];
NSString *name = @"哈哈jack";
// length方法算的是字数
int size = [name length];
NSLog(@"%d", size);
返回值是BOOL类型的,关于是否的一般用is开头
编程规范
1、最好在每个文件的最上头注释 作者,时间等文件相关的
2、int a = 5; // 这是注释 ( 注释双/ 的两侧有空格)
3、= 两边有空格
4、要尊重原文件的大小写一定不能改
5、要全面了解文档的意思,不要有歧义