サブクラスのインスタンスからポリモーフィズムを無視して任意のスーパークラスのメソッドを呼びます。
↓ 下のように Shape クラスと Shape クラスを継承した Path クラス、および Path クラス を継承した Circle があります。
それぞれのクラスで draw メソッドをオーバーライドしています。
#pragma mark - Shape
@interface Shape : NSObject
@end
@implementation Shape
- (void)draw {
NSLog(@"%@", @"Shape.");
}
@end
#pragma mark - Path
@interface Path : Shape
@end
@implementation Path
- (void)draw {
NSLog(@"%@", @"Path.");
}
@end
#pragma mark - Circle
@interface Circle : Path
@end
@implementation Circle
- (void)draw {
NSLog(@"%@", @"Circle.");
}
@end
↓ Circle クラスのインスタンスから draw メソッドを呼び出すと Circle クラスの draw メソッドが実行されて "Circle." と出力されます。
たまに多態性を無視してスーパークラスや、スーパークラスのさらにスーパークラスのメソッドを実行したいということってありますよね。
そういうときは 対象メソッドの IMP (メソッドを参照する関数へのポインタ) を使います。
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
Shape *shape = [[Circle alloc] init];
[shape draw];
SEL selector = @selector(draw);
void(*pathFunction)(id, SEL, ...) = (void(*)(id, SEL, ...))[Path instanceMethodForSelector:selector];
pathFunction(shape, selector);
void(*shapeFunction)(id, SEL, ...) = (void(*)(id, SEL, ...))[Shape instanceMethodForSelector:selector];
shapeFunction(shape, selector);
}
@end
↑ IMP の定義のままだと ARC が戻り値を retain しようとするので、戻り値が void の関数ポインタにキャストしています。
↓ 上記のコードの出力は下記になります。
2012-10-23 13:15:20.632 Monomorphism[50033:c07] Circle.
2012-10-23 13:15:20.633 Monomorphism[50033:c07] Path.
2012-10-23 13:15:20.633 Monomorphism[50033:c07] Shape.
サブクラスのインスタンスからポリモーフィズムを無視して任意のスーパークラスのメソッドが呼べました。
↓ 試したコードの全体を載せておきます。
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
#pragma mark - Shape
@interface Shape : NSObject
@end
@implementation Shape
- (void)draw {
NSLog(@"%@", @"Shape.");
}
@end
#pragma mark - Path
@interface Path : Shape
@end
@implementation Path
- (void)draw {
NSLog(@"%@", @"Path.");
}
@end
#pragma mark - Circle
@interface Circle : Path
@end
@implementation Circle
- (void)draw {
NSLog(@"%@", @"Circle.");
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
Shape *shape = [[Circle alloc] init];
[shape draw];
SEL selector = @selector(draw);
void(*pathFunction)(id, SEL, ...) = (void(*)(id, SEL, ...))[Path instanceMethodForSelector:selector];
pathFunction(shape, selector);
void(*shapeFunction)(id, SEL, ...) = (void(*)(id, SEL, ...))[Shape instanceMethodForSelector:selector];
shapeFunction(shape, selector);
}
@end