zoukankan      html  css  js  c++  java
  • oc语言学习之基础知识点介绍(四):方法的重写、多态以及self、super的介绍

    一、方法重写

    /*
     重写:当子类继承了父类的方法时,如果觉得父类的方法不适合,那么可以对这个方法进行重新实现,那么这个就重写。
     
     注意:也就是说,一定只能发生在父类和子类关系中。
     
            然后是子类重新实现父类的方法,绝对不是再写一个自己类的方法。
     
        代码中原话叫:子类重写父类方法。
     
     因为父类定义的方法不一定适用于子类。
     
     注意:如果有重写,那么调用的是自己重写后的方法,如果没有重写,那么就调用的是父类的方法。
     
     所以我们方法有一个执行的过程:
            1.先去自己类里面找这个方法,如果找到就执行。
            2.如果没找到,就去父类中找,如果找到就执行。
            3.如果还是没找到,就去父类的父类中找,如果找到就执行。
            4.如果没找到继续往上找,直到直到根类(NSObject)还没找到的话,就报错!
     
     注意:子类可以重写父类的方法,但是,不能定义跟父类同名的成员变量
     
    */
    
    #import <Foundation/Foundation.h> //框架,是一个核心基础框架,里面提供了很多OC的基础语法类库,左边代表框架,右边代表这个框架里的头文件。
    /*例如:在Animal类中,有一个Cry方法,里面打印出 在叫。然而对于不同的动物来说,都有着不同的叫声,狗是 汪汪汪,猫是  喵喵喵等等,所以Animal类中的Cry方法就不通用了,这个时候 我们需要在重写这个方法。
    */
    
    /*动物类开始*/
    @interface Animal: NSObject{
           @public 
           NSString * _name;
           //......
     }
    
    -(void) Cry;
    @end
    
    @implementation Animal{
    -(void) Cry{
          NSLog(@"动物在叫。");
      }
    }
    @end
    
    /*动物类结束*/
    
    /*猫类开始*/
    @interface Cat: Animal{
           NSString * _name;
           //......
     }
    
    -(void) Cry;
    
    -(void)setName:(NSString *)name;
    
    -(NSString *)name;
    
    @end
    
    @implementation Cat{
    
    -(void)setName:(NSString *) name{
        if([name isEqualTo:@"你麻痹"]){
            _name = @"无名";
        }else{
            //给属性赋值为你传进来的参数
            _name = name;
        }
    }
    
    -(NSString *)name{
        //返回这个属性
        return _name;
    }
    
    -(void) Cry{
          NSLog(@"小猫在喵喵喵的叫。");
      }
    
    }
    @end
    /*猫类结束*/
    /*类似于猫类,可以写出狗类、猪类等*/

    二、self和super关键字

    /*
    之前说过,类方法可以调用另一个类方法,语法就是 [类名 方法名];
    那么问题来了,对象方法怎么调用另外一个对象方法??
     
     self:
        用途:
            1.可以在对象方法里面调用另外一个对象方法。
                    [self 方法名];
     
            2.当方法内局部变量和成员变量同名时,用self关键字可以显示的调用成员变量。
                语法:self->成员变量名;
     
    之前调用对象方法语法:[对象  方法名];
    调用对象属性:   对象->成员变量;
     
     当使用self的时候,self代表谁呢?
    答案:
            谁调用这个方法,这个方法里的self就是谁!!!
                例:现有Person类和Student类,里面都有sayHi和classTest1方法。
                [p sayHi];//那么此时sayHi方法里的self就是p对象
                [p2 sayHi];//那么此时sayHi方法里的self就是p2对象
                [Person classTest1];//那么此时classTest1方法里的self就是Person类
                [Student classTest1];//那么此时classTest1方法里的self就是Student类
        
     
    super:可以显示的调用父类中的方法。
    应用场景:当子类改写父类的时候,其实父类的方法功能还是需要用的,只不过又多增加一些特有的操作,那么就可以在改写的时候先用super关键字调用一下父类的原方法,然后再写需要添加的代码。
    
        super其实不代表谁,就是一个关键字,能够方便的让你调用父类的东西而已。 
    */
    //实例我就 简写了
    //Person类
    @interface Person:NSObject{
    
      }
    -(void) sayHi;
    -(void) Test1;
    @end
    @implementation  Person{
       -(void) sayHi{
           NSLog(@"Person哈哈哈");
       }
    -(void) Test1{
        [self sayHi];
        NSLog(@"Person测试");
      }
    }
    @end
    
    //Student类
    @interface Student:Preson{
    
      }
    -(void) sayHi;
    -(void) Test1;
    -(void) Test2;
    @end
    @implementation  Person{
       -(void) sayHi{
           NSLog(@"Student哈哈哈");
       }
    -(void) Test1{
        [self sayHi];
        NSLog(@"Student测试");
      }
    -(void) Test1{
        [supersayHi];
        NSLog(@"Student测试");
      }
    }
    @end
    
    #import <Foundation/Foundation.h>
    #import "Person.h"
    #import "Student.h"
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
         Person p =[Person new];
         [p Test1];//Person哈哈哈  Person测试
         
         Student stu =[Studentnew];
         [stu Test1];//Student 哈哈哈  Student 测试
    
         [stu Test2];//Person哈哈哈  Student 测试
        }
        return 0;
    }

    还有一种情况,请看代码

    //Person类
    @interface Person:NSObject{
    
      }
    -(void) Test2;
    +(void) Test3;
    @end
    @implementation  Person{
    -(void) Test2{
        NSLog(@"self=%@",self);
      }
    +(void) Test3{
        NSLog(@"self=%@",self);
      }
    }
    @end
    
    //Student类
    @interface Student:Preson{
    
      }
    -(void) StuTest2;
    +(void) StuTest3;
    @end
    @implementation  Person{
    -(void) StuTest2{
        [super Test2];
        NSLog(@"Student测试");
      }
    +(void) StuTest3{
        [super Test3];
        NSLog(@"Student测试");
      }
    }
    @end
    
    #import <Foundation/Foundation.h>
    #import "Person.h"
    #import "Student.h"
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {     
         //Student stu =[Studentnew];
         //[stu StuTest2];//打印出Student类
           [Student StuTest3];//打印出Student类
        }
        return 0;
    }

    三、访问修饰符的介绍和用法

    /*
     @public:所有地方都能访问(注意:是无论哪个地方)
     
     @protected(默认):  本类以及子类、子类的子类、子类的子类的子类………………都可以访问
    
     @private:私有的。只能在本类中访问
    
     @package(不会用):介于@public和@private之间的。只能在当前框架中使用,简单来就说就是只能在当前的项目里面用
    
     注意:哪怕是@private的,子类也可以继承到,只是不能用!(不够严谨,以后学到KVC,@private的也可以用)
     
     注意:访问修饰符的修饰范围只能是它定义的位置到下一个访问修饰符
     
     注意:访问修饰符不能修饰方法
    
    
     “私有”成员变量:
            把成员变量,写在@implementation 类名后面的大括号里面。
            这种做法可以让子类根本都看不到这个私有成员变量,但是却也继承了,其实只是欺骗了编译器,编译器以为没有,达到“私有”目的。
    
    “私有”方法同上,子类可以继承到,但是不可以直接用。
    */
    //实例:
    //写在这里就可以做到私有且子类不可见
    @implementation Person{
        int _age;
    }

     四、多态

    /*
    
    多态:同一种行为,不同的实现
    代码中实现多态的步骤:
                1.要有继承关系
                2.子类重写父类方法
                3.用父类类型的指针指向子类的对象
                4.然后调用方法
    */
    //例如:
    //动物类中的动物叫的方法
    -(void) AnimalShout(){
            NSLog(@"叫叫叫");  
    }
    //
    -(void) CatShout(){
            NSLog(@"喵喵喵");  
    }
    //
    -(void) DogShout(){
            NSLog(@"汪汪汪");  
    }
    
    //调用
    Animal ani = [Catnew];
    [ani  CatShout];//猫叫
    ani = [Dog new];
    [ani  DogShout];//狗叫

    五、类的本质和SEL类型

    /* 
        类也是存在内存里面的,存在全局区,对象存在堆区。 
        类既然存在内存里面,它是以什么类型存的呢??? 
        因为我们说要把数据存在内存里面,都要有相应的数据类型 。
        10;用int类型来存。
        10.3f; 用float类型来存。 
        它用的是类类型来存的。类类型就是Class。 
        Class是一个像int float等等一样的类型。 
        获得这个类类型的数据:
                1.[类名 class] 可以得到 
                2.[对象  class] 也可以得到    
       作用: 
            1.  new一个对象
            2.  调用类方法 
     
     注意:大写的Class是类型  小写的class是方法 
     类的本质是结构体,类其实也是一个对象,是类类型对象(Class对象); 
     
    */
    
    #import <Foundation/Foundation.h>
    @interface Person : NSObject{
        
    @public
        int _age;
    }
    
    -(void)sayHi;
    
    +(void)test;
    
    @end
    
    @implementation Person
    
    -(void)sayHi{
        NSLog(@"hello");
    }
    
    +(void)test{
        NSLog(@"类方法调用");
    }
    
    @end
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            //Person *p = [Person new];
            
            //此时就得到了Person存在全局区的类数据,所以也就是说现在cp就是我们的Person类
            Class cp = [Person class];
     
            Person *p = [Person new];//此时p是Person对象
            
            Class cp2 = [p class];//调用对象class方法
            
            NSLog(@"%p",cp);
            NSLog(@"%p",cp2);
            
            Person *p2 = [cp2 new];
            
            [p2 sayHi];
            
    //        NSLog(@"%p",[p valueForKey:@"isa"]);    
            
            //Class cp相当于写了一个objc_class *cp
            
            //怎么用呢???
            //平时类可以创建对象,那么我们可不可以用我们刚刚拿到的Class类型的数据来创建对象呢??
            /*
            Person *p = [cp new]; //等于  Person *p = [Person new];
     
            p->_age = 20;
            
            [p sayHi];
            
            Person *p2 = [Person new];
            
            p2->_age = 20;
            
            [p2 sayHi];
        */
           
    //        [Person test];
    //        [cp test];
            
        }
        return 0;
    }

    上面简单的介绍了类的本质,还有一个SEL类型,请看下面:

    /* 
     方法也是要存储。 
     方法的类型:
            SEL类型 
     
     其实类里面(Class对象)里面没有存方法的实现,而是存了一个方法的地址,这个地址就是SEL类型。 
     方法的实现存哪去了??方法的本质是函数,存在代码区。 
     我们每次调用方法,其实是把方法包装成了SEL类型,然后去类类型的对象找到它所存的方法列表,进行比对,如果比对成功,则执行,如果所有的列表(包括父类,直到NSObject)都比对完,还没有相等的就报错。 
     那么我们自己怎么获得方法的SEL类型? 
        通过
            @selector(方法名);  这个就可以得到SEL类型
    */
    
    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject
    
    -(void)sayHi;
    
    +(void)clsTest;
    
    @end
    
    @implementation Person
    
    -(void)sayHi{
        
        NSLog(@"哈哈哈哈哈");
    }
    
    +(void)clsTest{
        
        NSLog(@"我是类方法");
    }
    
    @end
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {      
    
            //怎么用SEL类型调用方法????
            //因为我们包装的是对象方法,所以先要有对象
            
            Person *p = [Person new];
            
    //        //得到SEL类型了
    //        SEL funcSay =  @selector(sayHi);
    //        
    //        [p performSelector:funcSay];
            
            [p performSelector:@selector(sayHi)]; //这句和上面两句一样
            
            //类方法应用类名调用
            [Person performSelector:@selector(clsTest)];       
        }
        return 0;
    }
  • 相关阅读:
    HDU 4782 Beautiful Soup (模拟+注意细节)
    Linux 简单socket实现UDP通信
    Linux 简单socket实现TCP通信
    HDU 1698 Just a Hook(线段树区间覆盖)
    HDU 1271 整数对(思路题)
    HDU 2222 Keywords Search (AC自动机模板题)
    Windows平台使用Gitblit搭建Git服务器图文教程
    Git克隆
    移动端布局,div按比例布局,宽度为百分比,高度和宽度一样,即让div为正方形
    calc()问题
  • 原文地址:https://www.cnblogs.com/bobo-pcb/p/4981560.html
Copyright © 2011-2022 走看看