Implement a pure virtual method in Objective-C

21,927

Solution 1

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.

Solution 2

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.

Solution 3

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.

Solution 4

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

Solution 5

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.

Share:
21,927
Chris
Author by

Chris

Updated on July 25, 2022

Comments

  • Chris
    Chris almost 2 years

    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?

  • Stephen Furlani
    Stephen Furlani over 13 years
    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.
  • JeremyP
    JeremyP over 13 years
    @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++
  • JeremyP
    JeremyP over 13 years
    Exceptions are perfectly fine for throwing if a subclass fails to implement a method it is mandatory to do so.
  • Stephen Furlani
    Stephen Furlani over 13 years
    @JeremyP, that's true. Personally, I think that's a good thing.
  • justin
    justin over 13 years
    @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.
  • justin
    justin over 13 years
    @JeremyP 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.
  • DarkDust
    DarkDust over 13 years
    @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.
  • JeremyP
    JeremyP over 13 years
    @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.
  • DarkDust
    DarkDust over 13 years
    @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 ;-)
  • JeremyP
    JeremyP over 13 years
    @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.
  • DarkDust
    DarkDust over 13 years
    @JeremyP: Which is why I'm favoring an NSAssert.
  • justin
    justin over 13 years
    @JeremyP 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.
  • justin
    justin over 13 years
    @JeremyP hypothetical question: why would throwing an exception be an improvement over termination from the call site in the cases where app termination is 'ideal'?
  • JeremyP
    JeremyP over 13 years
    @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.
  • João Portela
    João Portela almost 13 years
    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?
  • Glenn Maynard
    Glenn Maynard almost 12 years
    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.
  • JeremyP
    JeremyP almost 12 years
    @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.
  • Glenn Maynard
    Glenn Maynard almost 12 years
    "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.
  • evya
    evya over 11 years
    virtual method should look this: - (UIImage*)getImage{ @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] userInfo:nil]; }
  • JeremyP
    JeremyP over 11 years
    @evya That's how to implement the equivalent of an abstract method.
  • chakrit
    chakrit over 11 years
    @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.
  • Luc Bloom
    Luc Bloom almost 10 years
    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/referen‌​ce/…
  • Dimitar Nestorov
    Dimitar Nestorov over 2 years