Chapter 4. Introduction to Classes, Objects, Methods and strings

 

Nothing can have value without being an object of utility.

 
 --Karl Marx
 

Your public servants serve you right.

 
 --Adlai E. Stevenson
 

You’ll see something new. Two things. And I call them Thing One and Thing Two.

 
 --Dr. Theodor Seuss Geisel
<feature> <supertitle>Objectives</supertitle>

In this chapter you’ll learn:

<objective>

How to declare a class and use it to create an object.

</objective>
<objective>

How to implement a class’s behaviors as methods.

</objective>
<objective>

How to implement a class’s attributes as instance variables and properties.

</objective>
<objective>

How to call an object’s methods to make them perform their tasks.

</objective>
<objective>

What instance variables of a class and local variables of a method are.

</objective>
<objective>

How to use a constructor to initialize an object’s data.

</objective>
</feature>
<feature> <supertitle>Outline</supertitle> </feature>

Introduction

In this chapter, we begin by explaining the concept of classes using a real-world example. Then we present five complete working applications to demonstrate how to create and use your own classes. The first four begin our case study on developing a grade book class that instructors can use to maintain student test scores. The last example introduces the type decimal and uses it to declare monetary amounts in the context of a bank account class that maintains a customer’s balance.

Classes, Objects, Methods, Properties and Instance Variables

Let’s begin with a simple analogy to help you understand classes and their contents. Suppose you want to drive a car and make it go faster by pressing down on its accelerator pedal. What must happen before you can do this? Well, before you can drive a car, someone has to design it. A car typically begins as engineering drawings, similar to the blueprints used to design a house. These engineering drawings include the design for an accelerator pedal to make the car go faster. The pedal “hides” the complex mechanisms that actually make the car go faster, just as the brake pedal “hides” the mechanisms that slow the car and the steering wheel “hides” the mechanisms that turn the car. This enables people with little or no knowledge of how engines work to drive a car easily.

Unfortunately, you can’t drive the engineering drawings of a car. Before you can drive a car, it must be built from the engineering drawings that describe it. A completed car will have an actual accelerator pedal to make the car go faster, but even that’s not enough—the car will not accelerate on its own, so the driver must press the accelerator pedal.

Methods

Now let’s use our car example to introduce the key programming concepts of this section. Performing a task in an application requires a method. The method describes the mechanisms that actually perform its tasks. The method hides from its user the complex tasks that it performs, just as the accelerator pedal of a car hides from the driver the complex mechanisms of making the car go faster.

Classes

In C#, we begin by creating an application unit called a class to house (among other things) a method, just as a car’s engineering drawings house (among other things) the design of an accelerator pedal. In a class, you provide one or more methods that are designed to perform the class’s tasks. For example, a class that represents a bank account might contain one method to deposit money in an account, another to withdraw money from an account and a third to inquire what the current account balance is.

Objects

Just as you cannot drive an engineering drawing of a car, you cannot “drive” a class. Just as someone has to build a car from its engineering drawings before you can actually drive it, you must build an object of a class before you can make an application perform the tasks the class describes. That’s one reason C# is known as an object-oriented programming language.

Method Calls

When you drive a car, pressing its gas pedal sends a message to the car to perform a task—make the car go faster. Similarly, you send messages to an object—each message is known as a method call and tells a method of the object to perform its task.

Attributes

Thus far, we’ve used the car analogy to introduce classes, objects and methods. In addition to a car’s capabilities, it also has many attributes, such as its color, the number of doors, the amount of gas in its tank, its current speed and its total miles driven (i.e., its odometer reading). Like the car’s capabilities, these attributes are represented as part of a car’s design in its engineering diagrams. As you drive a car, these attributes are always associated with the car. Every car maintains its own attributes. For example, each car knows how much gas is in its own gas tank, but not how much is in the tanks of other cars. Similarly, an object has attributes that are carried with the object as it’s used in an application. These attributes are specified as part of the object’s class. For example, a bank-account object has a balance attribute that represents the amount of money in the account. Each bank-account object knows the balance in the account it represents, but not the balances of the other accounts in the bank. Attributes are specified by the class’s instance variables.

Properties, Get Accessors and Set Accessors

Notice that these attributes are not necessarily accessible directly. The car manufacturer does not want drivers to take apart the car’s engine to observe the amount of gas in its tank. Instead, the driver can check the fuel gauge on the dashboard. The bank does not want its customers to walk into the vault to count the amount of money in an account. Instead, the customers talk to a bank teller or check personalized online bank accounts. Similarly, you do not need to have access to an object’s instance variables in order to use them. You can use the properties of an object. Properties contain get accessors for reading the values of variables, and set accessors for storing values into them.

Declaring a Class with a Method and Instantiating an Object of a Class

We begin with an example that consists of classes GradeBook (Fig. 4.1) and GradeBookTest (Fig. 4.2). Class GradeBook (declared in file GradeBook.cs) will be used to display a message on the screen (Fig. 4.2) welcoming the instructor to the grade-book application. Class GradeBookTest (declared in the file GradeBookTest.cs) is a testing class in which the Main method will create and use an object of class GradeBook. By convention, we declare classes GradeBook and GradeBookTest in separate files, such that each file’s name matches the name of the class it contains.

Example 4.1. Class declaration with one method.

 1   // Fig. 4.1: GradeBook.cs  
 2   // Class declaration with one method.  
 3   using System; 
 4
 5   public class GradeBook 
 6   {
 7      // display a welcome message to the GradeBook user
 8      public void DisplayMessage()
 9      {
10         Console.WriteLine( "Welcome to the Grade Book!" );
11      } // end method DisplayMessage
12   } // end class GradeBook

Example 4.2. Create a GradeBook object and call its DisplayMessage method.

 1   // Fig. 4.2: GradeBookTest.cs
 2   // Create a GradeBook object and call its DisplayMessage method.
 3   public class GradeBookTest
 4   {
 5      // Main method begins program execution
 6      public static void Main( string[] args )
 7      {
 8         // create a GradeBook object and assign it to myGradeBook
 9         GradeBook myGradeBook = new GradeBook();
10
11         // call myGradeBook's DisplayMessage method
12         myGradeBook.DisplayMessage();
13      } // end Main
14   } // end class GradeBookTest

Welcome to the Grade Book!

To start, select File > New Project... to open the New Project dialog, then create a GradeBook Console Application. Rename the Program.cs file to GradeBook.cs. Delete all the code provided automatically by the IDE and replace it with the code in Fig. 4.1.

Class GradeBook

The GradeBook class declaration (Fig. 4.1) contains a DisplayMessage method (lines 8–11) that displays a message on the screen. Line 10 of the class displays the message. Recall that a class is like a blueprint—we need to make an object of this class and call its method to get line 10 to execute and display its message—we do this in Fig. 4.2.

The class declaration begins in line 5. The keyword public is an access modifier. Access modifiers determine the accessibility of an object’s properties and methods to other methods in an application. For now, we simply declare every class public. Every class declaration contains keyword class followed by the class’s name. Every class’s body is enclosed in a pair of left and right braces ({ and }), as in lines 6 and 12 of class GradeBook.

In Chapter 3, each class we declared had one method named Main. Class GradeBook also has one method—DisplayMessage (lines 8–11). Recall that Main is a special method that’s always called automatically when you execute an application. Most methods do not get called automatically. As you’ll soon see, you must call method DisplayMessage to tell it to perform its task.

The method declaration begins with keyword public to indicate that the method is “available to the public”—that is, it can be called from outside the class declaration’s body by methods of other classes. Keyword void—known as the method’s return type—indicates that this method will not return (i.e., give back) any information to its calling method when it completes its task. When a method that specifies a return type other than void is called and completes its task, the method returns a result to its calling method. For example, when you go to an automated teller machine (ATM) and request your account balance, you expect the ATM to give you back a value that represents your balance. If you have a method Square that returns the square of its argument, you’d expect the statement

int result = Square( 2 );

to return 4 from method Square and assign 4 to variable result. If you have a method Maximum that returns the largest of three integer arguments, you’d expect the statement

int biggest = Maximum( 27, 114, 51 );

to return the value 114 from method Maximum and assign the value to variable biggest. You’ve already used methods that return information—for example, in Chapter 3 you used Console method ReadLine to input a string typed by the user at the keyboard. When ReadLine inputs a value, it returns that value for use in the application.

The name of the method, DisplayMessage, follows the return type (line 8). Generally, methods are named as verbs or verb phrases while classes are named as nouns. By convention, method names begin with an uppercase first letter, and all subsequent words in the name begin with an uppercase letter. This naming convention is referred to as Pascal case. The parentheses after the method name indicate that this is a method. An empty set of parentheses, as shown in line 8, indicates that this method does not require additional information to perform its task. Line 8 is commonly referred to as the method header. Every method’s body is delimited by left and right braces, as in lines 9 and 11.

The body of a method contains statements that perform the method’s task. In this case, the method contains one statement (line 10) that displays the message "Welcome to the Grade Book!", followed by a newline in the console window. After this statement executes, the method has completed its task.

Next, we’d like to use class GradeBook in an application. As you learned in Chapter 3, method Main begins the execution of every application. Class GradeBook cannot begin an application because it does not contain Main. This was not a problem in Chapter 3, because every class you declared had a Main method. To fix this problem for the GradeBook, we must either declare a separate class that contains a Main method or place a Main method in class GradeBook. To help you prepare for the larger applications you’ll encounter later in this book and in industry, we use a separate class (GradeBookTest in this example) containing method Main to test each new class we create in this chapter.

Adding a Class to a Visual C# Project

For each example in this chapter, you’ll add a class to your console application. To do this, right click the project name in the Solution Explorer and select Add > New Item... from the pop-up menu. In the Add New Item dialog that appears, select Code File, enter the name of your new file (GradeBookTest.cs) then click the Add button. A new blank file will be added to your project. Add the code from Fig. 4.2 to this file.

Class GradeBookTest

The GradeBookTest class declaration (Fig. 4.2) contains the Main method that controls our application’s execution. Any class that contains a Main method (as shown in line 6) can be used to execute an application. This class declaration begins in line 3 and ends in line 14. The class contains only a Main method, which is typical of many classes that simply begin an application’s execution.

Lines 6–13 declare method Main. A key part of enabling the method Main to begin the application’s execution is the static keyword (line 6), which indicates that Main is a static method. A static method is special because it can be called without first creating an object of the class (in this case, GradeBookTest) in which the method is declared. We explain static methods in Chapter 7, Methods: A Deeper Look.

In this application, we’d like to call class GradeBook’s DisplayMessage method to display the welcome message in the console window. Typically, you cannot call a method that belongs to another class until you create an object of that class, as shown in line 9. We begin by declaring variable myGradeBook. The variable’s type is GradeBook—the class we declared in Fig. 4.1. Each new class you create becomes a new type in C# that can be used to declare variables and create objects. New class types will be accessible to all classes in the same project. You can declare new class types as needed; this is one reason why C# is known as an extensible language.

Variable myGradeBook (line 9) is initialized with the result of the object-creation expression new GradeBook(). The new operator creates a new object of the class specified to the right of the keyword (i.e., GradeBook). The parentheses to the right of the GradeBook are required. As you’ll learn in Section 4.10, those parentheses in combination with a class name represent a call to a constructor, which is similar to a method, but is used only at the time an object is created to initialize the object’s data. In that section you’ll see that data can be placed in parentheses to specify initial values for the object’s data. For now, we simply leave the parentheses empty.

We can now use myGradeBook to call its method DisplayMessage. Line 12 calls the method DisplayMessage (lines 8–11 of Fig. 4.1) using variable myGradeBook followed by a member access (.) operator, the method name DisplayMessage and an empty set of parentheses. This call causes the DisplayMessage method to perform its task. This method call differs from the method calls in Chapter 3 that displayed information in a console window—each of those method calls provided arguments that specified the data to display. At the beginning of line 12, “myGradeBook.” indicates that Main should use the GradeBook object that was created in line 9. The empty parentheses in line 8 of Fig. 4.1 indicate that method DisplayMessage does not require additional information to perform its task. For this reason, the method call (line 12 of Fig. 4.2) specifies an empty set of parentheses after the method name to indicate that no arguments are being passed to method DisplayMessage. When method DisplayMessage completes its task, method Main continues executing at line 13. This is the end of method Main, so the application terminates.

UML Class Diagram for Class GradeBook

Figure 4.3 presents a UML class diagram for class GradeBook of Fig. 4.1. Recall from Section 1.15 that the UML is a graphical language used by programmers to represent their object-oriented systems in a standardized manner. In the UML, each class is modeled in a class diagram as a rectangle with three compartments. The top compartment contains the name of the class centered horizontally in boldface type. The middle compartment contains the class’s attributes, which correspond to instance variables and properties in C#. In Fig. 4.3, the middle compartment is empty because the version of class GradeBook in Fig. 4.1 does not have any attributes. The bottom compartment contains the class’s operations, which correspond to methods in C#. The UML models operations by listing the operation name followed by a set of parentheses. Class GradeBook has one method, DisplayMessage, so the bottom compartment of Fig. 4.3 lists one operation with this name. Method DisplayMessage does not require additional information to perform its tasks, so there are empty parentheses following DisplayMessage in the class diagram, just as they appeared in the method’s declaration in line 8 of Fig. 4.1. The plus sign (+) in front of the operation name indicates that DisplayMessage is a public operation in the UML (i.e., a public method in C#). The plus sign is sometimes called the public visibility symbol. We’ll often use UML class diagrams to summarize a class’s attributes and operations.

UML class diagram indicating that class GradeBook has a public DisplayMessage operation.

Figure 4.3. UML class diagram indicating that class GradeBook has a public DisplayMessage operation.

Declaring a Method with a Parameter

In our car analogy from Section 4.2, we discussed the fact that pressing a car’s gas pedal sends a message to the car to perform a task—make the car go faster. But how fast should the car accelerate? As you know, the farther down you press the pedal, the faster the car accelerates. So the message to the car actually includes both the task to be performed and additional information that helps the car perform the task. This additional information is known as a parameter—the value of the parameter helps the car determine how fast to accelerate. Similarly, a method can require one or more parameters that represent additional information it needs to perform its task. A method call supplies values—called arguments—for each of the method’s parameters. For example, the Console.WriteLine method requires an argument that specifies the data to be displayed in a console window. Similarly, to make a deposit into a bank account, a Deposit method specifies a parameter that represents the deposit amount. When the Deposit method is called, an argument value representing the deposit amount is assigned to the method’s parameter. The method then makes a deposit of that amount, by increasing the account’s balance.

Our next example declares class GradeBook (Fig. 4.4) with a DisplayMessage method that displays the course name as part of the welcome message. (See the sample execution in Fig. 4.5.) The new DisplayMessage method requires a parameter that represents the course name to output.

Example 4.4. Class declaration with a method that has a parameter.

 1   // Fig. 4.4: GradeBook.cs
 2   // Class declaration with a method that has a parameter.
 3   using System;
 4
 5   public class GradeBook
 6   {
 7      // display a welcome message to the GradeBook user
 8      public void DisplayMessage( string courseName )
 9      {
10         Console.WriteLine( "Welcome to the grade book for
{0}!",
11            courseName );
12      } // end method DisplayMessage
13   } // end class GradeBook

Example 4.5. Create GradeBook object and pass a string to its DisplayMessage method.

 1   // Fig. 4.5: GradeBookTest.cs
 2   // Create a GradeBook object and pass a string to
 3   // its DisplayMessage method.
 4   using System;
 5
 6   public class GradeBookTest
 7   {
 8      // Main method begins program execution
 9      public static void Main( string[] args )
10      {
11         // create a GradeBook object and assign it to myGradeBook
12         GradeBook myGradeBook = new GradeBook();
13
14         // prompt for and input course name
15         Console.WriteLine( "Please enter the course name:" );
16         string nameOfCourse = Console.ReadLine();  // read a line of text
17         Console.WriteLine();  // output a blank line
18
19         // call myGradeBook's DisplayMessage method
20         // and pass nameOfCourse as an argument
21         myGradeBook.DisplayMessage( nameOfCourse );
22      } // end Main
23   } // end class GradeBookTest

Please enter the course name:
CS101 Introduction to C# Programming

Welcome to the grade book for
CS101 Introduction to C# Programming!

Before discussing the new features of class GradeBook, let’s see how the new class is used from the Main method of class GradeBookTest (Fig. 4.5). Line 12 creates an object of class GradeBook and assigns it to variable myGradeBook. Line 15 prompts the user to enter a course name. Line 16 reads the name from the user and assigns it to the variable nameOfCourse, using Console method ReadLine to perform the input. The user types the course name and presses Enter to submit the course name to the application. Pressing Enter inserts a newline character at the end of the characters typed by the user. Method ReadLine reads characters typed by the user until the newline character is encountered, then returns a string containing the characters up to, but not including, the newline. The newline character is discarded.

Line 21 calls myGradeBook’s DisplayMessage method. The variable nameOfCourse in parentheses is the argument that’s passed to method DisplayMessage so that the method can perform its task. Variable nameOfCourse’s value in Main becomes the value of method DisplayMessage’s parameter courseName in line 8 of Fig. 4.4. When you execute this application, notice that method DisplayMessage outputs as part of the welcome message the name you type (Fig. 4.5).

Software Engineering Observation 4.1

Software Engineering Observation 4.1

Normally, objects are created with new. One exception is a string literal that’s contained in quotes, such as "hello". String literals are references to string objects that are implicitly created by C#.

More on Arguments and Parameters

When you declare a method, you must specify in the method’s declaration whether the method requires data to perform its task. To do so, you place additional information in the method’s parameter list, which is located in the parentheses that follow the method name. The parameter list may contain any number of parameters, including none at all. Each parameter is declared as a variable with a type and identifier in the parameter list. Empty parentheses following the method name (as in Fig. 4.1, line 8) indicate that a method does not require any parameters. In Fig. 4.4, DisplayMessage’s parameter list (line 8) declares that the method requires one parameter. Each parameter must specify a type and an identifier. In this case, the type string and the identifier courseName indicate that method DisplayMessage requires a string to perform its task. At the time the method is called, the argument value in the call is assigned to the corresponding parameter (in this case, courseName) in the method header. Then, the method body uses the parameter courseName to access the value. Lines 10–11 of Fig. 4.4 display parameter courseName’s value, using the {0} format item in WriteLine’s first argument. The parameter variable’s name (Fig. 4.4, line 8) can be the same or different from the argument variable’s name (Fig. 4.5, line 21).

A method can specify multiple parameters by separating each parameter from the next with a comma. The number of arguments in a method call must match the number of required parameters in the parameter list of the called method’s declaration. Also, the types of the arguments in the method call must be consistent with the types of the corresponding parameters in the method’s declaration. (As you’ll learn in subsequent chapters, an argument’s type and its corresponding parameter’s type are not always required to be identical.) In our example, the method call passes one argument of type string (nameOfCourse is declared as a string in line 16 of Fig. 4.5), and the method declaration specifies one parameter of type string (line 8 in Fig. 4.4). So the type of the argument in the method call exactly matches the type of the parameter in the method header.

Common Programming Error 4.1

Common Programming Error 4.1

A compilation error occurs if the number of arguments in a method call does not match the number of required parameters in the method declaration.

Common Programming Error 4.2

Common Programming Error 4.2

A compilation error occurs if the types of the arguments in a method call are not consistent with the types of the corresponding parameters in the method declaration.

Updated UML Class Diagram for Class GradeBook

The UML class diagram of Fig. 4.6 models class GradeBook of Fig. 4.4. Like Fig. 4.4, this GradeBook class contains public operation DisplayMessage. However, this version of DisplayMessage has a parameter. The UML models a parameter a bit differently from C# by listing the parameter name, followed by a colon and the parameter type in the parentheses following the operation name. The UML has several data types that are similar to the C# types. For example, UML types String and Integer correspond to C# types string and int, respectively. Unfortunately, the UML does not provide types that correspond to every C# type. For this reason, and to avoid confusion between UML types and C# types, we use only C# types in our UML diagrams. Class Gradebook’s method DisplayMessage (Fig. 4.4) has a string parameter named courseName, so Fig. 4.6 lists the parameter courseName : string between the parentheses following DisplayMessage.

UML class diagram indicating that class GradeBook has a public DisplayMessage operation with a courseName parameter of type string.

Figure 4.6. UML class diagram indicating that class GradeBook has a public DisplayMessage operation with a courseName parameter of type string.

Notes on using Directives

Notice the using directive in Fig. 4.5 (line 4). This indicates to the compiler that the application uses classes in the System namespace, like the Console class. Why do we need a using directive to use class Console, but not class GradeBook? There’s a special relationship between classes that are compiled in the same project, like classes GradeBook and GradeBookTest. By default, such classes are considered to be in the same namespace. A using directive is not required when one class in a namespace uses another in the same namespace—such as when class GradeBookTest uses class GradeBook. For simplicity, our examples in this chapter do not declare a namespace. Any classes that are not explicitly placed in a namespace are implicitly placed in the so-called global namespace.

Actually, the using directive in line 4 is not required if we always refer to class Console as System.Console, which includes the full namespace and class name. This is known as the class’s fully qualified class name. For example, line 15 could be written as

System.Console.WriteLine( "Please enter the course name:" );

Most C# programmers consider using fully qualified names to be cumbersome, and instead prefer to use using directives.

Instance Variables and Properties

In Chapter 3, we declared all of an application’s variables in the application’s Main method. Variables declared in the body of a method are known as local variables and can be used only in that method. When a method terminates, the values of its local variables are lost. Recall from Section 4.2 that an object has attributes that are carried with it as it’s used in an application. Such attributes exist before a method is called on an object and after the method completes execution.

Attributes are represented as variables in a class declaration. Such variables are called fields and are declared inside a class declaration but outside the bodies of the class’s method declarations. When each object of a class maintains its own copy of an attribute, the field that represents the attribute is also known as an instance variable—each object (instance) of the class has a separate instance of the variable. In Chapter 10, we discuss another type of field called a static variable, where all objects of the same class share one variable.

A class normally contains one or more properties that manipulate the attributes that belong to a particular object of the class. The example in this section demonstrates a GradeBook class that contains a courseName instance variable to represent a particular GradeBook object’s course name, and a CourseName property to manipulate courseName.

GradeBook Class with an Instance Variable and a Property

In our next application (Figs. 4.74.8), class GradeBook (Fig. 4.7) maintains the course name as an instance variable so that it can be used or modified at any time during an application’s execution. The class also contains one method—DisplayMessage (lines 24–30)—and one property—CourseName (line 11–21). Recall from Chapter 2 that properties are used to manipulate an object’s attributes. For example, in that chapter, we used a Label’s Text property to specify the text to display on the Label. In this example, we use a property in code rather than in the Properties window of the IDE. To do this, we first declare a property as a member of the GradeBook class. As you’ll soon see, the GradeBook’s CourseName property can be used to store a course name in a GradeBook (in instance variable courseName) or retrieve the GradeBook’s course name (from instance variable courseName). Method DisplayMessage—which now specifies no parameters—still displays a welcome message that includes the course name. However, the method now uses the CourseName property to obtain the course name from instance variable courseName.

Example 4.7. GradeBook class that contains a private instance variable, courseName, and a public property to get and set its value.

 1   // Fig. 4.7: GradeBook.cs
 2   // GradeBook class that contains a private instance variable, courseName,
 3   // and a public property to get and set its value.
 4   using System;
 5
 6   public class GradeBook
 7   {
 8      private string courseName; // course name for this GradeBook
 9
10      // property to get and set the course name
11      public string CourseName                  
12      {                                         
13         get                                    
14         {                                      
15            return courseName;                  
16         } // end get                           
17         set                                    
18         {                                      
19            courseName = value;                 
20         } // end set                           
21      } // end property CourseName              
22
23      // display a welcome message to the GradeBook user
24      public void DisplayMessage()
25      {
26         // use property CourseName to get the
27         // name of the course that this GradeBook represents
28         Console.WriteLine( "Welcome to the grade book for
{0}!",
29            CourseName ); // display property CourseName
30      } // end method DisplayMessage
31   } // end class GradeBook

Example 4.8. Create and manipulate a GradeBook object.

 1   // Fig. 4.8: GradeBookTest.cs
 2   // Create and manipulate a GradeBook object.
 3   using System;
 4
 5   public class GradeBookTest
 6   {
 7      // Main method begins program execution
 8      public static void Main( string[] args )
 9      {
10         // create a GradeBook object and assign it to myGradeBook
11         GradeBook myGradeBook = new GradeBook();
12
13         // display initial value of CourseName
14         Console.WriteLine( "Initial course name is: '{0}'
",
15            myGradeBook.CourseName );
16
17         // prompt for and read course name
18         Console.WriteLine( "Please enter the course name:" );
19         myGradeBook.CourseName = Console.ReadLine(); // set CourseName
20         Console.WriteLine(); // output a blank line
21
22         // display welcome message after specifying course name
23         myGradeBook.DisplayMessage();
24      } // end Main
25   } // end class GradeBookTest

Initial course name is: ''

Please enter the course name:
CS101 Introduction to C# Programming

Welcome to the grade book for
CS101 Introduction to C# Programming!

A typical instructor teaches more than one course, each with its own course name. Line 8 declares courseName as a variable of type string. Line 8 is a declaration for an instance variable, because the variable is declared in the class’s body (lines 7–31) but outside the bodies of the class’s method (lines 24–30) and property (lines 11–21). Every instance (i.e., object) of class GradeBook contains one copy of each instance variable. For example, if there are two GradeBook objects, each object has its own copy of courseName. All the methods and properties of class GradeBook can directly manipulate its instance variable courseName, but it’s considered good practice for methods of a class to use that class’s properties to manipulate instance variables (as we do in line 29 of method DisplayMessage). The software engineering reasons for this will soon become clear.

Access Modifiers public and private

Most instance-variable declarations are preceded with the keyword private (as in line 8). Like public, keyword private is an access modifier. Variables, properties or methods declared with access modifier private are accessible only to properties and methods of the class in which they’re declared. Thus, variable courseName can be used only in property CourseName and method DisplayMessage of class GradeBook.

Software Engineering Observation 4.2

Software Engineering Observation 4.2

Precede every field and method declaration with an access modifier. Generally, instance variables should be declared private and methods and properties should be declared public. If the access modifier is omitted before a member of a class, the member is implicitly declared private. We’ll see that it’s appropriate to declare certain methods private, if they will be accessed only by other methods of the class.

Software Engineering Observation 4.3

Software Engineering Observation 4.3

Declaring the instance variables of a class as private and the methods of the class as public facilitates debugging, because problems with data manipulations are localized to the class’s methods and properties, since the private instance variables are accessible only to these methods and properties.

Declaring instance variables with access modifier private is known as information hiding. When an application creates (instantiates) an object of class GradeBook, variable courseName is encapsulated (hidden) in the object and can be accessed only by methods and properties of the object’s class.

Setting and Getting the Values of private Instance Variables

How can we allow a program to manipulate a class’s private instance variables but ensure that they remain in a valid state? We need to provide controlled ways for programmers to “get” (i.e., retrieve) the value in an instance variable and “set” (i.e., modify) the value in an instance variable. Although you can define methods like GetCourseName and SetCourseName, C# properties provide a more elegant solution. Next, we show how to declare and use properties.

GradeBook Class with a Property

The GradeBook class’s CourseName property declaration is located in lines 11–21 of Fig. 4.7. The property begins in line 11 with an access modifier (in this case, public), followed by the type that the property represents (string) and the property’s name (CourseName). Properties use the same naming conventions as methods and classes.

Properties contain accessors that handle the details of returning and modifying data. A property declaration can contain a get accessor, a set accessor or both. The get accessor (lines 13–16) enables a client to read the value of private instance variable courseName; the set accessor (lines 17–20) enables a client to modify courseName.

After defining a property, you can use it like a variable in your code. For example, you can assign a value to a property using the = (assignment) operator. This executes the code in the property’s set accessor to set the value of the corresponding instance variable. Similarly, referencing the property to use its value (for example, to display it on the screen) executes the code in the property’s get accessor to obtain the corresponding instance variable’s value. We show how to use properties shortly. By convention, we name each property with the capitalized name of the instance variable that it manipulates (e.g., CourseName is the property that represents instance variable courseName)—C# is case sensitive, so these are distinct identifiers.

get and set Accessors

Let us look more closely at property CourseName’s get and set accessors (Fig. 4.7). The get accessor (lines 13–16) begins with the identifier get and its body is delimited by braces. The accessor’s body contains a return statement, which consists of the keyword return followed by an expression. The expression’s value is returned to the client code that uses the property. In this example, the value of courseName is returned when the property CourseName is referenced. For example, in the following statement

string theCourseName = gradeBook.CourseName;

the expression gradeBook.CourseName (where gradeBook is an object of class GradeBook) executes property CourseName’s get accessor, which returns the value of instance variable courseName. That value is then stored in variable theCourseName. Property CourseName can be used as simply as if it were an instance variable. The property notation allows the client to think of the property as the underlying data. Again, the client cannot directly manipulate instance variable courseName because it’s private.

The set accessor (lines 17–20) begins with the identifier set and its body is delimited by braces. When the property CourseName appears in an assignment statement, as in

gradeBook.CourseName = "CS100 Introduction to Computers";

the text "CS100 Introduction to Computers" is assigned to the set accessor’s contextual keyword named value and the set accessor executes. Note that value is implicitly declared and initialized in the set accessor—it’s a compilation error to declare a local variable value in this body. Line 19 stores the contents of value in instance variable courseName. A set accessor does not return any data when it completes its task.

The statements inside the property in lines 15 and 19 (Fig. 4.7) each access courseName even though it was declared outside the property. We can use instance variable courseName in the methods and properties of class GradeBook, because courseName is an instance variable of the class.

Using Property CourseName in Method DisplayMessage

Method DisplayMessage (lines 24–30 of Fig. 4.7) does not receive any parameters. Lines 28–29 output a welcome message that includes the value of instance variable courseName. We do not reference courseName directly. Instead, we access property CourseName (line 29), which executes the property’s get accessor, returning the value of courseName.

GradeBookTest Class That Demonstrates Class GradeBook

Class GradeBookTest (Fig. 4.8) creates a GradeBook object and demonstrates property CourseName. Line 11 creates a GradeBook object and assigns it to local variable myGradeBook. Lines 14–15 display the initial course name using the object’s CourseName property—this executes the property’s get accessor, which returns the value of courseName.

The first line of the output shows an empty name (marked by single quotes, ''). Unlike local variables, which are not automatically initialized, every field has a default initial value—a value provided by C# when you do not specify the initial value. Thus, fields are not required to be explicitly initialized before they’re used in an application—unless they must be initialized to values other than their default values. The default value for an instance variable of type string (like courseName) is null. When you display a string variable that contains the value null, no text is displayed on the screen.

Line 18 prompts the user to enter a course name. Line 19 assigns the course name entered by the user to object myGradeBook’s CourseName property. When a value is assigned to CourseName, the value specified (which is returned by ReadLine in this case) is assigned to implicit parameter value of CourseName’s set accessor (lines 17–20, Fig. 4.7). Then parameter value is assigned by the set accessor to instance variable courseName (line 19 of Fig. 4.7). Line 20 (Fig. 4.8) displays a blank line, then line 23 calls myGradeBook’s DisplayMessage method to display the welcome message containing the course name.

UML Class Diagram with a Property

Figure 4.9 contains an updated UML class diagram for the version of class GradeBook in Fig. 4.7. We model properties in the UML as attributes—the property (in this case, CourseName) is listed as a public attribute—as indicated by the plus (+) sign—preceded by the word “property” in guillemets (« and »). Using descriptive words in guillemets (called stereotypes in the UML) helps distinguish properties from other attributes and operations. The UML indicates the type of the property by placing a colon and a type after the property name. The get and set accessors of the property are implied, so they’re not listed in the UML diagram. Class GradeBook also contains one public method DisplayMessage, so the class diagram lists this operation in the third compartment. Recall that the plus (+) sign is the public visibility symbol.

UML class diagram indicating that class GradeBook has a public CourseName property of type string and one public method.

Figure 4.9. UML class diagram indicating that class GradeBook has a public CourseName property of type string and one public method.

A class diagram helps you design a class, so it’s not required to show every implementation detail of the class. Since an instance variable that’s manipulated by a property is really an implementation detail of that property, our class diagram does not show the courseName instance variable. A programmer implementing the GradeBook class based on this class diagram would create the instance variable courseName as part of the implementation process (as we did in Fig. 4.7).

In some cases, you may find it necessary to model the private instance variables of a class. Like properties, instance variables are attributes of a class and are modeled in the middle compartment of a class diagram. The UML represents instance variables as attributes by listing the attribute name, followed by a colon and the attribute type. To indicate that an attribute is private, a class diagram would list the private visibility symbol—a minus sign ()—before the attribute’s name. For example, the instance variable courseName in Fig. 4.7 would be modeled as “- courseName : string” to indicate that it’s a private attribute of type string.

Software Engineering with Properties and set and get Accessors

Using properties as described earlier in this chapter would seem to violate the notion of private data. Although providing a property with get and set accessors may appear to be the same as making its corresponding instance variable public, this is not the case. A public instance variable can be read or written by any property or method in the program. If an instance variable is private, the client code can access the instance variable only indirectly through the class’s non-private properties or methods. This allows the class to control the manner in which the data is set or returned. For example, get and set accessors can translate between the format of the data stored in the private instance variable and the format of the data preferred by the client.

Consider a Clock class that represents the time of day as a private int instance variable time, containing the number of seconds since midnight. Suppose the class provides a Time property of type string to manipulate this instance variable. Although get accessors typically return data exactly as it’s stored in an object, they need not expose the data in this “raw” format. When a client refers to a Clock object’s Time property, the property’s get accessor could use instance variable time to determine the number of hours, minutes and seconds since midnight, then return the time as a string of the form "HH:MM:SS". Similarly, suppose a Clock object’s Time property is assigned a string of the form "HH:MM:SS". Using the string capabilities presented in Chapter 16, and the method Convert.ToInt32 presented in Section 3.6, the Time property’s set accessor can convert this string to an int number of seconds since midnight and store the result in the Clock object’s private instance variable time. The Time property’s set accessor can also provide data-validation capabilities that scrutinize attempts to modify the instance variable’s value to ensure that the value it receives represents a valid time (e.g., "12:30:45" is valid but "42:85:70" is not). We demonstrate data validation in Section 4.11. So, although a property’s accessors enable clients to manipulate private data, they carefully control those manipulations, and the object’s private data remains safely encapsulated (i.e., hidden) in the object. This is not possible with public instance variables, which can easily be set by clients to invalid values.

Properties of a class should also be used by the class’s own methods to manipulate the class’s private instance variables, even though the methods can directly access the private instance variables. Accessing an instance variable via a property’s accessors—as in the body of method DisplayMessage (Fig. 4.7, lines 28–29)—creates a more robust class that’s easier to maintain and less likely to malfunction. If we decide to change the representation of instance variable courseName in some way, the declaration of method DisplayMessage does not require modification—only the bodies of property CourseName’s get and set accessors that directly manipulate the instance variable will need to change. For example, suppose we want to represent the course name as two separate instance variables—courseNumber (e.g., "CS101") and courseTitle (e.g., "Introduction to C# Programming"). The DisplayMessage method can still use property CourseName’s get accessor to obtain the full course name to display as part of the welcome message. In this case, the get accessor would need to build and return a string containing the courseNumber, followed by the courseTitle. Method DisplayMessage would continue to display the complete course title “CS101 Introduction to C# Programming,” because it’s unaffected by the change to the class’s instance variables.

Auto-Implemented Properties

In Fig. 4.7, we created a GradeBook class with a private courseName instance variable and a public property CourseName to enable client code to access the courseName. When you look at the CourseName property’s definition (Fig. 4.7, lines 11–21), notice that the get accessor simply returns private instance variable courseName’s value and the set accessor simply assigns a value to the instance variable—no other logic appears in the accessors. For such cases, C# provides automatically implemented properties (also known as auto-implemented properties). With an auto-implemented property, the C# compiler creates a private instance variable, and the get and set accessors for returning and modifying the private instance variable. Unlike a user-defined property, an auto-implemented property, must have both a get and a set accessor. This enables you to implement the property trivially, which is handy when you’re first designing a class. If you later decide to include other logic in the get or set accessors, you can simply modify the property’s implementation. To use an auto-implemented property in the GradeBook class of Fig. 4.7, you can replace the private instance variable at line 8 and the property at lines 11–21 with the following code:

public string CourseName { get; set; }

Code Snippets for Auto-implemented Properties

The IDE has a feature called code snippets that allows you to insert predefined code templates into your source code. One such snippet enables you to insert a public auto-implemented property by typing the word “prop” in the code window and pressing the Tab key twice. Certain pieces of the inserted code are highlighted for you to easily change the property’s type and name. You can press the Tab key to move from one highlighted piece of text to the next in the inserted code. By default, the new property’s type is int and its name is MyProperty. To get a list of all available code snippets, type Ctrl + k, Ctrl + x. This displays the Insert Snippet window in the code editor. You can navigate through the Visual C# snippet folders with the mouse to see the snippets. This feature can also be accessed by right clicking in the source code editor and selecting the Insert Snippet... menu item.

Value Types vs. Reference Types

Types in C# are divided into two categories—value types and reference types. C#’s simple types (like int and double) are all value types. A variable of a value type simply contains a value of that type. For example, Fig. 4.10 shows an int variable named count that contains the value 7. Values types are implemented as structs, which are similar to classes and are discussed in more detail in Chapter 16.

Value-type variable.

Figure 4.10. Value-type variable.

By contrast, a variable of a reference type (sometimes called a reference) contains the address of a location in memory where the data referred to by that variable is stored. Such a variable is said to refer to an object in the program. Line 11 of Fig. 4.8 creates a GradeBook object, places it in memory and stores the object’s reference in variable myGradeBook of type GradeBook as shown in Fig. 4.11. The GradeBook object is shown with its courseName instance variable.

Reference-type variable.

Figure 4.11. Reference-type variable.

Reference-type instance variables (such as myGradeBook in Fig. 4.11) are initialized by default to the value null. string is a reference type. For this reason, string variable courseName is shown in Fig. 4.11 with an empty box representing the null-valued variable. A string variable with the value null is not an empty string, which is represented by "" or string.Empty. The value null represents a reference that does not refer to an object. The empty string is a string object with no characters in it.

A client of an object must use a variable that refers to the object to invoke (i.e., call) the object’s methods and access the object’s properties. In Fig. 4.8, the statements in Main use variable myGradeBook, which contains the GradeBook object’s reference, to send messages to the GradeBook object. These messages are calls to methods (like DisplayMessage) or references to properties (like CourseName) that enable the program to interact with GradeBook objects. For example, the statement (in line 19 of Fig. 4.8)

myGradeBook.CourseName = Console.ReadLine(); // set CourseName

uses the reference myGradeBook to set the course name by assigning a value to property CourseName. This sends a message to the GradeBook object to invoke the CourseName property’s set accessor. The message includes as an argument the value read from the user’s input (in this case, "CS101 Introduction to C# Programming") that CourseName’s set accessor requires to perform its task. The set accessor uses this information to set the courseName instance variable. In Section 7.16, we discuss value types and reference types in detail.

Software Engineering Observation 4.4

Software Engineering Observation 4.4

A variable’s declared type (e.g., int, double or GradeBook) indicates whether the variable is of a value or a reference type. If a variable’s type is not one of the simple types (Appendix B), or an enum or a struct type (which we discuss in Section 7.10 and Chapter 16, respectively), then it’s a reference type. For example, Account account1 indicates that account1 is a variable that can refer to an Account object.

Initializing Objects with Constructors

As mentioned in Section 4.5, when a GradeBook (Fig. 4.7) object is created, its instance variable courseName is initialized to null by default. This is also true of the private instance variable that the compiler creates for the auto-implemented CourseName property discussed in Section 4.8. What if you want to provide a course name when you create a GradeBook object? Each class can provide a constructor that can be used to initialize an object of a class when the object is created. In fact, C# requires a constructor call for every object that’s created. The new operator calls the class’s constructor to perform the initialization. The constructor call is indicated by the class name, followed by parentheses. For example, line 11 of Fig. 4.8 first uses new to create a GradeBook object. The empty parentheses after “new GradeBook()" indicate a call without arguments to the class’s constructor. The compiler provides a public default constructor with no parameters in any class that does not explicitly define a constructor, so every class has a constructor. The default constructor does not modify the default values of the instance variables.

When you declare a class, you can provide your own constructor (or several constructors, as you’ll learn in Chapter 10) to specify custom initialization for objects of your class. For example, you might want to specify a course name for a GradeBook object when the object is created, as in

GradeBook myGradeBook =
   new GradeBook( "CS101 Introduction to C# Programming" );

In this case, the argument "CS101 Introduction to C# Programming" is passed to the GradeBook object’s constructor and used to initialize the CourseName. Each time you create a new GradeBook object, you can provide a different course name. The preceding statement requires that the class provide a constructor with a string parameter. Figure 4.12 contains a modified GradeBook class with such a constructor.

Example 4.12. GradeBook class with a constructor to initialize the course name.

 1   // Fig. 4.12: GradeBook.cs
 2   // GradeBook class with a constructor to initialize the course name.
 3   using System;
 4
 5   public class GradeBook
 6   {
 7      // auto-implemented property CourseName implicitly created an
 8      // instance variable for this GradeBook's course name
 9      public string CourseName { get; set; }
10
11      // constructor initializes auto-implemented property
12      // CourseName with string supplied as argument      
13      public GradeBook( string name )                     
14      {                                                   
15         CourseName = name; // set CourseName to name     
16      } // end constructor                                
17
18      // display a welcome message to the GradeBook user
19      public void DisplayMessage()
20      {
21         // use auto-implemented property CourseName to get the
22         // name of the course that this GradeBook represents
23         Console.WriteLine( "Welcome to the grade book for
{0}!",
24            CourseName );
25      } // end method DisplayMessage
26   } // end class GradeBook

Lines 13–16 declare the constructor for class GradeBook. A constructor must have the same name as its class. Like a method, a constructor specifies in its parameter list the data it requires to perform its task. When you use new to create an object, you place this data in the parentheses that follow the class name. Unlike a method, a constructor doesn’t specify a return type (not even void). Line 13 indicates that class GradeBook’s constructor has a parameter called name of type string. In line 15, the name passed to the constructor is used to initialize auto-implemented property CourseName via its set accessor.

Figure 4.13 demonstrates initializing GradeBook objects using this constructor. Lines 12–13 create and initialize a GradeBook object. The constructor of class GradeBook is called with the argument "CS101 Introduction to C# Programming" to initialize the course name. The object-creation expression to the right of = in lines 12–13 returns a reference to the new object, which is assigned to variable gradeBook1. Lines 14–15 repeat this process for another GradeBook object, this time passing the argument "CS102 Data Structures in C#" to initialize the course name for gradeBook2. Lines 18–21 use each object’s CourseName property to obtain the course names and show that they were indeed initialized when the objects were created. In Section 4.5, you learned that each instance (i.e., object) of a class contains its own copy of the class’s instance variables. The output confirms that each GradeBook maintains its own course name.

Example 4.13. GradeBook constructor used to specify the course name at the time each GradeBook object is created.

 1   // Fig. 4.13: GradeBookTest.cs
 2   // GradeBook constructor used to specify the course name at the
 3   // time each GradeBook object is created.
 4   using System;
 5
 6   public class GradeBookTest
 7   {
 8      // Main method begins program execution
 9      public static void Main( string[] args )
10      {
11         // create GradeBook object
12         GradeBook gradeBook1 = new GradeBook( // invokes constructor
13            "CS101 Introduction to C# Programming" );                
14         GradeBook gradeBook2 = new GradeBook( // invokes constructor
15            "CS102 Data Structures in C#" );                         
16
17         // display initial value of courseName for each GradeBook
18         Console.WriteLine( "gradeBook1 course name is: {0}",
19            gradeBook1.CourseName );
20         Console.WriteLine( "gradeBook2 course name is: {0}",
21            gradeBook2.CourseName );
22      } // end Main
23   } // end class GradeBookTest
gradeBook1 course name is: CS101 Introduction to C# Programming
gradeBook2 course name is: CS102 Data Structures in C#

Normally, constructors are declared public. If a class does not explicitly define a constructor, the class’s instance variables are initialized to their default values—0 for numeric types, false for type bool and null for reference types. If you declare any constructors for a class, C# will not create a default constructor for that class.

Error-Prevention Tip 4.1

Error-Prevention Tip 4.1

Unless default initialization of your class’s instance variables is acceptable, provide a constructor to ensure that your class’s instance variables are initialized with meaningful values when each new object of your class is created.

Adding the Constructor to Class GradeBook’s UML Class Diagram

The UML class diagram of Fig. 4.14 models class GradeBook of Fig. 4.12, which has a constructor that has a name parameter of type string. Like operations, the UML models constructors in the third compartment of a class in a class diagram. To distinguish a constructor from a class’s operations, the UML places the word “constructor” between guillemets (« and ») before the constructor’s name. It’s customary to list constructors before other operations in the third compartment.

UML class diagram indicating that class GradeBook has a constructor with a name parameter of type string.

Figure 4.14. UML class diagram indicating that class GradeBook has a constructor with a name parameter of type string.

Floating-Point Numbers and Type decimal

In our next application, we depart temporarily from our GradeBook case study to declare a class called Account that maintains a bank account’s balance. Most account balances are not whole numbers (such as 0, −22 and 1024). For this reason, class Account represents the account balance as a real number (i.e., a number with a decimal point, such as 7.33, 0.0975 or 1000.12345). C# provides three simple types for storing real numbers—float, double, and decimal. Types float and double are called floating-point types. The primary difference between them and decimal is that decimal variables store a limited range of real numbers precisely, whereas floating-point variables store only approximations of real numbers, but across a much greater range of values. Also, double variables can store numbers with larger magnitude and finer detail (i.e., more digits to the right of the decimal point—also known as the number’s precision) than float variables. A key application of type decimal is representing monetary amounts.

Real-Number Precision and Storage Requirements

Variables of type float represent single-precision floating-point numbers and have seven significant digits. Variables of type double represent double-precision floating-point numbers. These require twice as much storage as float variables and provide 15–16 significant digits—approximately double the precision of float variables. Furthermore, variables of type decimal require twice as much storage as double variables and provide 28–29 significant digits. In some applications, even variables of type double and decimal will be inadequate—such applications are beyond the scope of this book.

Most programmers represent floating-point numbers with type double. In fact, C# treats all real numbers you type in an application’s source code (such as 7.33 and 0.0975) as double values by default. Such values in the source code are known as floating-point literals. To type a decimal literal, you must type the letter “M” or “m” (which stands for “money”) at the end of a real number (for example, 7.33M is a decimal literal rather than a double). Integer literals are implicitly converted into type float, double or decimal when they’re assigned to a variable of one of these types. See Appendix B for the ranges of values for floats, doubles, decimals and all the other simple types.

Although floating-point numbers are not always 100% precise, they have numerous applications. For example, when we speak of a “normal” body temperature of 98.6, we do not need to be precise to a large number of digits. When we read the temperature on a thermometer as 98.6, it may actually be 98.5999473210643. Calling this number simply 98.6 is fine for most applications involving body temperatures. Due to the imprecise nature of floating-point numbers, type decimal is preferred over the floating-point types whenever the calculations need to be exact, as with monetary calculations. In cases where approximation is enough, double is preferred over type float because double variables can represent floating-point numbers more accurately. For this reason, we use type decimal throughout the book for monetary amounts and type double for other real numbers.

Real numbers also arise as a result of division. In conventional arithmetic, for example, when we divide 10 by 3, the result is 3.3333333..., with the sequence of 3s repeating infinitely. The computer allocates only a fixed amount of space to hold such a value, so clearly the stored floating-point value can be only an approximation.

Common Programming Error 4.3

Common Programming Error 4.3

Using floating-point numbers in a manner that assumes they’re represented precisely can lead to logic errors.

Account Class with an Instance Variable of Type decimal

Our next application (Figs. 4.154.16) contains a simple class named Account (Fig. 4.15) that maintains the balance of a bank account. A typical bank services many accounts, each with its own balance, so line 7 declares an instance variable named balance of type decimal. Variable balance is an instance variable because it’s declared in the body of the class (lines 6–36) but outside the class’s method and property declarations (lines 10–13, 16–19 and 22–35). Every instance (i.e., object) of class Account contains its own copy of balance.

Example 4.15. Account class with a constructor to initialize instance variable balance.

 1   // Fig. 4.15: Account.cs
 2   // Account class with a constructor to
 3   // initialize instance variable balance.
 4
 5   public class Account
 6   {
 7      private decimal balance; // instance variable that stores the balance
 8
 9      // constructor
10      public Account( decimal initialBalance )
11      {
12         Balance = initialBalance; // set balance using property
13      } // end Account constructor
14
15      // credit (add) an amount to the account
16      public void Credit( decimal amount )
17      {
18         Balance = Balance + amount; // add amount to balance
19      } // end method Credit
20
21      // a property to get and set the account balance
22      public decimal Balance
23      {
24         get
25         {
26            return balance;
27         } // end get
28         set
29         {
30            // validate that value is greater than or equal to 0;
31            // if it is not, balance is left unchanged           
32            if ( value >= 0 )                                   
33               balance = value;                                  
34         } // end set
35      } // end property Balance
36   } // end class Account

Example 4.16. Create and manipulate an Account object.

 1   // Fig. 4.16: AccountTest.cs
 2   // Create and manipulate Account objects.
 3   using System;
 4
 5   public class AccountTest
 6   {
 7      // Main method begins execution of C# application
 8      public static void Main( string[] args )
 9      {
10         Account account1 = new Account( 50.00M ); // create Account object
11         Account account2 = new Account( -7.53M ); // create Account object
12
13         // display initial balance of each object using a property
14         Console.WriteLine( "account1 balance: {0:C}",
15            account1.Balance ); // display Balance property
16         Console.WriteLine( "account2 balance: {0:C}
",
17            account2.Balance ); // display Balance property
18
19         decimal depositAmount; // deposit amount read from user
20
21         // prompt and obtain user input
22         Console.Write( "Enter deposit amount for account1: " );
23         depositAmount = Convert.ToDecimal( Console.ReadLine() );
24         Console.WriteLine( "adding {0:C} to account1 balance
",
25            depositAmount );
26         account1.Credit( depositAmount ); // add to account1 balance
27
28         // display balances
29         Console.WriteLine( "account1 balance: {0:C}",
30            account1.Balance );
31         Console.WriteLine( "account2 balance: {0:C}
",
32            account2.Balance );
33
34         // prompt and obtain user input
35         Console.Write( "Enter deposit amount for account2: " );
36         depositAmount = Convert.ToDecimal( Console.ReadLine() );
37         Console.WriteLine( "adding {0:C} to account2 balance
",
38            depositAmount );
39         account2.Credit( depositAmount ); // add to account2 balance
40
41         // display balances
42         Console.WriteLine( "account1 balance: {0:C}", account1.Balance );
43         Console.WriteLine( "account2 balance: {0:C}", account2.Balance );
44      } // end Main
45   } // end class AccountTest

account1 balance: $50.00
account2 balance: $0.00

Enter deposit amount for account1: 49.99
adding $49.99 to account1 balance

account1 balance: $99.99
account2 balance: $0.00

Enter deposit amount for account2: 123.21
adding $123.21 to account2 balance

account1 balance: $99.99
account2 balance: $123.21

Class Account contains a constructor, a method, and a property. Since it’s common for someone opening an account to place money in the account immediately, the constructor (lines 10–13) receives a parameter initialBalance of type decimal that represents the account’s starting balance. Line 12 assigns initialBalance to the property Balance, invoking Balance’s set accessor to initialize the instance variable balance.

Method Credit (lines 16–19) doesn’t return data when it completes its task, so its return type is void. The method receives one parameter named amount—a decimal value that’s added to the property Balance. Line 18 uses both the get and set accessors of Balance. The expression Balance + amount invokes property Balance’s get accessor to obtain the current value of instance variable balance, then adds amount to it. We then assign the result to instance variable balance by invoking the Balance property’s set accessor (thus replacing the prior balance value).

Property Balance (lines 22–35) provides a get accessor, which allows clients of the class (i.e., other classes that use this class) to obtain the value of a particular Account object’s balance. The property has type decimal (line 22). Balance also provides an enhanced set accessor.

In Section 4.5, we introduced properties whose set accessors allow clients of a class to modify the value of a private instance variable. In Fig. 4.7, class GradeBook defines property CourseName’s set accessor to assign the value received in its parameter value to instance variable courseName (line 19). This CourseName property does not ensure that courseName contains only valid data.

The application of Figs. 4.154.16 enhances the set accessor of class Account’s property Balance to perform this validation (also known as validity checking). Line 32 (Fig. 4.15) ensures that value is nonnegative. If the value is greater than or equal to 0, the amount stored in value is assigned to instance variable balance in line 33. Otherwise, balance is left unchanged.

AccountTest Class to Use Class Account

Class AccountTest (Fig. 4.16) creates two Account objects (lines 10–11) and initializes them respectively with 50.00M and -7.53M (the decimal literals representing the real numbers 50.00 and -7.53). The Account constructor (lines 10–13 of Fig. 4.15) references property Balance to initialize balance. In previous examples, the benefit of referencing the property in the constructor was not evident. Now, however, the constructor takes advantage of the validation provided by the set accessor of the Balance property. The constructor simply assigns a value to Balance rather than duplicating the set accessor’s validation code. When line 11 of Fig. 4.16 passes an initial balance of -7.53 to the Account constructor, the constructor passes this value to the set accessor of property Balance, where the actual initialization occurs. This value is less than 0, so the set accessor does not modify balance, leaving this instance variable with its default value of 0.

Lines 14–17 in Fig. 4.16 output the balance in each Account by using the Account’s Balance property. When Balance is used for account1 (line 15), the value of account1’s balance is returned by the get accessor in line 26 of Fig. 4.15 and displayed by the Console.WriteLine statement (Fig. 4.16, lines 14–15). Similarly, when property Balance is called for account2 from line 17, the value of the account2’s balance is returned from line 26 of Fig. 4.15 and displayed by the Console.WriteLine statement (Fig. 4.16, lines 16–17). The balance of account2 is 0 because the constructor ensured that the account could not begin with a negative balance. The value is output by WriteLine with the format item {0:C}, which formats the account balance as a monetary amount. The : after the 0 indicates that the next character represents a format specifier, and the C format specifier after the : specifies a monetary amount (C is for currency). The cultural settings on the user’s machine determine the format for displaying monetary amounts. For example, in the United States, 50 displays as $50.00. In Germany, 50 displays as 50,00 €. Figure 4.17 lists a few other format specifiers in addition to C.

Table 4.17. string format specifiers.

Format specifier

Description

C or c

Formats the string as currency. Displays an appropriate currency symbol ($ in the U.S.) next to the number. Separates digits with an appropriate separator character (comma in the U.S.) and sets the number of decimal places to two by default.

D or d

Formats the string as a whole number. Displays number as an integer.

N or n

Formats the string with a thousands separator and a default of two decimal places.

E or e

Formats the number using scientific notation with a default of six decimal places.

F or f

Formats the string with a fixed number of decimal places (two by default).

G or g

Formats the number normally with decimal places or using scientific notation, depending on context. If a format item does not contain a format specifier, format G is assumed implicitly.

X or x

Formats the string as hexadecimal.

Line 19 declares local variable depositAmount to store each deposit amount entered by the user. Unlike the instance variable balance in class Account, the local variable depositAmount in Main is not initialized to 0 by default. Also, a local variable can be used only in the method in which it’s declared. However, this variable does not need to be initialized here because its value will be determined by the user’s input. The compiler does not allow a local variable’s value to be read until it’s initialized.

Line 22 prompts the user to enter a deposit amount for account1. Line 23 obtains the input from the user by calling the Console class’s ReadLine method, then passing the string entered by the user to the Convert class’s ToDecimal method, which returns the decimal value in this string. Lines 24–25 display the deposit amount. Line 26 calls object account1’s Credit method and supplies depositAmount as the method’s argument. When the method is called, the argument’s value is assigned to parameter amount of method Credit (lines 16–19 of Fig. 4.15), then method Credit adds that value to the balance (line 18 of Fig. 4.15). Lines 29–32 (Fig. 4.16) output the balances of both Accounts again to show that only account1’s balance changed.

Line 35 prompts the user to enter a deposit amount for account2. Line 36 obtains the input from the user by calling method Console.ReadLine, and passing the return value to the Convert class’s ToDecimal method. Lines 37–38 display the deposit amount. Line 39 calls object account2’s Credit method and supplies depositAmount as the method’s argument, then method Credit adds that value to the balance. Finally, lines 42–43 output the balances of both Accounts again to show that only account2’s balance changed.

set and get Accessors with Different Access Modifiers

By default, the get and set accessors of a property have the same access as the property—for example, for a public property, the accessors are public. It’s possible to declare the get and set accessors with different access modifiers. In this case, one of the accessors must implicitly have the same access as the property and the other must be declared with a more restrictive access modifier than the property. For example, in a public property, the get accessor might be public and the set accessor might be private. We demonstrate this feature in Section 10.5.

Error-Prevention Tip 4.2

Error-Prevention Tip 4.2

The benefits of data integrity are not automatic simply because instance variables are made private—you must provide appropriate validity checking and report the errors.

Error-Prevention Tip 4.3

Error-Prevention Tip 4.3

set accessors that set the values of private data should verify that the intended new values are proper; if they’re not, the set accessors should leave the instance variables unchanged and indicate an error. We demonstrate how to indicate errors in Chapter 10.

UML Class Diagram for Class Account

The UML class diagram in Fig. 4.18 models class Account of Fig. 4.15. The diagram models the Balance property as a UML attribute of type decimal (because the corresponding C# property had type decimal). The diagram models class Account’s constructor with a parameter initialBalance of type decimal in the third compartment of the class. The diagram models operation Credit in the third compartment with an amount parameter of type decimal (because the corresponding method has an amount parameter of C# type decimal).

UML class diagram indicating that class Account has a public Balance property of type decimal, a constructor and a method.

Figure 4.18. UML class diagram indicating that class Account has a public Balance property of type decimal, a constructor and a method.

Wrap-Up

In this chapter, you learned the basic object-oriented concepts of classes, objects, methods, instance variables and properties—these will be used in most substantial C# applications you create. You learned how to declare instance variables of a class to maintain data for each object of the class, how to declare methods that operate on that data, and how to declare properties to obtain and set that data. We demonstrated how to call a method to tell it to perform its task and how to pass information to methods as arguments. We discussed the difference between a local variable of a method and an instance variable of a class and that only instance variables are initialized automatically. We discussed the difference between a value type and a reference type. You learned how to create auto-implemented properties. You also learned how to use a class’s constructor to specify the initial values for an object’s instance variables. We discussed some of the differences between value types and reference types. You learned about the value types float, double and decimal for storing real numbers.

We showed how the UML can be used to create class diagrams that model the constructors, methods, properties and attributes of classes. You learned the value of declaring instance variables private and using public properties to manipulate them. For example, we demonstrated how set accessors in properties can be used to validate an object’s data and ensure that the object is maintained in a consistent state. In the next chapter we begin our introduction to control statements, which specify the order in which an application’s actions are performed. You’ll use these in your methods to specify how they should perform their tasks.

Summary

Section 4.2 Classes, Objects, Methods, Properties and Instance Variables

  • Methods perform tasks. Each method describes the mechanisms that actually perform its tasks. The method hides from its user the complex tasks that it performs.

  • The application unit that houses a method is called a class. A class may contain one or more methods that are designed to perform the class’s tasks.

  • A method can perform a task and may return a result.

  • An instance of a class is called an object.

  • Each message sent to an object is a method call and tells that method to perform its task.

  • Each method can specify parameters that represent additional information the method requires to perform its task correctly. A method call supplies arguments for the method’s parameters.

  • An object has attributes that are carried with the object as it’s used in an application. These attributes are specified as part of the object’s class. Attributes are specified in classes by fields.

  • An object has properties for accessing attributes. Properties contain get accessors for reading attributes and set accessors for storing into them.

Section 4.3 Declaring a Class with a Method and Instantiating an Object of a Class

  • Keyword public is an access modifier.

  • Every class declaration contains keyword class followed immediately by the class’s name.

  • A method declaration that begins with keyword public indicates that the method is “available to the public”—that is, it can be called by other classes declared outside the class declaration.

  • Keyword void indicates that a method will not return any information when it completes its task.

  • By convention, method names begin with an uppercase first letter, and all subsequent words in the name begin with an uppercase first letter. This is called Pascal case.

  • Empty parentheses following a method name indicate that the method does not require any parameters to perform its task.

  • Every method’s body is delimited by left and right braces ({ and }).

  • The body of a method contains statements that perform the method’s task. After the statements execute, the method has completed its task.

  • When you attempt to execute an application, C# looks for a Main method to begin execution.

  • Typically, you create an object of a class to call the class’s methods.

  • Object creation expressions begin with the new operator and create new objects.

  • To call a method of an object, follow the variable name with a member access operator (.), the method name and a set of parentheses containing the method’s arguments.

  • In the UML, each class is modeled in a class diagram as a rectangle with three compartments. The top compartment contains the name of the class, centered horizontally in boldface. The middle compartment contains the class’s attributes, which correspond to fields in C#. The bottom compartment contains the class’s operations, which correspond to methods and constructors in C#.

  • The UML models operations by listing the operation name, followed by a set of parentheses. A plus sign (+) in front of the operation name indicates that the operation is a public operation in the UML (i.e., a public method in C#). The plus sign is called the public visibility symbol.

Section 4.4 Declaring a Method with a Parameter

  • Methods often require additional information to perform their tasks. Such additional information is provided to methods via arguments in method calls.

  • Console method ReadLine reads characters until a newline character is encountered, then returns the characters as a string.

  • A method that requires data to perform its task must specify this in its declaration by placing additional information in the method’s parameter list.

  • Each parameter must specify both a type and an identifier.

  • At the time a method is called, its arguments are assigned to its parameters. Then the method body uses the parameter variables to access the argument values.

  • A method can specify multiple parameters in a comma-separated parameter list.

  • The number of arguments in the method call must match the number of required parameters in the method declaration’s parameter list. Also, the argument types in the method call must be consistent with the types of the corresponding parameters in the method’s declaration.

  • The UML models a parameter of an operation by listing the parameter name, followed by a colon and the parameter type between the parentheses following the operation name.

  • The UML does not provide types that correspond to every C# type. For this reason, and to avoid confusion between UML types and C# types, we use only C# types in our UML diagrams.

  • There’s a special relationship between classes that are compiled in the same project. By default, such classes are considered to be in the same namespace. A using directive is not required when one class in a namespace uses another in the same namespace.

  • A using directive is not required if you always refer to a class with its fully qualified class name.

Section 4.5 Instance Variables and Properties

  • Local variables can be used only in the method in which they’re declared.

  • A class normally contains methods that manipulate the attributes that belong to a particular object of the class. Attributes are represented as instance variables in a class declaration. Such variables are declared inside a class declaration but outside its method’s bodies.

  • Each object (instance) of a class has a separate copy of each instance variable.

  • Most instance-variable declarations are preceded with the private access modifier. Variables, properties or methods declared with access modifier private are accessible only to methods (and properties) of the class in which they’re declared.

  • Declaring instance variables with access modifier private is known as information hiding.

  • Properties contain accessors that handle the details of modifying and returning data.

  • Properties provide a controlled way for programmers to “get” (i.e., retrieve) the value in an instance variable and “set” (i.e., modify) the value in an instance variable.

  • A property declaration can contain a get accessor, a set accessor or both. The get accessor typically enables a client to read the value of a private instance variable. The set accessor typically enables a client to modify that instance variable’s value.

  • After defining a property, you can use it the same way as you use a variable.

  • The default value for a field of type string is null.

Section 4.6 UML Class Diagram with a Property

  • We model properties in the UML as attributes, preceded by the word “property” in guillemets (« and »). Using descriptive words in guillemets (called stereotypes in the UML) helps distinguish properties from other attributes.

  • A class diagram helps you design a class, so it’s not required to show every implementation detail of the class. Since an instance variable that’s manipulated by a property is really an implementation detail of that property, our class diagrams do not show instance variables.

  • private class members are preceded by the private visibility symbol (-) in the UML.

  • The UML represents instance variables and properties as attributes by listing the attribute name, followed by a colon and the attribute type.

Section 4.7 Software Engineering with Properties and set and get Accessors

  • Properties can scrutinize attempts to modify an instance variable’s value (known as data validation), thus ensuring that the new value for that instance variable is valid.

  • Using properties would seem to violate the notion of private data. However, a set accessor can provide data-validation capabilities to ensure that the value is set properly; get and set accessors can translate between the format of the data used by the client and the format used in the private instance variable.

  • A benefit of fields over local variables is that all of a class’s methods and properties can use the fields. Another distinction is that a field has a default initial value provided by C# when you do not specify the field’s initial value, but a local variable does not.

Section 4.8 Auto-Implemented Properties

  • With an auto-implemented property, the C# compiler automatically creates a private instance variable, and the get and set accessors for returning and modifying the private instance variable.

  • Visual C# 2010 Express and Visual Studio 2010 have a feature called code snippets that allows you to insert predefined code templates into your source code. One such snippet enables you to insert a public auto-implemented property by typing the word “prop” in the code window and pressing the Tab key twice.

  • Pieces of the inserted code are highlighted for you to easily change the property’s type and name. Press the Tab key to move from one highlighted piece of text to the next in the inserted code.

  • To get a list of all available code snippets, type Ctrl + k, Ctrl + x. This displays the Insert Snippet window in the code editor. This feature can also be accessed by right clicking in the source code editor and selecting the Insert Snippet... menu item.

Section 4.9 Value Types vs. Reference Types

  • Types are divided into two categories—value types and reference types.

  • A variable of a value type contains data of that type.

  • A variable of a reference type (sometimes called a reference) contains the address of a location in memory where an object is stored.

  • Reference-type instance variables are initialized by default to the value null.

Section 4.10 Initializing Objects with Constructors

  • A constructor can be used to initialize an object of a class when the object is created.

  • If no constructor is provided for a class, the compiler provides a public default constructor with no parameters that does not modify the instance variables’ default values.

  • Like operations, the UML models constructors in the third compartment of a class diagram. To distinguish a constructor from a class’s operations, the UML places the word “constructor” between guillemets (« and ») before the constructor’s name.

  • Constructors can specify parameters but cannot specify return types.

Section 4.11 Floating-Point Numbers and Type decimal

  • A real number is a number with a decimal point, such as 7.33, 0.0975 or 1000.12345. C# provides three simple types for storing real numbers—float, double, and decimal.

  • Types float and double are called floating-point types. The primary difference between them and the decimal type is that decimal variables store a limited range of real numbers precisely, but floating-point variables store approximations of real numbers across a much greater range.

  • Variables of type float represent single-precision floating-point numbers and have seven significant digits. Variables of type double represent double-precision floating-point numbers. These require twice as much storage as float variables and provide 15–16 significant digits—approximately double the precision of float variables. Furthermore, variables of type decimal require twice as much storage as double variables and provide 28–29 significant digits.

  • Real number values that appear in source code are of type double by default.

  • Convert method ToDecimal extracts a decimal value from a string.

  • The : in a format item indicates that the next character represents a format specifier.

  • The C format specifier specifies a monetary amount (C is for currency).

  • It’s possible to declare the get and set accessors of a property with different access modifiers. One accessor must implicitly have the same access as the property and the other must be declared with a more restrictive access modifier than the property; private is more restrictive than public.

Self-Review Exercises

4.1

Fill in the blanks in each of the following:

  1. A house is to a blueprint as a(n) _______ is to a class.

  2. Every class declaration contains keyword _______ followed immediately by the class’s name.

  3. Operator _______ creates an object of the class specified to the right of the keyword.

  4. Each parameter must specify both a(n) _______ and a(n) _______.

  5. By default, classes that are not explicitly declared in a namespace are implicitly placed in the _______.

  6. When each object of a class maintains its own copy of an attribute, the field that represents the attribute is also known as a(n) _______.

  7. C# provides three simple types for storing real numbers—_______, _______ and _______.

  8. Variables of type double represent _______ floating-point numbers.

  9. Convert method _______ returns a decimal value.

  10. Keyword public is a(n) _______.

  11. Return type _______ indicates that a method will not return any information when it completes its task.

  12. Console method _______ reads characters until a newline character is encountered, then returns those characters (not including the newline) as a string.

  13. A(n) _______ is not required if you always refer to a class with its fully qualified class name.

  14. Variables of type float represent _______ floating-point numbers.

  15. The format specifier _______ is used to display values in a monetary format.

  16. Types are either _______ types or _______ types.

  17. For a(n) _______, the compiler automatically generates a private instance variable and set and get accessors.

4.1

  1. object.

  2. class.

  3. new.

  4. type, name.

  5. global namespace.

  6. instance variable.

  7. float, double, decimal.

  8. double-precision.

  9. ToDecimal.

  10. access modifier.

  11. void.

  12. ReadLine.

  13. using directive.

  14. single-precision.

  15. C.

  16. value, reference.

  17. auto-implemented property.

4.2

State whether each of the following is true or false. If false, explain why.

  1. By convention, method names begin with a lowercase first letter and all subsequent words in the name begin with a capital first letter.

  2. A property’s get accessor enables a client to modify the value of the instance variable associated with the property.

  3. A using directive is not required when one class in a namespace uses another in the same namespace.

  4. Empty parentheses following a method name in a method declaration indicate that the method does not require any parameters to perform its task.

  5. After defining a property, you can use it the same way you use a method, but with empty parentheses, because no arguments are passed to a property.

  6. Variables or methods declared with access modifier private are accessible only to methods and properties of the class in which they’re declared.

  7. Variables declared in the body of a particular method are known as instance variables and can be used in all methods of the class.

  8. A property declaration must contain both a get accessor and a set accessor.

  9. The body of any method or property is delimited by left and right braces.

  10. Local variables are initialized by default.

  11. Reference-type instance variables are initialized by default to the value null.

  12. Any class that contains public static void Main( string[] args ) can be used to execute an application.

  13. The number of arguments in the method call must match the number of required parameters in the method declaration’s parameter list.

  14. Real number values that appear in source code are known as floating-point literals and are of type float by default.

4.2

  1. False. By convention, method names begin with an uppercase first letter and all subsequent words in the name begin with an uppercase first letter.

  2. False. A property’s get accessor enables a client to retrieve the value of the instance variable associated with the property. A property’s set accessor enables a client to modify the value of the instance variable associated with the property.

  3. True.

  4. True.

  5. False. After defining a property, you can use it the same way you use a variable.

  6. True.

  7. False. Such variables are called local variables and can be used only in the method in which they’re declared.

  8. False. A property declaration can contain a get accessor, a set accessor or both.

  9. True.

  10. False. Instance variables are initialized by default.

  11. True.

  12. True.

  13. True.

  14. False. Such literals are of type double by default.

4.3

What is the difference between a local variable and an instance variable?

4.3

A local variable is declared in the body of a method and can be used only in the method in which it’s declared. An instance variable is declared in a class, but not in the body of any of the class’s methods. Every object (instance) of a class has a separate copy of the class’s instance variables. Also, instance variables are accessible to all methods of the class. (We’ll see an exception to this in Chapter 10, Classes and Objects: A Deeper Look.)

4.4

Explain the purpose of a method parameter. What is the difference between a parameter and an argument?

4.4

A parameter represents additional information that a method requires to perform its task. Each parameter required by a method is specified in the method’s declaration. An argument is the actual value that’s passed to a method parameter when a method is called.

Answers to Self-Review Exercises

Exercises

4.5

What is the purpose of operator new? Explain what happens when this keyword is used in an application.

4.6

What is a default constructor? How are an object’s instance variables initialized if a class has only a default constructor?

4.7

Explain the purpose of an instance variable.

4.8

Explain how an application could use class Console without using a using directive.

4.9

Explain why a class might provide a property for an instance variable.

4.10

(GradeBook Modification) Modify class GradeBook (Fig. 4.12) as follows:

  1. Include a second string auto-implemented property that represents the name of the course’s instructor.

  2. Modify the constructor to specify two parameters—one for the course name and one for the instructor’s name.

  3. Modify method DisplayMessage such that it first outputs the welcome message and course name, then outputs "This course is presented by: ", followed by the instructor’s name.

Use your modified class in a test application that demonstrates the class’s new capabilities.

4.11

(Account Modification) Modify class Account (Fig. 4.15) to provide a method called Debit that withdraws money from an Account. Ensure that the debit amount doesn’t exceed the balance. If it does, the balance should not be changed and the method should display a message indicating "Debit amount exceeded account balance." Modify class AccountTest (Fig. 4.16) to test method Debit.

4.12

(Invoice Class) Create a class called Invoice that a hardware store might use to represent an invoice for an item sold at the store. An Invoice should include four pieces of information as either instance variables or automatic properties—a part number (type string), a part description (type string), a quantity of the item being purchased (type int) and a price per item (decimal). Your class should have a constructor that initializes the four values. Provide a property with a get and set accessor for any instance variables. For the Quantity and PricePerItem properties, if the value passed to the set accessor is negative, the value of the instance variable should be left unchanged. Also, provide a method named GetInvoiceAmount that calculates the invoice amount (i.e., multiplies the quantity by the price per item), then returns the amount as a decimal value. Write a test application named InvoiceTest that demonstrates class Invoice’s capabilities.

4.13

(Employee Class) Create a class called Employee that includes three pieces of information as either instance variables or automatic properties—a first name (type string), a last name (type string) and a monthly salary (decimal). Your class should have a constructor that initializes the three values. Provide a property with a get and set accessor for any instance variables. If the monthly salary is negative, the set accessor should leave the instance variable unchanged. Write a test application named EmployeeTest that demonstrates class Employee’s capabilities. Create two Employee objects and display each object’s yearly salary. Then give each Employee a 10% raise and display each Employee’s yearly salary again.

4.14

(Date Class) Create a class called Date that includes three pieces of information as automatic properties—a month (type int), a day (type int) and a year (type int). Your class should have a constructor that initializes the three automatic properties and assumes that the values provided are correct. Provide a method DisplayDate that displays the month, day and year separated by forward slashes (/). Write a test application named DateTest that demonstrates class Date’s capabilities.

Making a Difference Exercises

4.15

(Target-Heart-Rate Calculator) While exercising, you can use a heart-rate monitor to see that your heart rate stays within a safe range suggested by your trainers and doctors. According to the American Heart Association (AHA) (www.americanheart.org/presenter.jhtml?identifier=4736), the formula for calculating your maximum heart rate in beats per minute is 220 minus your age in years. Your target heart rate is a range that is 50–85% of your maximum heart rate. [Note: These formulas are estimates provided by the AHA. Maximum and target heart rates may vary based on the health, fitness and gender of the individual. Always consult a physician or qualified health care professional before beginning or modifying an exercise program.] Create a class called HeartRates. The class attributes should include the person’s first name, last name, year of birth and the current year. Your class should have a constructor that receives this data as parameters. For each attribute provide a property with set and get accessors. The class also should include a property that calculates and returns the person’s age (in years), a property that calculates and returns the person’s maximum heart rate and properties that calculate and return the person’s minimum and maximim target heart rates. Write an application that prompts for the person’s information, instantiates an object of class HeartRates and prints the information from that object—including the person’s first name, last name and year of birth—then calculates and prints the person’s age in (years), maximum heart rate and targetheart-rate range.

4.16

(Computerization of Health Records) A health care issue that has been in the news lately is the computerization of health records. This possibility is being approached cautiously because of sensitive privacy and security concerns, among others. [We address such concerns in later exercises.] Computerizing health records could make it easier for patients to share their health profiles and histories among their various health care professionals. This could improve the quality of health care, help avoid drug conflicts and erroneous drug prescriptions, reduce costs and, in emergencies, could save lives. In this exercise, you’ll design a “starter” HealthProfile class for a person. The class attributes should include the person’s first name, last name, gender, date of birth (consisting of separate attributes for the month, day and year of birth), height (in inches) and weight (in pounds). Your class should have a constructor that receives this data. For each attribute provide a property with set and get accessors. The class also should include methods that calculate and return the user’s age in years, maximum heart rate and target-heart-rate range (see Exercise 4.15), and body mass index (BMI; see Exercise 3.31). Write an application that prompts for the person’s information, instantiates an object of class HealthProfile for that person and prints the information from that object—including the person’s first name, last name, gender, date of birth, height and weight—then calculates and prints the person’s age in years, BMI, maximum heart rate and target-heart-rate range. It should also display the “BMI values” chart from Exercise 3.31.

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

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