C H A P T E R  4

Image

Classes: The Basics

Image Overview of Classes

Image Programs and Classes: A Quick Example

Image Declaring a Class

Image Class Members

Image Creating Variables and Instances of a Class

Image Allocating Memory for the Data

Image Instance Members

Image Access Modifiers

Image Accessing Members from Inside the Class

Image Accessing Members from Outside the Class

Image Putting It All Together

Overview of Classes

In the previous chapter, you saw that C# provides six user-defined types. The most important of these, and the one I'll cover first, is the class. Since the topic of classes in C# is a large one, its discussion will be spread over the next several chapters.

A Class Is an Active Data Structure

Before the days of object-oriented analysis and design, programmers thought of a program as just a sequence of instructions. The focus at that time was on structuring and optimizing those instructions. With the advent of the object-oriented paradigm, the focus changed from optimizing instructions to organizing a program's data and functions into encapsulated sets of logically related data items and functions, called classes.

A class is a data structure that can store data and execute code. It contains the following:

  • Data members, which store data associated with the class or an instance of the class. Data members generally model the attributes of the real-world object the class represents.
  • Function members, which execute code. Function members generally model the functions and actions of the real-world object the class represents.

A C# class can have any number of data and function members. The members can be any combination of nine possible member types. Table 4-1 shows these member types. The ones I'll cover in this chapter—fields and methods—are checked in the table.

Image

Image Note Classes are encapsulated sets of logically related data items and functions that generally represent objects in the real world or a conceptual world.

Programs and Classes: A Quick Example

A running C# program is a group of interacting type objects, most of which are instances of classes. For example, suppose you have a program simulating a poker game. When it's running, it might have an instance of a class called Dealer, whose job is to run the game, and several instances of a class called Player, which represent the players of the game.

The Dealer object stores such information as the current state of the card deck and the number of players. Its actions include shuffling the deck and dealing the cards.

The Player class is very different. It stores such information as the player's name and the amount of money left to bet, and it performs such actions as analyzing the player's current hand and placing bets. Figure 4-1 illustrates the running program.

Image

Figure 4-1. The objects in a running program

A real program would undoubtedly contain dozens of other classes besides Dealer and Player. These would include classes such as Card and Deck. Each class models some thing that is a component of the poker game.

Image Note A running program is a set of objects interacting with each other.

Declaring a Class

Although types int, double, and char are defined in the C# language, classes such as Dealer and Player, as you can probably guess, are not defined by the language. If you want to use them in a program, you'll have to define them yourself. You do this by writing a class declaration.

A class declaration defines the characteristics and members of a new class. It does not create an instance of the class but creates the template from which class instances will be created. The class declaration provides the following:

  • The class name
  • The members of the class
  • The characteristics of the class

The following is an example of the minimum syntax for a class declaration. The curly braces contain the member declarations that make up the class body. Class members can be declared in any order inside the class body. This means it's perfectly fine for the declaration of a member to refer to another member that is not yet defined until further down in the class declaration.

Image

For example, the following code shows the outlines of two class declarations:

   class Dealer                                    // Class declaration
   {
      ...
   }

   class Dealer                                    // Class declaration
   {
      ...
   }

Image Note Since a class declaration “defines” a new class, you will often see a class declaration referred to as a class definition both in the literature and in common usage among programmers.

Class Members

Fields and methods are the most important of the class member types. Fields are data members, and methods are function members.

Fields

A field is a variable that belongs to a class.

  • It can be of any type, either predefined or user-defined.
  • Like all variables, fields store data and have the following characteristics:
    • They can be written to.
    • They can be read from.

The minimum syntax for declaring a field is the following:

Image

For example, the following class contains the declaration of field MyField, which can store an int value:

Image

Image Note Unlike C and C++, there are no global variables (that is, variables or fields) declared outside of a type. All fields belong to a type and must be declared within the type declaration.

Explicit and Implicit Field Initialization

Since a field is a kind of variable, the syntax for a field initializer is the same as that of the variable initializer shown in the previous chapter.

  • A field initializer is part of the field declaration and consists of an equals sign followed by an expression that evaluates to a value.
  • The initialization value must be determinable at compile time.

    Image

  • If no initializer is used, the value of a field is set by the compiler to a default value, determined by the type of the field. Table 3-1 (in Chapter 3) gives the default values for the simple types. To summarize them, though, the default value for each type is 0, and false for bool. The default for reference types is null.

For example, the following code declares four fields. The first two fields are initialized implicitly. The second two fields are initialized explicitly with initializers.

   class MyClass
   {
       int    F1;                     // Initialized to 0    - value type
       string F2;                     // Initialized to null - reference type

       int    F3; = 25;               // Initialized to 25
       string F4 = "abcd";            // Initialized to "abcd"
   }
Declarations with Multiple Fields

You can declare multiple fields of the same type in the same statement by separating the names with commas. You cannot mix different types in a single declaration. For example, you can combine the four preceding field declarations into two statements, with the exact same semantic result:

   int    F1, F3 = 25;
   string F2, F4 = "abcd";

Methods

A method is a named block of executable code that can be executed from many different parts of the program, and even from other programs. (There are also anonymous methods, which aren't named—but I'll cover those in Chapter 15.)

When a method is called, or invoked, it executes its code and then returns to the code that called it. Some methods return a value to the position from which they were called. Methods correspond to member functions in C++.

The minimum syntax for declaring a method includes the following components:

  • Return type: This states the type of value the method returns. If a method doesn't return a value, the return type is specified as void.
  • Name: This is the name of the method.
  • Parameter list: This consists of at least an empty set of matching parentheses. If there are parameters (which I'll cover in the next chapter), they are listed between the parentheses.
  • Method body: This consists of a matching set of curly braces, containing the executable code.

For example, the following code declares a class with a simple method called PrintNums. From the declaration, you can tell the following about PrintNums:

  • It returns no value; hence, the return type is specified as void.
  • It has an empty parameter list.
  • It contains two lines of code in its method body.

Image

Image Note Unlike C and C++, there are no global functions (that is, methods or functions) declared outside of a type declaration. Also, unlike C and C++, there is no “default” return type for a method. All methods must include a return type or list it as void.

Creating Variables and Instances of a Class

The class declaration is just the blueprint from which instances of the class are created. Once a class is declared, you can create instances of the class.

  • Classes are reference types, which, as you will remember from the previous chapter, means that they require memory both for the reference to the data and for the actual data.
  • The reference to the data is stored in a variable of the class type. So, to create an instance of the class, you need to start by declaring a variable of the class type. If the variable isn't initialized, its value is undefined.

Figure 4-2 illustrates how to define the variable to hold the reference. At the top of the code on the left is a declaration for class Dealer. Below that is a declaration for class Program, which contains method Main. Main declares variable theDealer of type Dealer. Since the variable is uninitialized, its value is undefined, as shown on the right in the figure.

Image

Figure 4-2. Allocating memory for the reference of a class variable

Allocating Memory for the Data

Declaring the variable of the class type allocates the memory to hold the reference, but not the memory to hold the actual data of the class object. To allocate memory for the actual data, you use the new operator.

  • The new operator allocates and initializes memory for an instance of any specified type. It allocates the memory from either the stack or the heap, depending on the type.
  • Use the new operator to form an object-creation expression, which consists of the following:
    • The keyword new.
    • The name of the type of the instance for which memory is to be allocated.
    • Matching parentheses, which might or might not include parameters. I'll discuss more about the possible parameters later.

    Image

  • If the memory allocated is for a reference type, the object-creation expression returns a reference to the allocated and initialized instance of the object in the heap.

This is exactly what you need to allocate and initialize the memory to hold the class instance data. Use the new operator to create an object-creation expression, and assign the value returned by it to the class variable. Here's an example:

Image

The code on the left in Figure 4-3 shows the new operator used to allocate memory and create an instance of class Dealer, which is then assigned to the class variable. The memory structure is illustrated in the figure, to the right of the code.

Image

Figure 4-3. Allocating memory for the data of a class variable

Combining the Steps

You can combine the two steps by initializing the variable with the object-creation expression.

Image

In the case of local variables, but not fields, you can simplify the syntax a bit more by having the compiler infer the type in the declaration part on the left. But I'll cover that in the section on local variables in the next chapter.

Instance Members

A class declaration acts as a blueprint from which you can create as many instances of the class as you like.

  • Instance members: Each instance of a class is a separate entity that has its own set of data members, distinct from the other instances of the same class. These are called instance members since they are associated with an instance of the class.
  • Static members: Instance members are the default, but you can also declare members called static members that are associated with the class, rather than the instance. I'll cover these in Chapter 6.

As an example of instance members, the following code shows the poker program with three instances of class Player. Figure 4-4 shows that each instance has a different value for the Name field.

   class Dealer { ... }                            // Declare class
   class Player {                                  // Declare class
      string Name;                                 // Field
         ...
   }

   class Program {
      static void Main()
      {
         Dealer theDealer = new Dealer();
         Player player1   = new Player();
         Player player2   = new Player();
         Player player3   = new Player();
         ...
      }
   }
Image

Figure 4-4. Instance members have distinct values between class objects.

Access Modifiers

From within a class, any function member can access any other member of the class by simply using that member's name.

The access modifier is an optional part of a member declaration that specifies what other parts of the program have access to the member. The access modifier is placed before the simple declaration forms. The following is the syntax for fields and methods:

Image

The five categories of member access are the following. I'll describe the first two in this chapter and the others in Chapter 7.

  • private
  • public
  • protected
  • internal
  • protected internal

Private and Public Access

Private members are accessible only from within the class in which they are declared—other classes cannot see or access them.

  • Private access is the default access level, so if a member is declared without an access modifier, it is a private member.
  • You can also use the private access modifier to explicitly declare a member as private.
  • There is no semantic difference between declaring a private member implicitly as opposed to explicitly. The forms are equivalent.

For example, the following two declarations both specify private int members:

Image

Public members are accessible to other objects in the program. You must use the public access modifier to specify public access.

Image

Depicting Public and Private Access

The figures in this text represent classes as labeled boxes, as shown in Figure 4-5.

  • The class members are represented as smaller labeled boxes inside the class boxes.
  • Private members are represented enclosed entirely within their class box.
  • Public members are represented sticking partially outside their class box.
Image

Figure 4-5. Representing classes and members

Example of Member Access

Class C1 in the following code declares both public and private fields and methods. Figure 4-6 illustrates the visibility of the members of class C1.

   class C1
   {
      int         F1;                     // Implicit private field
      private int F2;                     // Explicit private field
      public int F3;                      // Public field

      void DoCalc();                      // Implicit private method
      {
         ...
      }

      public int GetVal()                 // Public method
      {
         ...
      }
   }
Image

Figure 4-6. Private and public class members

Accessing Members from Inside the Class

As mentioned, members of a class can access the other class members by just using their names.

For example, the following class declaration shows the methods of the class accessing the fields and other methods. Even though the fields and two of the methods are declared private, all the members of a class can be accessed by any method (or any function member) of the class. Figure 4-7 illustrates the code.

Image

Image

Figure 4-7. Members within a class can freely access each other.

Accessing Members from Outside the Class

To access a public instance member from outside the class, you must include the variable name and the member name, separated by a period (dot). This is called dot-syntax notation; it will be discussed in more detail later.

For example, the second line of the following code shows an example of accessing a method from outside the class:

Image

As an example, the following code declares two classes: DaysTemp and Program.

  • The two fields in DaysTemp are declared public, so they can be accessed from outside the class.
  • Method Main is a member of class Program. It creates a variable and object of class DaysTemp, and it assigns values to the fields of the object. It then reads the values of the fields and prints them out.

Image

This code produces the following output:


High:  85
Low:   60

Putting It All Together

The following code creates two instances and stores their references in variables named t1 and t2. Figure 4-8 illustrates t1 and t2 in memory. The code demonstrates the following three actions discussed so far in the use of a class:

  • Declaring a class
  • Creating instances of the class
  • Accessing the class members (that is, writing to a field and reading from a field)

Image

This code produces the following output:


t1: 76, 57, 66
t2: 75, 53, 64

Image

Figure 4-8. Memory layout of instances t1 and t2

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

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