深入解析macOS 10.14.2中的重载与重写:面向对象编程基础概念详解
macOS 10.14.2

前言
重载和覆盖是面向对象语言中两个非常基本的概念。本文将讨论Obj-C中的重载和重写。
超载
在某些编程语言中,函数重载或方法重载是创建具有不同实现的同名多个函数的能力。对重载函数的调用将运行适合于调用上下文的该函数的特定实现,从而允许一个函数调用根据上下文执行不同的任务。
函数重载 - 维基百科
翻译:
在某些编程语言中,函数重载或方法重载是指创建具有相同名称但具有不同实现的多个函数的能力。调用重载函数将执行上下文函数调用,允许函数调用根据上下文执行不同的任务。
函数重载 - 维基百科
正如维基百科所说,简单来说,重载是指同一个类中具有相同函数名但参数数量不同或参数类型不同或返回值不同的函数。但由于 Obj-C 是一种消息结构语言,因此方法调用在其意义上本质上是消息传递。
@interface Computer : NSObject
- (void)run;
- (void)run:(NSString *)sth;
@end
@implementation Computer
- (void)run {
NSLog(@"run");
}
- (void)run:(NSString *)sth {
NSLog(@"run - %@", sth);
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Computer *cpt = [[Computer alloc] init];
[cpt run];
[cpt run:@"sth"];
}
return 0;
}
我们定义一个继承自 NSObject 的 Computer 类,并且有两个实例方法。尝试将上面的代码翻译成C++,xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-64.cpp。由于 Obj-C 是一种消息结构语言,因此 objc_msgSend 是其消息传输的地方。我们可以发现原来的方法已经变成了字符串:sel_registerName("alloc")、sel_registerName("init")、sel_registerName("run")和sel_registerName("run:")。事实上,这些字符串是 Obj-C 方法的方法名称。方法名称忽略参数名称和返回值。实例方法和类方法的区别只是消息接收对象不同。所以严格来说,Obj-C不支持方法重载,因为它不允许存在同名函数。但如果不同数量的参数也是方法重载,Obj-C 只支持不同数量参数的重载。每个参数都会在方法名后面多生成一个:,以便于区分。
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
Computer *cpt = ((Computer *(*)(id, SEL))(void *)objc_msgSend)((id)((Computer *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Computer"), sel_registerName("alloc")), sel_registerName("init"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)cpt, sel_registerName("run"));
((void (*)(id, SEL, NSString *))(void *)objc_msgSend)((id)cpt, sel_registerName("run:"), (NSString *)&__NSConstantStringImpl__var_folders_qt_ctbfp1yd2gn7bv6y6v6qgvgm0000gn_T_main_ea7dac_mi_0);
}
return 0;
}
改写
在面向对象编程中,方法重写是一种语言功能,允许子类或子类提供其超类或父类之一已提供的方法的特定实现。子类中的实现通过提供与父类中的方法具有相同名称、相同参数或签名以及相同返回类型的方法来覆盖(替换)超类中的实现。执行的方法的版本将由用于调用它的对象确定。如果使用父类的对象调用方法,则执行父类中的版本,如果使用子类的对象调用方法,则执行子类中的版本。有些语言允许程序员防止方法被重写。
方法重写 - 维基百科
翻译:
在面向对象编程中,方法重写是一种语言功能,允许子类提供其父类或超类已提供的特定方法的实现。子类中的实现通过提供与超类中的方法具有相同名称、相同参数或签名以及相同返回类型的方法来覆盖(替换)超类中的实现。执行方法的版本将由调用对象确定。如果使用父类对象调用该方法,则将执行父类中的版本,但如果使用子类对象调用该方法,则将执行子类中的版本。有些语言允许程序员防止方法被重写。
方法重写 - 维基百科
@interface Mac : Computer
@end
@implementation Mac
- (void)run:(NSString *)sth {
NSLog(@"Mac - run - %@", sth);
}
@end
与重载完全不同,重写是指在子类中重写父类的方法,并且方法名称、参数类型、参数个数、返回值类型等必须一致。 Obj-C 完全支持方法重写:
Computer *cpt = [[Computer alloc] init];
[cpt run:@"cpt_run"];
Computer *mac = [[Mac alloc] init];
[mac run:@"mac_run"];
// OUTPUT:
// run - cpt_run
// Mac - run - mac_run
参考