OC从入门到精通-2.三大特性(封装,继承,多态)

OC三大特性

  • 封装
  • 继承
  • 多态

封装

set和get方法

成员变量命名规范

弱语法

类方法的使用

self的一些用法

用法1:self用来访问成员变量
//先看一段没使用self的代码

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    int _age;
}

- (void)setAge;

- (void)age;

- (void)test;

@end

@implementation Person

- (void)setAge:(int)age
{
    //_age是成员变量
    _age=age;

}

- (int)getAge
{
    return _age;
}

- (void)test
{
    int _age=20;  //这是一个局部变量
    NSLog(@"成员变量_age的值为%d",_age);
}


@end

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

    Person *p=[Person new];
    [p setAge:10];
    [p getAge];
    [p test];
    return 0;
}

输出结果为:

2016-03-25 11:43:15.326 3-25-3[39932:2019323]
成员变量_age的值为20
Program ended with exit code: 0

修改上述test方法的代码,如下

- (void)test
{
    //self :指向调用它的指针
    int _age=20;
  //self->age用来调用当前对象的成员变量,局部变量不会影响它
    NSLog(@"成员变量_age的值为%d",self->_age);
}

输出结果为:

2016-03-25 11:45:36.209 3-25-3[39942:2021207] 成员变量_age的值为10
Program ended with exit code: 0

//self :指向调用它的指针

2.self用来访问对象方法 or 类方法
//self的使用

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    int _age;
}

- (void)setAge:(int)age;

- (int)age;

- (void)test;

- (void)eat;

- (void)run;
@end

@implementation Person

- (void)setAge:(int)age
{
    //_age是成员变量
    _age=age;

}

- (int)age
{
    return _age;
}

- (void)eat
{
    NSLog(@"先吃饭");

}

- (void)run
{
    [self eat];  //可以调用其他对象方法 or 类方法
    NSLog(@"后跑步");

}

- (void)test
{
    //int _age=20;
    NSLog(@"成员变量_age的值为%d",self->_age);
}


@end

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

    Person *p=[Person new];
    [p run];
    return 0;
}

输出结果:

2016-03-25 11:50:16.441 3-25-self2[39968:2024515] 先吃饭
2016-03-25 11:50:16.442 3-25-self2[39968:2024515] 后跑步
Program ended with exit code: 0
3.self指向调用它的指针,本身就是一个指针

下面来看一段代码,估计下它的输出结果是什么

//self的使用

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
}

- (void)test;
+ (void)test;

- (void)test1;
+ (void)test1;


- (void)rest1;
+ (void)rest2;
@end

@implementation Person

- (void)test
{
    NSLog(@" - test");

}
+ (void)test
{
    NSLog(@" + test");

}

- (void)test1
{

    [self test];  //-test
}

+ (void)test1
{

    [self test];  //+test
}

@end

int main(int argc, const char * argv[]) {
    Person *p =[Person new];
    [p test1];
    return 0;
}

输出为:

- test

这里的[p test1]中的p是一个Person对象,所以首先调用 - test1 对象方法,- test1 对象方法中的self 指向的是调用它的指针,也就是对象p,所以self 就会调用- test() 对象方法

如果把上述main 方法修改如下:

int main(int argc, const char * argv[]) {
    //Person *p =[Person new];
    //[p test1];

    [Person test1];

输出则为:

+ test

这里的[Person test1]中的Person是一个类,所以首先调用 + test1 类方法,+ test1 类方法中的self 指向的是调用它的指针,也就是类Person,所以self 就会调用+ test() 类方法

2.继承

类A继承类B,则类B的所有属性,类A都将获得。

继承的基本语法

//
//  main.m
//  继承1


#import <Foundation/Foundation.h>

//父类 People类,代表所有人类
@interface People : NSObject
{
    int _age;
    double _weight;
}

- (void)setAge:(int)age;
- (int)age;

- (void)setWeight:(double)weight;
- (double)weight;

@end

@implementation People
- (void)setAge:(int)age
{
    _age=age;

}
- (int)age
{
    return _age;
}

- (void)setWeight:(double)weight
{
    _weight=weight;
}
- (double)weight
{
    return _weight;
}

@end


/****Student****/
//Student 继承了People,相当于拥有了People里的所以成员变量和方法
@interface Student : People
@end

@implementation Student
@end

/****Teacher****/
@interface Teacher : People
@end

@implementation Teacher
@end



int main(int argc, const char * argv[]) {
    Student *s=[Student new];
    [s setAge:20];
    NSLog(@"The age of Student is %d", [s age]);

    Teacher *t=[Teacher new];
    [t setWeight:50.2];
    NSLog(@"The age of Teacher is %f", [t weight]);


    return 0;
}

输出结果为:

The age of Student is 20
The age of Teacher is 50.200000

子类继承父类,那么子类可以访问父类的所以成员变量和方法。

类的继承关系
上图显示的正是代码中的类继承关系。这不是标准的类图,该图主要是帮助理解,箭头所指的是继承关系。继承后,子类拥有父类的方法。所以在Student 和Teacher方法中没有写任何方法,却可以调用set 和get 方法。

继承中的成员变量

对上面代码的Student 作如下修改

@interface Student : People
 int _age;
 int _num;
@end

运行时会报错!将其注释//int age是可以运行的。
可以看出
- OC中不允许子类和父类有相同的成员变量
- OC中子类可以添加父类中没有的成员变量或方法

继承中的方法

优先检查子类中重写的方法,如果没有再检查父类中的方法

看如下代码:

//
//  main.m
//  继承1


#import <Foundation/Foundation.h>

//父类 People类,代表所有人类
@interface People : NSObject
{
    int _age;
    double _weight;
}


- (void)run;

@end

@implementation People

- (void)run
{
    NSLog(@"People在跑");

}

@end


/****Student****/
//Student 继承了People,相当于拥有了People里的所以成员变量和方法
@interface Student : People

//定义自己的run方法
//父类中已经有了run方法了,所以这里就是“重写”父类方法
- (void)run;

@end

@implementation Student

- (void)run
{
    NSLog(@"Student在跑");
}
@end




int main(int argc, const char * argv[]) {
    Student *s=[Student new];
    [s run];
    return 0;
}

输出结果为:

Student在跑
Program ended with exit code: 0

优先检查子类中重写的方法,如果没有再检查父类中的方法
其实这个过程很好理解,每个对象里面有一个isa指针,指向它的类,而每个类里面也有一个superclass指针,指向它的父类。
当执行[s run];首先通过s 对象的isa指针指到Student类,在类中寻找run方法,一旦找到就执行。
如果没有找到的话,就会通过superclass指针寻找父类中的run方法,知道找到为止,找不到的话程序会报错。
类继承深层理解

继承的使用场合

  1. 多个类有相同的属性和方法的时候,最好使用一个父类将公有属性和方法集中起来,便于子类的重用。子类继承这个父类就可以了
  2. 但是,大量使用继承会导致耦合性较高,类和类之间的依赖太强。必须要符合逻辑的依赖关系,才使用继承。
  3. 当B类完全拥有A类的属性和方法时,可以使B继承A

继承和组合的区别

下面看一段代码:

//
//  main.m
//  继承1


#import <Foundation/Foundation.h>

//父类 People类,代表所有人类
@interface People : NSObject

- (void)run;

@end

@implementation People
- (void)run
{
    NSLog(@"People在跑");

}

@end

/***Score***/
@interface Score : NSObject
{
    int value;
}
- (int)value;

@end

@implementation Score

- (int)value{
    return  value;
}

@end



//继承:xx是xxx
//组合:xxx拥有xxx

/****Student****/
@interface Student : People
{
    //这里Student则是拥有的Score类里的所有属性和方法了
    //组合
    Score *_score;

}
- (void)run;
@end

@implementation Student

- (void)run
{
    NSLog(@"Student在跑");
}
@end

int main(int argc, const char * argv[]) {
    return 0;
}

上面的代码显示,不使用继承也可以获取另一个类的所有方法和属性。这就是组合。从逻辑关系上score明显不适合被继承,Student又想拿到该类的所有内容,所以使用组合是不错的解决方法。

super关键字

//
//  main.m
//  继承1


#import <Foundation/Foundation.h>

//父类 People类,代表所有人类
@interface People : NSObject

- (void)run;

@end

@implementation People
- (void)run
{
    NSLog(@"People准备奔跑!!!");

}

@end





/****Student****/
@interface Student : People
{


}

- (void)run;



@end

@implementation Student

- (void)run
{
    [super run]; //直接调用父类的方法
    NSLog(@"Student在跑");

}
@end




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

    Student *s=[Student new];
    [s run];

    return 0;
}

输出结果:

 People准备奔跑!!!
 Student在跑
Program ended with exit code: 0

Super关键字可以使子类方法直接调用父类方法
Super不仅可以调用对象方法,还可以调用类方法
Super具体是调用类方法还是对象方法是看Supe所在环境

代码如下:

#import <Foundation/Foundation.h>
//父类 People类,代表所有人类
@interface People : NSObject
- (void)run;
+ (void)run;
@end
@implementation People
- (void)run
{
    NSLog(@"-People准备奔跑!!!");
}

+ (void)run
{
    NSLog(@"+People准备奔跑!!!");

}

@end





/****Student****/
@interface Student : People
{


}

- (void)run;
+ (void)run;


@end

@implementation Student

- (void)run
{
    [super run]; //直接调用父类的方法
    NSLog(@"Student在跑");

}

+ (void)run
{
    [super run]; //直接调用父类的方法
    NSLog(@"Student在跑");

}
@end


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

    [Student run];

    return 0;
}

3.多态

多态:字面指多种状态
父类指针指向子类对象

//
//


#import <Foundation/Foundation.h>

//父类 People类,代表所有人类
@interface People : NSObject
- (void)run;
@end

@implementation People
- (void)run
{
    NSLog(@"People奔跑");
}
@end


/****Student****/
@interface Student : People
{

}
- (void)run;
@end

@implementation Student

- (void)run
{
    NSLog(@"Student奔跑");
}


@end

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

    //多态:父类指针指向子类对象
    People *p = [Student new];
    [p run];
    return 0;
}

输出结果为:

Student奔跑

为什么要用多态?
比如现在有个People类,还有两个子类Student ,Teacher继承这个People类

//父类 People类,代表所有人类
@interface People : NSObject
{
    @public
    int age;
}
@end
@implementation People
@end

/****Student****/
@interface Student : People
@end
@implementation Student
@end

/****Teacher****/
@interface Teacher : People
@end
@implementation Teacher
@end

定义一个函数,用来对Student和Teacher的age赋值,由于它们是两个类,至少需要两个函数

void setAge1(Student *p)
{
    p->age=20;
}

void setAge2(Teacher *p)
{
    p->age=20;

}

下面引入多态的概念,函数直接改成这样,使用一个函数就可以实现多个函数的功能,增加了重用

//如果函数的参数是一个父类类型,则可以传入父类,子类对象
void setAge(People *p){
    p->age=20;
}

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

    //多态:父类指针指向子类对象
    People *p = [Student new];
    setAge(p);   //这样就是设置Student的对象的age

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值