面试资料收集

OC的三大特性

2018-09-18  本文已影响0人  VampireJune

面向对象的三大特征:

成员变量的封装、继承、多态

1.成员变量的封装 encapsulation : setter getter 方法

@interface VampireJune : NSObject
{
  // 成员变量尽量不要用 @public 
  // @public 
  int _age;
}
// setter 方法 声明
- (void)setAge:(int)age;
// getter 方法 声明
- (int)age;

@end

@implementation VampireJune
// setter 方法 实现
- (void)setAge:(int)age
{
  // 这里可以对传进来的参数进行过滤
  _age = age;
}
// getter 方法 实现
- (int)age
{
  return _age;
}
@end
@interface VampireJune : NSObject
- (void)run;
@end

@implementation VampireJune
- (void)run
{
  // 执行一些代码
}
@end

int main()
{
  // 调用 run 类方法
  [Person run];
  return 0;
}

:对象方法中 可以使用类方法 !!但不能使用 self调类方法,会造成死循环

2.继承 inheritance :类与类之间的关系

@interface VampireJune : NSObject // 继承自 NSObject 类
@end
- 继承 :
@interface A : NSObject
{
   int _age;
}
@end

@interface B : A
{
   int _weight;
}
@end

- 组合 :
@interface A : NSObject
{
   int _age;
}
@end

@interface B : NSObject 
{
   A *_a;
   int _weight;
}
@end

3.多态 Polymorphism :多种形态

@interface Animal : NSObject 
- (void)eat;
@end

@implementation Animal
- (void)eat
{
  NSLog(@"------%@------吃东西------",self);
}

@interface Dog : Animal 
- (void)run; // Dog 特有的方法,父类 Animal 没有,验证多态局限性
@end

@implementation Dog
- (void)run
{
  NSLog(@"------Dog------跑起来------");
}

- (void)eat
{
  NSLog(@"------Dog------吃东西------");
}
@end

int main()
{
  Dog *d = [Dog new]; // Dog 类型

  // 多态 :`父类指针`指向`子类对象`
  Animal *a = [Dog new];

  // 调用方法时,会检测对象的真实类型(这就是动态检测)
  [a eat];

  // 这也是多态
  NSObject *n = [Dog new];
  NSObject *n2 = [Animal new];

  // 这样是不合理的,OC是弱语法,虽然编译器不报错,只是警告,但是也不要这么写
  // Dog *d = [Animal new]; 

  return 0;
}
@interface Cat : Animal 
@end

@implementation Cat
- (void)eat
{
  NSLog(@"------Cat------吃东西------");
}
@end

// 专门用来喂动物的函数
void feed (Animal *a)
{ // 如果参数中使用的是父类类型,可以传入父类、子类对象
  [a eat];
} // 只写一个方法,节省了写多个方法的代码

int main()
{
  Animal *a = [Animal new];
  feed(a);

  Dog *d = [Dog new];
  feed(d);

  Cat *c = [Cat new];
  feed(c);

  return 0;
}

int main()
{
  // 使用多态 调用 `run` 方法
  Animal *a = [Dog new];
  // [a run]; // 从语法角度上,这样不合理
  // 编译器肯定先去 `Animal` 里找 `run` 方法
  // 编译器找不到 `run` 方法,只报出一个警告
  // 因为调用对象方法是动态绑定,动态检测对象的真实类型
  // 然后就会去 `Dog` 里面找 `run` 方法,还是运行成功
  // 这样写不好,可以强制转换,将 `a` 转换为 `Dog *` 类型的变量
  Dog *dd = (Dog *)a;
  [dd run];

  Dog *d = [Dog new];
  [d run];

  return 0;
}
上一篇下一篇

猜你喜欢

热点阅读