Implement a pure virtual method in Objective-C
Asked Answered
D

6

41

I want to go to there. Seriously though, how does one implement a pure virtual method in an "Apple" way? Do you use a Protocol with your base class and throw exceptions on those methods?

Devastate answered 7/3, 2011 at 16:19 Comment(1)
It's a good question for people coming from a strong OO C++ background.Aggappera
K
55

When you program in Objective-C you need to purge your mind of such things as virtual methods. You don't call methods on Objective-C objects, you send messages to them. Objects either respond to messages or they don't, but due to the dynamic binding, you can't tell this until run time.

Thus, you can declare a method on a base object and not not provide an implementation, no problem (except for the compiler warning), but you can't have the compiler flag up when you directly instantiate an object with such methods and it won't throw an error at runtime unless you actually send that message to the object.

The best way to create "virtual" base classes (in my opinion) is to declare the method and give it a stub implementation that throws a suitable exception.

Kreindler answered 7/3, 2011 at 16:31 Comment(8)
what is the convention of where I should declare the method to be implemented? do I put it in the superclass interface with a comment next to it?Narvaez
Sorry, it's just silly to pretend that "sending messages" in ObjC is somehow magically different than function calling and needs its own name. Maybe it seemed that way back in the day, before we all learned how function binding doesn't have to be static, but today we all know that they're all just functions, regardless of the binding mechanism.Longmire
@GlennMaynard No, it is not silly. It's fundamental to the OO model that Objective-C inherited from Smalltalk. The selector and the method are different things.Kreindler
"Selectors" are nothing but first-class function signatures, and "sending a message" is nothing but finding and calling a function with that signature. It's all the same thing.Longmire
virtual method should look this: - (UIImage*)getImage{ @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] userInfo:nil]; }Jardena
@Jardena That's how to implement the equivalent of an abstract method.Kreindler
@GlennMaynard I don't think anyone is pretending. They simply realize the subtle differences as they wrote lots of ObjC. It is indeed very similar to signature finding and method calling but if you limit yourself to that model of thought you're just missing out on a lot of the niceties of ObjC. "sending a message" is much more than finding and calling a function with that signature. For example, you can have things like NSProxy that transforms message passing through them, or JSON parser pseudo-object that treat getter messages (non-existent methods) as access to JSON hash key values.Slum
From Antony Clements: Put this code in the implementation of the base class: [self doesNotRecognizeSelector:_cmd]; As noted by Apple, here: developer.apple.com/library/mac/#documentation/cocoa/reference/…Paralysis
N
33

In Objective-C, there is no pure virtual support as in C++.

A simulation would be that you declare a method in your interface but don't implement it in your .m file. Of course you'd get compiler warnings but IIRC you can turn those off. But you won't get warnings/errors if you don't overwrite them in the subclass, which you get in C++ (IIRC).

An alternative would be to implement them with just an NSAssert(NO, @"Subclasses need to overwrite this method"); body. Still, you'd only catch this at runtime, not compiletime.

Neddra answered 7/3, 2011 at 16:28 Comment(0)
I
7

Depending on what you're doing the delegate pattern may be more appropriate than a subclass, where the delegate is defined as id<YourDelegateProtocol>. The compiler will generate a warning if the required methods in the delegate protocol are not implemented.

Subclassing is generally avoided in Objective-C since objects cannot inherit from multiple superclasses but they can implement multiple protocols.

Infix answered 7/3, 2011 at 18:18 Comment(4)
every object in Objective-C is a subclass of NSObject. So I'd say that Subclassing is pretty important, and not 'generally avoided'. It occurs every time I make a custom view, table, or controller.Bereft
@Stephen: True, but what is generally avoided is deep hierarchies of subclasses. It's used much less often than in languages like Java and C++Kreindler
@JeremyP, that's true. Personally, I think that's a good thing.Bereft
@Stephan Furlani not every class in objc is a subclass of NSObject. a) not all objc systems/libraries are derived or inherit from nextstep b) even when interfacing with Apple's libraries only, you can still encounter root classes in the wild (for various reasons); NSProxy is one public example of this.Minster
T
6

You should use the:

- (void)doesNotRecognizeSelector:(SEL)aSelector method. 

As noted by Apple, here: https://developer.apple.com/library/mac/#documentation/cocoa/reference/Foundation/Classes/NSObject_Class/Reference/Reference.html

Thurnau answered 21/1, 2013 at 11:2 Comment(1)
Working docs link: developer.apple.com/documentation/objectivec/nsobject/…Austenite
M
2

You have a few options, but you're on the right track.

ObjC doesn't support this directly, forcing subclasses to implement a protocol is the best way to check it at compilation.

'Secretly' implementing the method in the base class and asserting is what I do to confirm the subclasser has subclassed correctly at runtime. Some people have mixed feelings about assertions, or must leave them active, so that's not always a good solution.

You can also force subclasses use a specific class constructor and initialization sequence, then verify they have implemented everything required before returning an instance, in case compiler warnings don't cut it.

But ObjC is missing some lang features which allow clients to shoot themselves in the foot, or workaround what they wish so... you shouldn't get too stuck on enforcing it.

note: Exceptions are very uncommon (and a bit unsafe, too) in ObjC.

Minster answered 7/3, 2011 at 16:40 Comment(10)
Exceptions are perfectly fine for throwing if a subclass fails to implement a method it is mandatory to do so.Kreindler
@Kreindler no, they're not unconditionally fine. in fact, you're asking for UB when the exception crosses module boundaries. anyone throwing an exception makes the (potentially false) assumption that the client has enabled support for objc exceptions in all modules. it's far safer and far more idiomatic to return 0 (and assert and/or log a message) if the client fails to meet the api's requirement(s). you'll not make friends with your clients if that ships -- even though they failed to meet your object's requirements.Minster
@JeremyP: Apart from the points Justin made, there's also the memory problem: if you're in a GC environment this is not an issue, but in a "traditional" reference counting environment you face the problem of memory leaks. Consider: Allocate an object, call a method "foo", release object. If "foo" now throws an exception the allocated object is never released.Neddra
@DarkDust, @Justin: this would be considered a programming error and therefore not really recoverable, much like a range exception or a null pointer dereference. Ideally, the program would terminate at that point, so memory leaks are not a concern.Kreindler
@JeremyP: If all you want is app termination then yes, exceptions are fine in this very scenario (thrown when an unimplemented method is called). Let's just hope nobody catches it, though ;-)Neddra
@DarkDust: You'd have to say the same about an NSRangeException or a "does not respond to this selector" exception both of which are thrown by the runtime.Kreindler
@JeremyP: Which is why I'm favoring an NSAssert.Neddra
@Kreindler the OP never stated that the client's failure to implement the interface is fatal or not -- you can fail more gracefully than exceptions and abort/termination in most_real_world_cases. returning 0 is the primary indication to the client that something went wrong along the way. in most cases, it's better to let the client decide how to handle the situation -- they know the context of its invocation and consequences. meanwhile, you've done what you can by disallowing an object's use by returning 0.Minster
@Kreindler hypothetical question: why would throwing an exception be an improvement over termination from the call site in the cases where app termination is 'ideal'?Minster
@Justin: The OP wanted something equivalent to pure virtual functions. If such things aren't implemented be subclasses in C++ or Java, you will get a compiler error. The designer of the superclass is saying "suclasses must implement this method". If they don't it is a programming error, in much the same way that sending a message to an object to which it doesn't respond is a programming error, or indexing off the end of an array is a programming error.Kreindler
P
0

A virtual method is a method whose behavior can be overridden within an inheriting class by a function with the same signature (i.e same name with same number of params and type of params).

Example:-

@implementation BaseClass

-(void)viewDidLoad
{
 [self virtualMethod:123];
}

-(void)virtualMethod:(int)param
{
 //implement this method in subclass
}

@end

////////////////////////////////////////////////////

@interface ChildClass:BaseClass
@end

@implementation ChildClass

-(void)virtualMethod:(int)param
{
 NSLog(@"There is no keyword "Virtual" in Objective C.");
}
@end

Output:-

"There is no keyword "Virtual" in Objective C."

Papke answered 12/4, 2013 at 9:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.