Objective-C中的方法重载与初始化方法

时间:2023-01-09 19:47:49

一、方法重载
OC中其实没有严格的方法重载。方法重载应该是参数个数不一样的“同名”方法,例如在下面的代码中:

#import <Foundation/Foundation.h>

@interface Parent : NSObject

-(void) MethodWithArgsX:(double)x Y:(double)y;//1
-(void) MethodWithArgsX:(double)x Y:(int)y;//2
-(int) MethodWithArgsX:(double)x Y:(double)y;//3
-(void) MethodWithArgsX:(double)x AndY:(double)y;//4
-(void) MethodWithArgsX:(double)x AndY:(double)y :(double)Z;//5

@end

方法123对于oc意味着同一个方法, 若123同时存在,则23都提示编译错误(重复声明MethodWithArgsX:Y:方法):

Duplicate declaration of method 'MethodWithArgsX:Y:'

对于方法5,其方法明为MethodWithArgsX: AndY::,多个冒号,多一个参数,因此不会与方法4构成冲突。
即OC不管参数类型和返回值,方法名称和参数个数相等的,都认为是同一个方法的重复声明。
@selector指令也证明了这一点,该指令不管返回值类型,不管参数类型,仅仅使用方法名来确定一个方法(方法名其实确定了参数个数,几个冒号就几个参数),例如:

 @selector(viewWillTransitionToSize:withTransitionCoordinator:)

二、初始化方法
初始化方法约定以init开头,执行对对象的初始化工作。很多资料中也提到oc中可以以new简写来代替alloc和init的嵌套使用。

对于我这样有过C++编程经验的初学者来说,似乎这样的概念和C++中的构造函数相“对应”,而dealloc则对应C++中的析构函数,执行清理工作。实际上在使用中发现,虽然二者的用处确实是一样,但是实际上还是有很大不同的。看代码:
父类.h文件:

@interface Parent : NSObject -(Parent*) initWithName:(NSString*)name;
@end

父类.m文件:

@implementation Parent

-(Parent*) initWithName:(NSString*)name{
    if(self=[super init]){
        NSLog(@"call initWithName of Parent");
    }
    return self;
}
@end

子类.h文件:

@interface Son : Parent
@end
@interface ClassNoParent
@end

子类.m文件:

@implementation Son

-(Son*) initWithName:(NSString*)name{
    NSLog(@"call initWithName of Son");
    return [self init];
}
@end

在main中进行测试:

Parent* p0=[[Parent alloc] initWithName:@""];
        NSLog(@"//>>>>");
        Parent* p1=[[Son alloc] initWithName:@""];
        //ClassNoParent* p3=[ClassNoParent init];// No known class method for selector 'init'
        //ClassNoParent* p4=[[ClassNoParent alloc ]init];// No known class method for selector 'alloc'

输出结果为:
call initWithName of Parent
//>>>>
call initWithName of Son
C++构造函数的执行过程其实颇为复杂,大概过程:
–>编译器为对象分配内存空间并调用该类的构造函数
–>执行初始化列表
–>进入构造函数体
–>显式地调用直接基类的某个构造函数,否则,将会自动其直接基类的默认构造函数。(如果用户并没有显示地定义任何构造函数,编译器会为它自动生成一个默认构造函数)。

而观察上述执行结果,有两点可知:
其一,子类的init并不会自动调用父类的init,因此初始化方法中一般都需要显式调用父类的指定初始化方法。
其二,默认的init方法其实是从NSObject继承来的,类并不会自己添加默认的init方法,虽然ClassNoParent这样的写法本身就是错误的,但是可以看到ClassNoParent没有继承自NSObject,因此没有init。

另外,对于继承关系中,方法覆盖的判定与重载一样,子类中只要是与父类方法名称一致的,就构成了覆盖,例如在Parent类中增加方法:

-(void) method:(double)d{ NSLog(@"call method of Parent"); }

子类Son中对应增加

-(void) method:(NSString*)s{ NSLog(@"call method of Son %@",s); }

测试代码中增加:

[p0 method:0];
[p1 method:0];

输出为:

call method of Parent call method of Son (null)

可见子类中即使修改了参数类型,仍然对method方法构成了覆盖。而这里使用0调用参数类型为NSString的子类method竟然没有出错,输出为null,这里面的详细过程不得而知,并不清楚为什么不会出错。

Ps:写这些简单的博客实为记录自己的学习过程,尽量将这些知识正确地写出来,以期对学习内容有个巩固。看到的朋友如果对您有帮助,那是出乎目前阶段的我的意料了。虽然是基础知识,但也可能存在一些误解。高手如发现错误,也请不吝指正。