Object-Oriented Programming:Defining an Objective-C Class to Work with Fractions

The Objective-C language was invented by Brad Cox in the early 1980s. The language was based on a language called SmallTalk-80 and was licensed by NeXT Software in When Apple acquired NeXT in 1988, it used NEXTSTEP as the basis for its Mac OS X operating system. Most of the applications found today on Mac OS X are written in Objective-C.

Program 19.2 shows how you can define and use a Fraction class in Objective-C.

Program 19.2   Working with Fractions in Objective-C

// Program to work with fractions – Objective-C version

#import <stdio.h>

#import <objc/Object.h>

//——- @interface section ——-

@interface Fraction: Object

{

int numerator;

int denominator;

}

-(void) setNumerator: (int) n;

-(void) setDenominator: (int) d;

-(void) print;

@end

//——- @implementation section ——-

@implementation Fraction;

// getters

-(int) numerator

{

return numerator;

}

-(int) denominator

{

return denominator;

}

// setters

-(void) setNumerator: (int) num

{

numerator = num;

}

-(void) setDenominator: (int) denom

{

denominator = denom;

}

// other

-(void) print

{

printf (“The value of the fraction is %i/%i\n”, numerator, denominator);

}

@end

//——- program section ——- int main (void)

{

Fraction  *myFract;

myFract = [Fraction new]; [myFract setNumerator: 1];

[myFract setDenominator: 3];

printf (“The numerator is %i, and the denominator is %i\n”,

[myFract numerator], [myFract denominator]);

[myFract print];  // use the method to display the fraction

[myFract free];

return 0;

}

Program 19.2   Output

The numerator is 1, and the denominator is 3

The value of the fraction is 1/3

As you can see from the comments in Program 19.2, the program is logically divided into three sections: the @interface section, the @implementation section, and the pro- gram section. These sections are typically placed in separate files. The @interface section is usually put into a header file that gets included in any program that wants to work with that particular class. It tells the compiler what variables and methods are contained in the class.

The @implementation section contains the actual code that implements these meth- ods. Finally, the program section contains the program code to carry out the intended purpose of the program.

The name of the new class is Fraction, and its parent class is Object. Classes inherit methods and variables from their parents.

As you can see in the @interface section, the declarations

int numerator;

int denominator;

say that a Fraction object has two integer members called numerator and denominator.

The members declared in this section are known as the instance variables. Each time you create a new object, a new and unique set of instance variables is created. Therefore, if you have two fractions, one called fracA and another called fracB, each has its own set of instance variables. That is, fracA and fracB each has its own separate numerator and denominator.

You have to define methods to work with your fractions.You need to be able to set the value of a fraction to a particular value. Because you don’t have direct access to the internal representation of a fraction (in other words, direct access to its instance vari- ables), you must write methods to set the numerator and denominator (these are known as setters).You also need methods to retrieve the values of your instance variables (such methods are known as getters).1

The fact that the instance variables for an object are kept hidden from the user of the object is another key concept of OOP  known as data encapsulation. This assures someone extending or modifying a class that all the code that accesses the data (that is, the instance variables) for that class is contained in the methods. Data encapsulation provides a nice layer of insulation between the programmer and the class developer.

Here’s what one such setter method declaration looks like:

-(int) numerator;

The leading minus sign (-) says that the method is an instance method. The only other option is a plus sign (+), which indicates a class method. A class method is one that per- forms some operation on the class itself, such as creating a new instance of the class. This is similar to manufacturing a new car, in that the car is the class and you want to create a new one—which would be a class method.

An instance method performs some operation on a particular instance of a class, such as setting its value, retrieving its value, displaying its value, and so on. Referring to the car example, after you have manufactured the car, you might need to fill it with gas. The operation of filling it with gas is performed on a particular car, so it is analogous to an instance method.

When you declare a new method (and similar to declaring a function), you tell the Objective-C compiler whether the method returns a value, and if it does, what type of value it returns. This is done by enclosing the return type in parentheses after the leading minus or plus sign. So, the declaration

-(int) numerator;

specifies that the instance method called numerator returns an integer value. Similarly, the line

-(void) setNumerator: (int) num;

defines a method that doesn’t return a value that can be used to set the numerator of your fraction.

When a method takes an argument, you append a colon to the method name when referring to the method. Therefore, the correct way to identify these two methods is setNumerator: and setDenominator:—each of which takes a single argument. Also, the identification of the numerator and denominator methods without a trailing colon indi- cates that these methods do not take any arguments.

The setNumerator: method takes the integer argument you called num and simply stores it in the instance variable numerator. Similarly, setDenominator: stores the value of its argument denom in the instance variable denominator. Note that methods have direct access to their instance variables.

The last method defined in your Objective-C program is called print. It’s use is to display the value of a fraction. As you see, it takes no arguments and returns no results. It simply uses printf to display the numerator and denominator of the fraction, separated by a slash.

Inside main, you define a variable called myFract with the following line:

Fraction *myFract;

This line says that myFract is an object of type Fraction; that is, myFract is used to store values from your new Fraction class. The asterisk (*) in front of myFraction says that myFract is actually a pointer to a Fraction. In fact, it points to the structure that contains the data for a particular instance from the Fraction class.

Now that you have an object to store a Fraction, you need to create one, just like you ask the factory to build you a new car. This is done with the following line:

myFract = [Fraction new];

You want to allocate memory storage space for a new fraction. The expression

[Fraction new]

sends a message to your newly created Fraction class.You are asking the Fraction class to apply the new method, but you never defined a new method, so where did it come from? The method was inherited from a parent class.

You are now ready to set the value of your Fraction. The program lines

[myFract setNumerator: 1];

[myFract setDenominator: 3];

do just that. The first message statement sends the setNumerator: message to myFract. The argument that is supplied is the value 1. Control is then sent to the setNumerator: method you defined for your Fraction class. The Objective-C runtime system knows that it is the method from this class to use because it knows that myFract is an object from the Fraction class.

Inside the setNumerator: method, the single program line in that method takes the value passed in as the argument and stores it in the instance variable numerator. So, you have effectively set the numerator of myFract to 1.

The message that invokes the setDenominator: method on myFract follows next, and works in a similar way.

With the fraction being set, Program 19.2 then calls the two getter methods numerator and denominator to retrieve the values of the corresponding instance variables from myFract. The results are then passed to printf to be displayed.

The program next invokes the  print method. This method displays the value of the fraction that is the receiver of the message. Even though you saw in the program how the numerator and denominator could be retrieved using the getter methods, a separate print method was also added to the definition of the Fraction class for illustrative pur- poses.

The last message in the program

[myFract free];

frees the memory that was used by your Fraction object.

Source: Kochan Stephen G. (2004), Programming in C: A Complete Introduction to the C Programming Language, Sams; Subsequent edition.

Leave a Reply

Your email address will not be published. Required fields are marked *