#import <Foundation/Foundation.h>

@interface Base : NSObject
{
    id<NSObject> obj;
    void *ptr;
}
- (instancetype)initWithObject: (id<NSObject>)anObj pointer: (void *)aPtr;
- (void)run;
- (void)method: (id<NSObject>)anObj with: (void *)aPtr;
@end

@implementation Base

- (instancetype)initWithObject: (id<NSObject>)anObj pointer: (void *)aPtr
{
    if ((self = [super init]) != nil)
    {
	obj = [anObj retain];
	ptr = aPtr;
    }
    return self;
}

- (void)dealloc
{
    [obj release];
    [super dealloc];
}

- (void)run
{
    [self method: obj with: ptr];
}

- (void)method: (id<NSObject>)anObj with: (void *)aPtr
{
    NSLog(@"In base implementation of -method:with:");
}

@end

@interface D : Base
@end

@implementation D

- (instancetype)initWithObject: (id<NSObject>)anObj ptr: (void *)aPtr
{
    return [super initWithObject: anObj ptr: aPtr];
}

@end

@interface E : Base
@end

@implementation E

- (instancetype)initWithObject: (id<NSObject>)anObj ptr: (void *)aPtr
{
    return [super initWithObject: anObj pointer: aPtr];
}

- (void)run
{
    [super method: obj pointer: ptr];
}

@end

int
main()
{
    @autoreleasepool
    {
	NSObject *o = [NSNull null];

#define nsstr(s) @#s
#define run(v) do { NSLog(@"Calling [" nsstr(v) @" run] for %@", v); [v run]; } while (0)

	@try
	{
	    D *d = [[D alloc] initWithObject: o ptr: &o];
	    run(d);
	}
	@catch (NSException *e)
	{
	    NSLog(@"Caught exception %@", e);
	}

	@try
	{
	    E *e = [[E alloc] initWithObject: o ptr: &o];
	    run(e);
	}
	@catch (NSException *e)
	{
	    NSLog(@"Caught exception %@", e);
	}
    }
}
