Learn Objective-C, Objects (Part 5): Inheritance – Extending & Overriding
An object inherits various instance variables and methods from its superclass. However, the fundamental principles of inheritance also allow you to extend its superclass, as well as override inherited methods, replacing them with a different implementation. To illustrate this example, we will subclass our Fraction
class with a MixedNumber
class. Let’s get started!
Extending
How would we implement a mixed number? At initial glance, it looks pretty simple—and it is! A mixed number can be simply represented with an integer as the main number component, and a Fraction object for the fractional component (in fact, a class that uses another class as part of its data storage is known as a hybrid (sub)class). But the good part about inheritance is that the instance variables from its superclass—MixedNumber inherits numerator and denominator from Fraction, so we can simply use that. Therefore, the only new ivar we need to add is the integer for the numerical portion.
In Xcode, open up your FractionDemo project. Click on File > New File… Select Objective-C File, then Next. Name the file “MixedNumber”. Click Create. Create another new file. This time select Header File. Name it “MixedNumber” (should show up as “MixedNumber.h”). Click Create. Select MixedNumber.h, if it’s not already. Import “Fraction.h”, and make it a subclass of Fraction. Rather than providing the full listing, try to figure out the code by yourself. If you’re stuck, you can download the full code at the end of the post. Add an NSInteger
for the wholeNumber
portion, and synthesize it.
In MixedNumber.m, add the following method implementations:
- (void)setWholeNumber:(NSInteger)number andNumerator:(NSInteger)num overDenominator:(NSInteger)denom {
self.wholeNumber = number;
self.numerator = num;
self.denominator = denom;
}
- (void)setWholeNumber:(NSInteger)number andFraction:(Fraction *)frac {
self.wholeNumber = number;
self.numerator = frac.numerator;
self.denominator = frac.denominator;
}
- (void)display {
NSString *numberString = [[NSString alloc] initWithFormat:@"%d", self.wholeNumber];
NSString *numeratorString = [[NSString alloc] initWithFormat:@"%d", self.numerator];
NSString *denominatorString = [[NSString alloc] initWithFormat:@"%d", self.denominator];
NSLog(@"%@+(%@/%@)", numberString, numeratorString, denominatorString);
[denominatorString release];
[numeratorString release];
[numberString release];
}
+ (MixedNumber *)addMixedNumber:(MixedNumber *)num1 toMixedNumber:(MixedNumber *)num2 {
// Store result in "result"
MixedNumber *result = [[[MixedNumber alloc] init] autorelease];
result.wholeNumber = num1.wholeNumber + num2.wholeNumber;
result.numerator = num1.numerator * num2.denominator + num1.denominator * num2.numerator;
result.denominator = num1.denominator * num2.denominator;
// Reduce
if (result.numerator > result.denominator) {
int extra = result.numerator / result.denominator;
result.wholeNumber += extra; // Taking advantage of integer division
result.numerator -= extra * result.denominator;
int u = result.numerator;
int v = result.denominator;
int temp = 0;
// Euclid's procedure to find GCD (Greatest Common Denominator)
// Don't worry about how this works, exactly.
while (v != 0) {
temp = u % v;
u = v;
v = temp;
}
result.numerator /= u;
result.denominator /= u;
}
return result;
}
Make sure to add the method declarations to the header.
A few things to note here:
-
The first two methods are similar to the set… methods of the Fraction class—nothing new or interesting here.
-
The
display
method is interesting- it has the same name as its superclass,Fraction
. This invokes the inheritance chain—the runtime will find the version ofdisplay
that is closest to MixedNumber. Therefore, it will call this latter implementation rather thanFraction
’s. -
The add method is a class method (for extra practice, declare and implement all four instance methods and the remaining three class methods). Here, we add the whole number portions, and properly add the fractional components. We reduce, first by checking and making sure that the fraction is actually less than one, and then using Euclid’s method to reduce our resulting fraction.
Note that a subclass can call one of its (direct) superclass’s overridden methods by using the super keyword:
[super display];
This works in much the same way as the self keyword, except that the latter refers to the current instance, while the former refers to the superclass.
A test routine for the MixedNumber class:
...
// bFraction is declared previously
MixedNumber *aMixedNum = [[MixedNumber alloc] init];
MixedNumber *bMixedNum = [[MixedNumber alloc] init];
[aMixedNum setWholeNumber:3 andNumerator:2 overDenominator:4];
[bMixedNum setWholeNumber:4 andFraction:bFraction];
NSLog(@"aMixedNum is"); [aMixedNum display];
// Uses Fraction's reduce method on the fractional portion of MixedNumber
NSLog(@"After reducing, aMixedNum is"); [aMixedNum reduce]; [aMixedNum display];
NSLog(@"Addition: ");
[aMixedNum display]; NSLog(@" + "); [bMixedNum display]; NSLog(@" = ");
[[MixedNumber addMixedNumber:aMixedNum toMixedNumber:bMixedNum] display];
// display is invoked on the return value of the add method
[bFraction release];
[aMixedNum release];
[bMixedNum release];
...
The code is rather self-explanatory, but make sure you understand which method is called, and which method is actually being found in the inheritance chain, especially when you start to override methods.
The output is:
aMixedNum is
3+(2/4)
After reducing, aMixedNum is
3+(1/2)
Addition:
3+(1/2)
+
4+(1/3)
=
7+(5/6)
You can find the latest demo source code right here.
This post is part of the Learn Objective-C in 24 Days course.
Previous Lesson | Next Lesson |