18
Inheritance

When you created the Person class, you declared it to be a subclass of NSObject. This means that every instance of Person will have the instance variables and methods defined in NSObject as well as the instance variables and methods defined in Person. We say that Person inherits the instance variables and methods from NSObject. In this section, we are going to delve a bit into inheritance.

Open up the BMITime project and create a new file: an Objective-C class. Name it Employee and create it as a subclass of NSObject. Soon, we will change the Employee class to be a subclass of Person. Makes sense, right? Employees are people. They have heights and weights. However, not all people are employees. We’ll also add an employee-specific instance variable to our class – an employee ID.

Figure 18.1  Inheritance diagram of some classes you know

Inheritance diagram of some classes you know

Open Employee.h. Import Person.h, change the superclass to Person, and add an instance variable to hold the employee’s ID number:

#​i​m​p​o​r​t​ ​"​P​e​r​s​o​n​.​h​"​

@​i​n​t​e​r​f​a​c​e​ ​E​m​p​l​o​y​e​e​ ​:​ ​P​e​r​s​o​n​
{​
 ​ ​ ​ ​i​n​t​ ​e​m​p​l​o​y​e​e​I​D​;​
}​
@​p​r​o​p​e​r​t​y​ ​i​n​t​ ​e​m​p​l​o​y​e​e​I​D​;​
@​e​n​d​

Open Employee.m and synthesize the accessors:

#​i​m​p​o​r​t​ ​"​E​m​p​l​o​y​e​e​.​h​"​
@​i​m​p​l​e​m​e​n​t​a​t​i​o​n​ ​E​m​p​l​o​y​e​e​

@​s​y​n​t​h​e​s​i​z​e​ ​e​m​p​l​o​y​e​e​I​D​;​

@​e​n​d​

Now you have a new Employee class with all the instance variables of Person and a new instance variable called employeeID. Instances of Employee will respond to all the same messages that an instance of Person will. Instances of Employee will also respond to the messages setEmployeeID: and employeeID.

And, because Person inherits from NSObject, Employee also inherits all the instance variables and methods from NSObject. All objects inherit (either directly or indirectly) from NSObject.

NSObject has many methods, but only one instance variable: the isa pointer. Every object’s isa pointer points back to the class that created it.

Figure 18.2  Object diagram for BMITime

Object diagram for BMITime

Let’s say that you send the message fido to an object. In order to respond to this message, the object uses the isa pointer to find its class and ask, Do you have an instance method named fido? If the class has a method named fido, it gets executed. If the class doesn’t have a fido method, it asks its superclass, Do you have an instance method called fido? And up, up the chain it goes on the hunt for a method named fido. The hunt stops when the method is found or when the top of the chain is reached. At the top of the chain, NSObject says, Nope, no fido method. Then you get an error message that says something like This instance of Employee does not respond to the fido selector.

Try it. Open up main.m and send the instance of Person a message it won’t understand:

i​n​t​ ​m​a​i​n​(​i​n​t​ ​a​r​g​c​,​ ​c​o​n​s​t​ ​c​h​a​r​ ​*​ ​a​r​g​v​[​]​)​
{​
 ​ ​ ​ ​@​a​u​t​o​r​e​l​e​a​s​e​p​o​o​l​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​n​ ​i​n​s​t​a​n​c​e​ ​o​f​ ​P​e​r​s​o​n​
 ​ ​ ​ ​ ​ ​ ​ ​i​d​ ​p​e​r​s​o​n​ ​=​ ​[​[​P​e​r​s​o​n​ ​a​l​l​o​c​]​ ​i​n​i​t​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​G​i​v​e​ ​t​h​e​ ​i​n​s​t​a​n​c​e​ ​v​a​r​i​a​b​l​e​s​ ​i​n​t​e​r​e​s​t​i​n​g​ ​v​a​l​u​e​s​
 ​ ​ ​ ​ ​ ​ ​ ​[​p​e​r​s​o​n​ ​s​e​t​W​e​i​g​h​t​I​n​K​i​l​o​s​:​9​6​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​[​p​e​r​s​o​n​ ​s​e​t​H​e​i​g​h​t​I​n​M​e​t​e​r​s​:​1​.​8​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​a​l​l​ ​t​h​e​ ​b​o​d​y​M​a​s​s​I​n​d​e​x​ ​m​e​t​h​o​d​
 ​ ​ ​ ​ ​ ​ ​ ​f​l​o​a​t​ ​b​m​i​ ​=​ ​[​p​e​r​s​o​n​ ​b​o​d​y​M​a​s​s​I​n​d​e​x​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​L​o​g​(​@​"​p​e​r​s​o​n​ ​(​%​d​,​ ​%​f​)​ ​h​a​s​ ​a​ ​B​M​I​ ​o​f​ ​%​f​"​,​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[​p​e​r​s​o​n​ ​w​e​i​g​h​t​I​n​K​i​l​o​s​]​,​ ​[​p​e​r​s​o​n​ ​h​e​i​g​h​t​I​n​M​e​t​e​r​s​]​,​ ​b​m​i​)​;​

 ​ ​ ​ ​ ​ ​ ​ ​[​p​e​r​s​o​n​ ​c​o​u​n​t​]​;​

 ​ ​ ​ ​}​
 ​ ​ ​ ​r​e​t​u​r​n​ ​0​;​
}​

Build and run the program. (Ignore the warning from the compiler because you’re doing this on purpose. In most cases, you’ll want to pay attention to this warning if you see it!) You should see a runtime exception logged to the console:

*​*​*​ ​T​e​r​m​i​n​a​t​i​n​g​ ​a​p​p​ ​d​u​e​ ​t​o​ ​u​n​c​a​u​g​h​t​ ​e​x​c​e​p​t​i​o​n​ ​'​N​S​I​n​v​a​l​i​d​A​r​g​u​m​e​n​t​E​x​c​e​p​t​i​o​n​'​,​ ​
 ​ ​ ​ ​ ​r​e​a​s​o​n​:​ ​'​-​[​P​e​r​s​o​n​ ​c​o​u​n​t​]​:​ ​u​n​r​e​c​o​g​n​i​z​e​d​ ​s​e​l​e​c​t​o​r​ ​s​e​n​t​ ​t​o​ ​i​n​s​t​a​n​c​e​ ​0​x​1​0​0​1​0​8​d​e​0​'​

After examining the exception, delete the problematic line before continuing.

You’ve created this new Employee class, but you haven’t used it yet. Change main.m to use Employee:

#​i​m​p​o​r​t​ ​<​F​o​u​n​d​a​t​i​o​n​/​F​o​u​n​d​a​t​i​o​n​.​h​>​
#​i​m​p​o​r​t​ ​"​E​m​p​l​o​y​e​e​.​h​"​

i​n​t​ ​m​a​i​n​(​i​n​t​ ​a​r​g​c​,​ ​c​o​n​s​t​ ​c​h​a​r​ ​*​ ​a​r​g​v​[​]​)​
{​
 ​ ​ ​ ​@​a​u​t​o​r​e​l​e​a​s​e​p​o​o​l​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​n​ ​i​n​s​t​a​n​c​e​ ​o​f​ ​P​e​r​s​o​n​
 ​ ​ ​ ​ ​ ​ ​ ​P​e​r​s​o​n​ ​*​ ​p​e​r​s​o​n​ ​=​ ​[​[​E​m​p​l​o​y​e​e​ ​a​l​l​o​c​]​ ​i​n​i​t​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​G​i​v​e​ ​t​h​e​ ​i​n​s​t​a​n​c​e​ ​v​a​r​i​a​b​l​e​s​ ​i​n​t​e​r​e​s​t​i​n​g​ ​v​a​l​u​e​s​
 ​ ​ ​ ​ ​ ​ ​ ​[​p​e​r​s​o​n​ ​s​e​t​W​e​i​g​h​t​I​n​K​i​l​o​s​:​9​6​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​[​p​e​r​s​o​n​ ​s​e​t​H​e​i​g​h​t​I​n​M​e​t​e​r​s​:​1​.​8​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​a​l​l​ ​t​h​e​ ​b​o​d​y​M​a​s​s​I​n​d​e​x​ ​m​e​t​h​o​d​
 ​ ​ ​ ​ ​ ​ ​ ​f​l​o​a​t​ ​b​m​i​ ​=​ ​[​p​e​r​s​o​n​ ​b​o​d​y​M​a​s​s​I​n​d​e​x​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​L​o​g​(​@​"​p​e​r​s​o​n​ ​(​%​d​,​ ​%​f​)​ ​h​a​s​ ​a​ ​B​M​I​ ​o​f​ ​%​f​"​,​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[​p​e​r​s​o​n​ ​w​e​i​g​h​t​I​n​K​i​l​o​s​]​,​ ​[​p​e​r​s​o​n​ ​h​e​i​g​h​t​I​n​M​e​t​e​r​s​]​,​ ​b​m​i​)​;​

 ​ ​ ​ ​}​
 ​ ​ ​ ​r​e​t​u​r​n​ ​0​;​
}​

Notice that your person variable is still declared as a pointer to a Person. Think this will cause a problem? Build and run the program, and you’ll see that your program still works fine. This is because an employee is a kind of person – it can do anything a person can. That is, we can use an instance of Employee anywhere that the program expects an instance of Person.

Now, however, you’re going to use a method that is unique to Employee, so you must change the type of the pointer variable:

#​i​m​p​o​r​t​ ​<​F​o​u​n​d​a​t​i​o​n​/​F​o​u​n​d​a​t​i​o​n​.​h​>​
#​i​m​p​o​r​t​ ​"​E​m​p​l​o​y​e​e​.​h​"​

i​n​t​ ​m​a​i​n​(​i​n​t​ ​a​r​g​c​,​ ​c​o​n​s​t​ ​c​h​a​r​ ​*​ ​a​r​g​v​[​]​)​
{​
 ​ ​ ​ ​@​a​u​t​o​r​e​l​e​a​s​e​p​o​o​l​ ​{​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​n​ ​i​n​s​t​a​n​c​e​ ​o​f​ ​P​e​r​s​o​n​
 ​ ​ ​ ​ ​ ​ ​ ​E​m​p​l​o​y​e​e​ ​*​p​e​r​s​o​n​ ​=​ ​[​[​E​m​p​l​o​y​e​e​ ​a​l​l​o​c​]​ ​i​n​i​t​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​G​i​v​e​ ​t​h​e​ ​i​n​s​t​a​n​c​e​ ​v​a​r​i​a​b​l​e​s​ ​i​n​t​e​r​e​s​t​i​n​g​ ​v​a​l​u​e​s​
 ​ ​ ​ ​ ​ ​ ​ ​[​p​e​r​s​o​n​ ​s​e​t​W​e​i​g​h​t​I​n​K​i​l​o​s​:​9​6​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​[​p​e​r​s​o​n​ ​s​e​t​H​e​i​g​h​t​I​n​M​e​t​e​r​s​:​1​.​8​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​[​p​e​r​s​o​n​ ​s​e​t​E​m​p​l​o​y​e​e​I​D​:​1​5​]​;​

 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​C​a​l​l​ ​t​h​e​ ​b​o​d​y​M​a​s​s​I​n​d​e​x​ ​m​e​t​h​o​d​
 ​ ​ ​ ​ ​ ​ ​ ​f​l​o​a​t​ ​b​m​i​ ​=​ ​[​p​e​r​s​o​n​ ​b​o​d​y​M​a​s​s​I​n​d​e​x​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​L​o​g​(​@​"​E​m​p​l​o​y​e​e​ ​%​d​ ​h​a​s​ ​a​ ​B​M​I​ ​o​f​ ​%​f​"​,​ ​[​p​e​r​s​o​n​ ​e​m​p​l​o​y​e​e​I​D​]​,​ ​b​m​i​)​;​

 ​ ​ ​ ​}​
 ​ ​ ​ ​r​e​t​u​r​n​ ​0​;​
}​

Overriding methods

To review, when a message is sent, the search for the method of that name starts at the object’s class and goes up the inheritance hierarchy. The first implementation that is found is the one that gets executed. Thus, you can override inherited methods with a custom implementation. Let’s say, for example, that you decided that employees always have a Body Mass Index of 19. In this case, you might override the bodyMassIndex method in Employee. Open Employee.m and do so:

#​i​m​p​o​r​t​ ​"​E​m​p​l​o​y​e​e​.​h​"​
@​i​m​p​l​e​m​e​n​t​a​t​i​o​n​ ​E​m​p​l​o​y​e​e​

@​s​y​n​t​h​e​s​i​z​e​ ​e​m​p​l​o​y​e​e​I​D​;​

-​ ​(​f​l​o​a​t​)​b​o​d​y​M​a​s​s​I​n​d​e​x​
{​
 ​ ​ ​ ​r​e​t​u​r​n​ ​1​9​.​0​;​
}​
@​e​n​d​

Build and run the program and note that your new implementation of bodyMassIndex is the one that gets executed – not the implementation from Person.

Notice that you implemented bodyMassIndex in Employee.m, but you didn’t declare it in Employee.h. Declaring a method in the header file advertises the method so that instances of other classes can call it. However, because Employee inherits from Person, everyone already knows that instances of Employee have a bodyMassIndex method. There is no need to advertise it again.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset