IOS开发学习笔记010-面向对象的三大特性 一、封装 二、继承 三、多态

面向对象的三大特性

  1、封装

  2、继承

  3、多态

将类内部的属性保护起来,在外部不能直接访问,那么如果需要访问怎么办呢?

OC提供了set方法来对成员变量进行访问

set方法

1、作用:提供一个方法给外界设置age属性的值

2、命名规范

   方法名必须是set开头

   set后面跟上成员变量的名称,成员变量首字母必须大写

   返回值一定是void

   一定要接收一个参数,并且和成员变量类型一致

   形参名不能和成员变量名一样

 声明

- (void)setAge:(int)newAge;//声明

实现

1 - (void)setAge:(int)newAge//set方法实现
2 {
3     if(newAge <= 0)//如果小于0岁就赋值为1
4     {
5         newAge = 1;
6     }
7     age = newAge;//设置年龄
8 }

使用

1  Student *p = [Student new];//新建对象
2  [p setAge:20];//设置属性
3  [p study];//调用方法

 get方法

 1、作用:返回对象内部的成员变量

 2、命名规范:

    肯定有返回值,返回类型和成员变量一致

    方法名和成员变量名一样

    不需要接收参数

声明

- (int)age;//

实现

1 - (int)age//
2 {
3     return age;
4 }

使用

1  NSLog(@"%d岁的学生在学习!",[p age]);

成员变量的使用

命名规范:

  成员变量都以下划线 _ 开头

  可以跟get方法的名称区分开

  可以跟其他局部变量区分开,一看到下划线开头的变量,肯定是成员变量

 1 @interface Student : NSObject
 2 {
 3     //@public
 4     //成员变量
 5     //让成员变量和get方法区分开,成员变量都要加_
 6     int _no;
 7     int _age;
 8     Sex _sex;
 9 }
10 
11 @end

练习1

 1 #import <Foundation/Foundation.h>
 2 
 3 //成绩类
 4 /*
 5     C成绩(读写)
 6     OC成绩(读写)
 7     平均分(只读)
 8     总分(只读)
 9  */
10 //类的声明
11 @interface Score : NSObject
12 {
13     int _cScore;//c成绩
14     int _ocScore;//oc成绩
15     
16     int _totalScore;//总分
17     int _averageScore;//平均分
18 }
19 
20 //方法声明
21 //set
22 - (void)setCScore:(int)newCScore;
23 - (void)setOcScore:(int)newOcScore;
24 
25 //get
26 - (int)cScore;
27 - (int)ocScore;
28 - (int)totalScore;
29 - (int)averageScore;
30 
31 @end
32 
33 
34 
35 //类的实现
36 @implementation Score
37 //方法实现
38 - (void)setCScore:(int)newCScore
39 {
40     _cScore = newCScore;
41     //计算总分和平均分
42     _totalScore = _cScore + _ocScore;
43     _averageScore = _totalScore/2;
44 }
45 - (void)setOcScore:(int)newOcScore
46 {
47     _ocScore = newOcScore;
48     //计算总分和平均分
49     _totalScore = _cScore + _ocScore;
50     _averageScore = _totalScore/2;
51 }
52 
53 - (int)cScore
54 {
55     return _cScore;
56 }
57 - (int)ocScore
58 {
59     return _ocScore;
60 }
61 - (int)totalScore
62 {
63     return _totalScore;
64 }
65 - (int)averageScore
66 {
67     return _averageScore;
68 }
69 @end
70 
71 
72 int main()
73 {
74     Score *p = [Score new];//新建对象
75     [p setCScore:100];//set方法
76     [p setOcScore:90];//set方法
77     
78     NSLog(@"总分:%d",[p totalScore]);
79     
80     NSLog(@"平均分:%d",[p averageScore]);
81     
82     return 0;
83 }

OC弱语法

如果调用不存在的方法,那么在编译和链接时都不会报错,最多有一个警告。只有在运行时才回出错。

unrecognized selector sent to instance 0x0000034034C0

给对象发送的消息不能识别

OC只有在运行过程中才会检测对象有没有实现相应的方法。

类方法

1、以+开头

2、通过类名调用的方法。

3、类方法不能访问成员变量

4、类方法和对象方法可以重名

5、使用场合:当不需要访问成员变量时尽量用类方法

声明

+ (void)printClassName;//

实现

1 + (void)printClassName//
2 {
3     NSLog(@"class name is Person");
4 }

使用

 [Person printClassName];//类方法的调用,直接使用类名

工具类

没有成员变量的类,里面的方法全是类方法。

示例

 1 #import <Foundation/Foundation.h>
 2 /*
 3 工具类
 4     没有成员变量
 5     所有方法全是类方法
 6  */
 7 //类声明
 8 @interface JiSuanQi : NSObject
 9 
10 + (void)printClassName;//类方法
11 
12 + (int)sumOfSum1:(int)sum1 andSum2:(int)sum2;//类方法
13 
14 @end
15 //类的实现
16 @implementation JiSuanQi
17 + (void)printClassName
18 {
19     NSLog(@"class name is JiSuanQi");
20     
21 }
22 + (int)sumOfSum1:(int)sum1 andSum2:(int)sum2
23 {
24     return sum1 + sum2;
25 }
26 
27 @end
28 
29 int main()
30 {
31  
32     [JiSuanQi printClassName];//类方法的调用,直接使用类名
33     int res = [JiSuanQi sumOfSum1:10 andSum2:20];
34     NSLog(@"%d",res);
35     return 0;
36 }

self关键字

谁调用,self代表谁。

如果用对象调用,就代表对象,如果是类调用,就代表类。

成员变量和局部变量同名

  当成员变量和局部变量同名时,采取就近原则,访问的是局部变量

  用self访问成员变量,区分同名的局部变量

self出现的位置:

  所有的OC方法中(对象方法类方法),不能出现在函数

作用方式:

  使用 "self->成员变量名" 访问当前方法调用的成员变量

  使用 "[self 方法名];" 来调用方法(对象方法类方法)

1 - (void)setAge:(int)newAge
2 {
3     _age = newAge;
4 
5     int _age = 10;//局部变量与成员变量同名时,如果需要使用成员变量,则需要使用self关键字
6     NSLog(@"age is %d",self->_age);//self 是一个指指针,指向调用的对象
7 }

 小练习

   设计Car类,一个对象方法跟其他车子比较车速,返回速度差,一个类方法比较两辆车的车速,返回速度差

 1 #import <Foundation/Foundation.h>
 2 
 3 //类的声明
 4 @interface Car : NSObject
 5 {
 6     int _speed;//速度
 7 }
 8 - (void)setSpeed:(int)newSpeed;
 9 - (int)speed;
10 //对象方法
11 /*
12 作用:比较两辆车的速度大小,返回差值
13 方法名:differenceSpeedWithOtherCar:
14 参数:(Car *)otherCar
15 返回值:int
16  */
17 - (int)differenceSpeedWithOtherCar:(Car *)otherCar;
18 
19 //类方法
20 /*
21  作用:比较两辆车的速度大小,返回差值
22  方法名:differenceSpeedWithCar1: :
23  参数:(Car *)Car1 (Car *)Car2
24  返回值:int
25  */
26 + (int)differenceSpeedWithCar1:(Car *)Car1 andCar2:(Car *)Car2;
27 @end
28 
29 //类的实现
30 @implementation Car
31 //对象方法的实现
32 - (void)setSpeed:(int)newSpeed
33 {
34     _speed = newSpeed;
35 }
36 
37 - (int)speed
38 {
39     return _speed;
40 }
41 
42 //对象方法
43 - (int)differenceSpeedWithOtherCar:(Car *)otherCar
44 {
45     return [self speed] - [otherCar speed];//self指向调用者也就是本对象
46 }
47 
48 //类方法
49 
50 + (int)differenceSpeedWithCar1:(Car *)Car1 andCar2:(Car *)Car2;
51 {
52     return [Car1 speed] - [Car2 speed];//通过类调用的话,只能传进来两个参数,因为默认成员变量是0,没有任何实际意义。
53 }
54 
55 @end
56 
57 int main()
58 {
59     Car *p1 = [Car new];
60     [p1 setSpeed:300];
61     
62     Car *p2 = [Car new];
63     [p2 setSpeed:200];
64     
65     Car *p3 = [Car new];
66     [p3 setSpeed:90];
67     
68     int  res = [p1 differenceSpeedWithOtherCar:p2];//使用对象调用方法
69     NSLog(@"%d",res);
70     
71     res = [Car differenceSpeedWithCar1:p1 andCar2:p3];//使用类调用方法
72     NSLog(@"%d",res);
73     return 0;
74 }

二、继承

 子类从父类继承一些公共属性和方法。

 不允许子类和父类拥有同名的成员变量。

 方法可以和父类的方法同名(重写),调用过程是先找子类的,再找父类的。

 继承的使用场合

  1、当两个类拥有相同的属性和方法时,可以将相同的东西抽象到一个类中

  2、当类a中含有类B所需的全部或部分属性和方法时,可以让B继承A

继承与组合区别

  继承:A 是 B;

  组合:A 拥有B;

示例

 1 #import <Foundation/Foundation.h>
 2 
 3 //Animal类的声明
 4 @interface Animal : NSObject
 5 {
 6     int _age;//年龄
 7     double _weight;//体重
 8 }
 9 //对象方法
10 - (void)setAge:(int)newAge;
11 - (int)age;
12 
13 - (void)setWeight:(int)newWeight;
14 - (double)weight;
15 
16 - (void)run;
17 @end
18 
19 
20 //Animal类的实现
21 @implementation Animal
22 //方法实现
23 - (void)setAge:(int)newAge
24 {
25     _age = newAge;
26 }
27 - (int)age
28 {
29     return _age;
30 }
31 
32 - (void)setWeight:(int)newWeight
33 {
34     _weight = newWeight;
35 }
36 - (double)weight
37 {
38     return _weight;
39 }
40 
41 - (void)run
42 {
43     NSLog(@"动物在奔跑!");
44 }
45 
46 @end
47 
48 
49 
50 
51 
52 //Dog类的声明
53 @interface Dog : Animal
54 {
55     //int _age;//子类不能和父类的成员变量重名
56     int gouPai;//狗牌
57 }
58 //对象方法
59 - (void)run;//重写父类的方法
60 @end
61 
62 
63 //Dog类的实现
64 @implementation Dog
65 //方法实现
66 - (void)run
67 {
68     NSLog(@"Dog在奔跑!");
69 }
70 
71 @end
72 
73 //Cat类的声明
74 @interface Cat : Animal
75 {
76     
77 }
78 //对象方法
79 
80 @end
81 
82 
83 //Cat类的实现
84 @implementation Cat
85 //方法实现
86 
87 
88 @end
89 
90 int main()
91 {
92     Dog *d = [Dog new];
93     [d setAge:4];
94     [d run];//子类的run会覆盖父类的run方法
95     NSLog(@"%d",[d age]);
96     
97     return 0;
98 }

super关键字

如果在子类中想访问父类的方法(对象方法和类方法都可以),可以使用关键字super进行调用 ;  

[super walk];//具体是对象方法还是类方法取决于调用时所处于的环境。

使用场景:子类使用父类的方法时想保留父类的一些操作

1 //方法实现
2 - (void)run
3 {
4     NSLog(@"Dog在奔跑!");
5     
6     [super run];//super 关键字,调用父类的方法
7 }

三、多态

  父类指针指向子类对象:多态

 1、没有继承就没有多态

2、父指针指向子类对象

3、优点:函数/方法传入父指针,则在调用时可以传入子类指针和父类指针

4、缺点:父类类型的变量,不能直接调用子类特有的方法

代码示例

  1 #import <Foundation/Foundation.h>
  2 /*
  3 多态
  4  
  5  */
  6 
  7 
  8 //Animal类的声明
  9 @interface Animal : NSObject
 10 {
 11    // int _age;//年龄
 12     //double _weight;//体重
 13 }
 14 //对象方法
 15 
 16 - (void)eat;
 17 @end
 18 
 19 
 20 //Animal类的实现
 21 @implementation Animal
 22 //方法实现
 23 - (void)eat
 24 {
 25     NSLog(@"吃吃吃!");
 26 }
 27 
 28 @end
 29 
 30 
 31 
 32 
 33 
 34 //Dog类的声明
 35 @interface Dog : Animal
 36 {
 37     //int _age;//子类不能和父类的成员变量重名
 38     //int gouPai;//狗牌
 39 }
 40 //对象方法
 41 - (void)eat;//重写父类的方法
 42 @end
 43 
 44 
 45 //Dog类的实现
 46 @implementation Dog
 47 //方法实现
 48 - (void)eat
 49 {
 50     NSLog(@"Dog在吃吃吃!");
 51     
 52    // [super eat];//super 关键字,调用父类的方法
 53 }
 54 
 55 @end
 56 
 57 
 58 //Cat类的声明
 59 @interface Cat : Animal
 60 {
 61     //int _age;//子类不能和父类的成员变量重名
 62     //int gouPai;//狗牌
 63 }
 64 //对象方法
 65 - (void)eat;//重写父类的方法
 66 - (void)run;
 67 @end
 68 
 69 
 70 //Dog类的实现
 71 @implementation Cat
 72 //方法实现
 73 - (void)eat
 74 {
 75     NSLog(@"Cat在吃吃吃!");
 76     
 77     // [super eat];//super 关键字,调用父类的方法
 78 }
 79 - (void)run
 80 {
 81       NSLog(@"Cat在跑!");
 82 }
 83 @end
 84 
 85 
 86 int main()
 87 {
 88     //Dog *d = [Dog new];
 89 
 90     //父类指针指向子类对象:多态
 91     Animal *a = [Dog new];
 92     //[a run];//父类指针调用子类的特有方法,会有警告
 93 
 94     
 95     Dog *d = (Dog *)a;//可以强制转换,调用子类特有的方法
 96     [d eat];
 97     
 98     
 99     
100     return 0;
101 }