一、封装
封装其实是成员变量的封装,封装可以使外界不能直接访问成员变量,从而保证数据安全性。
set方法:
作用:提供一个方法给外界设置成员变量值,可以在set方法中对参数进行过滤。
命名规范:
1>方法名必须以set开头
2>set后面跟上成员变量的名称,且成员变量名称首字母必须大写
3>返回值一定是void
4>一定要接收一个参数,而且参数类型跟成员变量类型一致
5>形参的名称不要跟成员变量名一样
get方法:
作用:返回对象内部的成员变量
命名规范:
1>肯定有返回值,返回值类型与成员变量类型一致
2>方法名跟成员变量名一致
3>不需要接收任何参数
成员变量的命名规范
成员变量都以下划线 _ 开头
可以跟get方法的名称区分开,get方法名不加_
可以跟其他局部变量区分开,一看到下划线开头的变量,肯定是成员变量
/*
设计一个成绩类
属性:
C成绩,可读可写
OC成绩,可读可写
总分,只读
平均分,只读
*/
#import <Foundation/Foundation.h>
@interface Score : NSObject
{
double _cScore;
double _ocScoer;
double _sum;
double _average;
}
- (void)setCSore:(double)cScore;
- (double)cScore;
- (void)setOCScore:(double)ocScore;
- (double)ocScore;
- (double)sum;
- (double)average;
@end
@implementation Score
- (void)setCSore:(double)cScore
{
_cScore=cScore;
_sum=_cScore+_ocScoer;//每设置一个成绩就将总分算一遍
}
- (double)cScore
{
return _cScore;
}
- (void)setOCScore:(double)ocScore
{
_ocScoer=ocScore;
_sum=_cScore+_ocScoer;
}
- (double)ocScore
{
return _ocScoer;
}
- (double)sum
{
return _sum;
}
- (double)average
{
return _sum/2;
}
@end
int main()
{
Score *score=[Score new];
[score setCSore:1];
[score setOCScore:1];
double sum=[score sum];
double average=[score average];
NSLog(@"sum-----%0.2f,average------%0.2f",sum,average);
return 0;
}
不允许有相同的对象方法或者类方法,但是可以允许类方法和对象方法同名
对象方法中可以调用类方法。
对象方法:
1>减号- 开头
2>只能由对象来调用
3>对象方法中能访问当前对象的成员变量(实例变量)
类方法:
1>加号 + 开头
2>只能由类来调用
3>类方法中不能访问成员变量(实例变量)
类方法的好处和使用场合:
1>不依赖于对象,执行效率高
2>能用类方法尽量用类方法
3>当方法中不需要使用到成员变量时,就可以改为类方法。
//设计一个计算器类,求和、求平均值方法
#import <Foundation/Foundation.h>
//工具类:基本没有成员变量,方法基本都是类方法
@interface jiSuanQi : NSObject
+ (int)sumWithNum1:(int)num1 andNum2:(int)num2;
+ (double)averageWithNum1:(int)num1 andNum2:(int)num2;
@end
@implementation jiSuanQi
+ (int)sumWithNum1:(int)num1 andNum2:(int)num2
{
return num1+num2;
}
+ (double)averageWithNum1:(int)num1 andNum2:(int)num2
{
return [jiSuanQi sumWithNum1:num1 andNum2:num2]/2.0;
}
@end
int main()
{
NSLog(@"%d",[jiSuanQi sumWithNum1:23 andNum2:34]);
NSLog(@"%0.2f",[jiSuanQi averageWithNum1:34 andNum2:54]);
return 0;
}
三、self
1.概念:是个指针,指向当前对象(方法调用者)
2.用途:
可以利用self->成员变量名 来访问当前对象内部的成员变量
[self 方法名]可以调用其他对象方法或者类方法
注意:self和函数就不要掺合了
//设计一个计算器类,求和、求平均值方法
#import <Foundation/Foundation.h>
//工具类:基本没有成员变量,方法基本都是类方法
@interface jiSuanQi : NSObject
{
int _num;
}
- (void)setNum:(int)num;
+ (int)sumWithNum1:(int)num1 andNum2:(int)num2;
+ (double)averageWithNum1:(int)num1 andNum2:(int)num2;
@end
@implementation jiSuanQi
- (void)setNum:(int)num
{
_num=num;
}
- (void)test:(int)num
{
int _num=num;
//NSLog(@"%d",_num); 这是访问的这个方法中的_num
NSLog(@"%d",self->_num);
}
+ (int)sumWithNum1:(int)num1 andNum2:(int)num2
{
return num1+num2;
}
+ (double)averageWithNum1:(int)num1 andNum2:(int)num2
{
//self代表当前类
return [self sumWithNum1:num1 andNum2:num2]/2.0;
}
@end
int main()
{
NSLog(@"%d",[jiSuanQi sumWithNum1:23 andNum2:34]);
NSLog(@"%0.2f",[jiSuanQi averageWithNum1:34 andNum2:54]);
jiSuanQi *j=[jiSuanQi new];
[j setNum:23];
[j test:90];
return 0;
}
四、继承
继承的好处:
1>抽取重复代码
2>建立了类之间的关系
3>子类可以拥有父类中的所有成员变量和方法
注意:基本上所有类的基类都是NSObject
继承使用注意:
1>父类声明要在子类前面(声明必须在前面,实现可以不在前面)
2>不允许子类和父类拥有相同名称的成员变量
3>子类和父类的方法可以同名。子类重新实现父类的某个方法叫重写,覆盖了父类的方法。
4>调用某个对象的方法时,优先去当前对象找,找不到再去父类找。
类方法也满足这些。
5>内存中每个类都有个superclass指针,指针父类。在当前类找不到某个方法就会顺着这个指针去父类里找
继承的坏处:耦合性太强(两个类的关系太密切)
继承的使用场合:
1>当两个类拥有相同属性和方法的时候,就可以将相同的东西抽取到一个类中。
2>当A类拥有B类中的部分属性和方法时,可考虑让B继承A。
类之间的关系:
继承——xx是xxx
组合——xx拥有xxx
super作用:
1>可直接调用父类中的某个方法
2>若super在类方法中,就调用类方法
若super在对象方法中,就调用对象方法
3>使用场景:子类重写父类方法时,想保留父类的行为
/*
定义三个类:Person、Student、Score(成绩)
Student和Person是继承关系,Student和Score是组合关系
*/
#import <Foundation/Foundation.h>
//Score类
@interface Score : NSObject
{
@public
int _cScore;
}
- (void)setCScore:(int)cScore;
@end
@implementation Score
- (void)setCScore:(int)cScore
{
_cScore=cScore;
}
@end
//Person类
@interface Person : NSObject
{
int _age;
}
-(void)setAge:(int)age;
-(void)said;
+(void)live;
@end
@implementation Person
-(void)setAge:(int)age
{
_age=age;
}
- (void)said
{
NSLog(@"age=%d",self->_age);
}
+(void)live
{
NSLog(@"eat and sleep");
}
@end
//Student类
@interface Student : Person
{
//int _age; 不能喝父类拥有同名的成员变量
char *_name;
@public
Score *score;
}
@end
@implementation Student
//重写父类的对象方法
- (void)said
{
[super said];
NSLog(@"cScore=%d",score->_cScore);
}
//重写父类方法
+(void)live
{
NSLog(@"stady");
[super live];//使用super关键字,调用父类的live方法,用来保留父类的某些行为
}
@end
int main()
{
Student *student=[Student new];//创建Student对象
Score *sc=[Score new];//创建Score对象
student->score=sc;//给Student内部的score赋值
[student setAge:23];
[student->score setCScore:90];
[Student live];
[student said];
return 0;
}
五、多态
概念:没有继承就没有多态,即多态的前提是有继承。多态就是父类类型指针指向子类对象。
#import <Foundation/Foundation.h>
//Animal类
@interface Animal : NSObject
{
int age;
}
- (void)eat;
@end
@implementation Animal
- (void)eat
{
NSLog(@"Animal--吃");
}
- (void)sleep
{
NSLog(@"Animal--睡觉");
}
@end
//Dog类,继承Animal
@interface Dog : Animal
- (void)eat;
- (void)test;
@end
@implementation Dog
- (void)eat
{
NSLog(@"Dog--吃");
}
- (void)test
{
NSLog(@"咬人");
}
@end
//Cat类,继承Animal
@interface Cat : Animal
- (void)eat;
@end
@implementation Cat
- (void)eat
{
NSLog(@"Cat--吃");
}
@end
void feet(Animal *animal)//假如没有多态,那么这个参数类型将是Cat *或者Dog *。那么这个功能
{ //用一个函数不能实现。因此多态的好处就显而易见
NSLog(@"喂动物");
}
int main()
{
Animal *a=[Dog new];//父类指针指向子类对象
[a eat];//输出结果为 Dog--吃
//程序运行时,会真正去确定a的真实类型,然后调用这个真实类型的方法,这是动态检测
[a sleep];//由于Dog中没有这个方法,所以就调用父类的
/*
[a test];//编译时会警告可能没有这个方法,但是编译器是动态检测,所以程序可以正常运行.
但是不建议这么做,父类类型的指针变量不能用来调用子类的特有方法。要想调用必须
先强制转换
*/
Dog *d=(Dog *)a;//类型强制转换
[d test];
feet(a);//调用函数
return 0;
}
总结:
1>没有继承就不会有多态
2>多态是父类指针指向子类对象
3>好处--函数/方法参数使用父类,实参可以是子类或者父类类型
4>父类类型指针不能直接调用子类特有方法,若想调用,必须先强制转换为子类类型。
5>父类类型指针调用子类方法,若子类已重写,那就调用子类的。子类没重写,那就是父类的。