面向对象的三大特性
1、封装
2、继承
3、多态
一、封装
将类内部的属性保护起来,在外部不能直接访问,那么如果需要访问怎么办呢?
OC提供了set方法来对成员变量进行访问
set方法
1、作用:提供一个方法给外界设置age属性的值
2、命名规范
方法名必须是set开头
set后面跟上成员变量的名称,成员变量首字母必须大写
返回值一定是void
一定要接收一个参数,并且和成员变量类型一致
形参名不能和成员变量名一样
声明
- (void)setAge:(int)newAge;//声明
实现
- (void)setAge:(int)newAge//set方法实现
{
if(newAge <= )//如果小于0岁就赋值为1
{
newAge = ;
}
age = newAge;//设置年龄
}
使用
Student *p = [Student new];//新建对象
[p setAge:];//设置属性
[p study];//调用方法
get方法
1、作用:返回对象内部的成员变量
2、命名规范:
肯定有返回值,返回类型和成员变量一致
方法名和成员变量名一样
不需要接收参数
声明
- (int)age;//
实现
- (int)age//
{
return age;
}
使用
NSLog(@"%d岁的学生在学习!",[p age]);
成员变量的使用
命名规范:
成员变量都以下划线 _ 开头
可以跟get方法的名称区分开
可以跟其他局部变量区分开,一看到下划线开头的变量,肯定是成员变量
@interface Student : NSObject
{
//@public
//成员变量
//让成员变量和get方法区分开,成员变量都要加_
int _no;
int _age;
Sex _sex;
} @end
练习1
#import <Foundation/Foundation.h> //成绩类
/*
C成绩(读写)
OC成绩(读写)
平均分(只读)
总分(只读)
*/
//类的声明
@interface Score : NSObject
{
int _cScore;//c成绩
int _ocScore;//oc成绩 int _totalScore;//总分
int _averageScore;//平均分
} //方法声明
//set
- (void)setCScore:(int)newCScore;
- (void)setOcScore:(int)newOcScore; //get
- (int)cScore;
- (int)ocScore;
- (int)totalScore;
- (int)averageScore; @end //类的实现
@implementation Score
//方法实现
- (void)setCScore:(int)newCScore
{
_cScore = newCScore;
//计算总分和平均分
_totalScore = _cScore + _ocScore;
_averageScore = _totalScore/;
}
- (void)setOcScore:(int)newOcScore
{
_ocScore = newOcScore;
//计算总分和平均分
_totalScore = _cScore + _ocScore;
_averageScore = _totalScore/;
} - (int)cScore
{
return _cScore;
}
- (int)ocScore
{
return _ocScore;
}
- (int)totalScore
{
return _totalScore;
}
- (int)averageScore
{
return _averageScore;
}
@end int main()
{
Score *p = [Score new];//新建对象
[p setCScore:];//set方法
[p setOcScore:];//set方法 NSLog(@"总分:%d",[p totalScore]); NSLog(@"平均分:%d",[p averageScore]); return ;
}
OC弱语法
如果调用不存在的方法,那么在编译和链接时都不会报错,最多有一个警告。只有在运行时才回出错。
unrecognized selector sent to instance 0x0000034034C0
给对象发送的消息不能识别
OC只有在运行过程中才会检测对象有没有实现相应的方法。
类方法
1、以+开头
2、通过类名调用的方法。
3、类方法不能访问成员变量
4、类方法和对象方法可以重名
5、使用场合:当不需要访问成员变量时尽量用类方法
声明
+ (void)printClassName;//
实现
+ (void)printClassName//
{
NSLog(@"class name is Person");
}
使用
[Person printClassName];//类方法的调用,直接使用类名
工具类
没有成员变量的类,里面的方法全是类方法。
示例
#import <Foundation/Foundation.h>
/*
工具类
没有成员变量
所有方法全是类方法
*/
//类声明
@interface JiSuanQi : NSObject + (void)printClassName;//类方法 + (int)sumOfSum1:(int)sum1 andSum2:(int)sum2;//类方法 @end
//类的实现
@implementation JiSuanQi
+ (void)printClassName
{
NSLog(@"class name is JiSuanQi"); }
+ (int)sumOfSum1:(int)sum1 andSum2:(int)sum2
{
return sum1 + sum2;
} @end int main()
{ [JiSuanQi printClassName];//类方法的调用,直接使用类名
int res = [JiSuanQi sumOfSum1: andSum2:];
NSLog(@"%d",res);
return ;
}
self关键字
谁调用,self代表谁。
如果用对象调用,就代表对象,如果是类调用,就代表类。
成员变量和局部变量同名
当成员变量和局部变量同名时,采取就近原则,访问的是局部变量
用self访问成员变量,区分同名的局部变量
self出现的位置:
所有的OC方法中(对象方法\类方法),不能出现在函数
作用方式:
使用 "self->成员变量名" 访问当前方法调用的成员变量
使用 "[self 方法名];" 来调用方法(对象方法\类方法)
- (void)setAge:(int)newAge
{
_age = newAge; int _age = ;//局部变量与成员变量同名时,如果需要使用成员变量,则需要使用self关键字
NSLog(@"age is %d",self->_age);//self 是一个指指针,指向调用的对象
}
小练习
设计Car类,一个对象方法跟其他车子比较车速,返回速度差,一个类方法比较两辆车的车速,返回速度差
#import <Foundation/Foundation.h> //类的声明
@interface Car : NSObject
{
int _speed;//速度
}
- (void)setSpeed:(int)newSpeed;
- (int)speed;
//对象方法
/*
作用:比较两辆车的速度大小,返回差值
方法名:differenceSpeedWithOtherCar:
参数:(Car *)otherCar
返回值:int
*/
- (int)differenceSpeedWithOtherCar:(Car *)otherCar; //类方法
/*
作用:比较两辆车的速度大小,返回差值
方法名:differenceSpeedWithCar1: :
参数:(Car *)Car1 (Car *)Car2
返回值:int
*/
+ (int)differenceSpeedWithCar1:(Car *)Car1 andCar2:(Car *)Car2;
@end //类的实现
@implementation Car
//对象方法的实现
- (void)setSpeed:(int)newSpeed
{
_speed = newSpeed;
} - (int)speed
{
return _speed;
} //对象方法
- (int)differenceSpeedWithOtherCar:(Car *)otherCar
{
return [self speed] - [otherCar speed];//self指向调用者也就是本对象
} //类方法 + (int)differenceSpeedWithCar1:(Car *)Car1 andCar2:(Car *)Car2;
{
return [Car1 speed] - [Car2 speed];//通过类调用的话,只能传进来两个参数,因为默认成员变量是0,没有任何实际意义。
} @end int main()
{
Car *p1 = [Car new];
[p1 setSpeed:]; Car *p2 = [Car new];
[p2 setSpeed:]; Car *p3 = [Car new];
[p3 setSpeed:]; int res = [p1 differenceSpeedWithOtherCar:p2];//使用对象调用方法
NSLog(@"%d",res); res = [Car differenceSpeedWithCar1:p1 andCar2:p3];//使用类调用方法
NSLog(@"%d",res);
return ;
}
二、继承
子类从父类继承一些公共属性和方法。
不允许子类和父类拥有同名的成员变量。
方法可以和父类的方法同名(重写),调用过程是先找子类的,再找父类的。
继承的使用场合
1、当两个类拥有相同的属性和方法时,可以将相同的东西抽象到一个类中
2、当类a中含有类B所需的全部或部分属性和方法时,可以让B继承A
继承与组合区别
继承:A 是 B;
组合:A 拥有B;
示例
#import <Foundation/Foundation.h> //Animal类的声明
@interface Animal : NSObject
{
int _age;//年龄
double _weight;//体重
}
//对象方法
- (void)setAge:(int)newAge;
- (int)age; - (void)setWeight:(int)newWeight;
- (double)weight; - (void)run;
@end //Animal类的实现
@implementation Animal
//方法实现
- (void)setAge:(int)newAge
{
_age = newAge;
}
- (int)age
{
return _age;
} - (void)setWeight:(int)newWeight
{
_weight = newWeight;
}
- (double)weight
{
return _weight;
} - (void)run
{
NSLog(@"动物在奔跑!");
} @end //Dog类的声明
@interface Dog : Animal
{
//int _age;//子类不能和父类的成员变量重名
int gouPai;//狗牌
}
//对象方法
- (void)run;//重写父类的方法
@end //Dog类的实现
@implementation Dog
//方法实现
- (void)run
{
NSLog(@"Dog在奔跑!");
} @end //Cat类的声明
@interface Cat : Animal
{ }
//对象方法 @end //Cat类的实现
@implementation Cat
//方法实现 @end int main()
{
Dog *d = [Dog new];
[d setAge:];
[d run];//子类的run会覆盖父类的run方法
NSLog(@"%d",[d age]); return ;
}
super关键字
如果在子类中想访问父类的方法(对象方法和类方法都可以),可以使用关键字super进行调用 ;
[super walk];//具体是对象方法还是类方法取决于调用时所处于的环境。
使用场景:子类使用父类的方法时想保留父类的一些操作
//方法实现
- (void)run
{
NSLog(@"Dog在奔跑!"); [super run];//super 关键字,调用父类的方法
}
三、多态
父类指针指向子类对象:多态
1、没有继承就没有多态
2、父指针指向子类对象
3、优点:函数/方法传入父指针,则在调用时可以传入子类指针和父类指针
4、缺点:父类类型的变量,不能直接调用子类特有的方法
代码示例
#import <Foundation/Foundation.h>
/*
多态 */ //Animal类的声明
@interface Animal : NSObject
{
// int _age;//年龄
//double _weight;//体重
}
//对象方法 - (void)eat;
@end //Animal类的实现
@implementation Animal
//方法实现
- (void)eat
{
NSLog(@"吃吃吃!");
} @end //Dog类的声明
@interface Dog : Animal
{
//int _age;//子类不能和父类的成员变量重名
//int gouPai;//狗牌
}
//对象方法
- (void)eat;//重写父类的方法
@end //Dog类的实现
@implementation Dog
//方法实现
- (void)eat
{
NSLog(@"Dog在吃吃吃!"); // [super eat];//super 关键字,调用父类的方法
} @end //Cat类的声明
@interface Cat : Animal
{
//int _age;//子类不能和父类的成员变量重名
//int gouPai;//狗牌
}
//对象方法
- (void)eat;//重写父类的方法
- (void)run;
@end //Dog类的实现
@implementation Cat
//方法实现
- (void)eat
{
NSLog(@"Cat在吃吃吃!"); // [super eat];//super 关键字,调用父类的方法
}
- (void)run
{
NSLog(@"Cat在跑!");
}
@end int main()
{
//Dog *d = [Dog new]; //父类指针指向子类对象:多态
Animal *a = [Dog new];
//[a run];//父类指针调用子类的特有方法,会有警告 Dog *d = (Dog *)a;//可以强制转换,调用子类特有的方法
[d eat]; return ;
}