Programs and Classes: A Quick Example
Creating Variables and Instances of a Class
Allocating Memory for the Data
Accessing Members from Inside the Class
Accessing Members from Outside the Class
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.
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:
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.
Note Classes are encapsulated sets of logically related data items and functions that generally represent objects in the real world or a conceptual world.
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.
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.
Note A running program is a set of objects interacting with each other.
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 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.
For example, the following code shows the outlines of two class declarations:
class Dealer // Class declaration
{
...
}
class Dealer // Class declaration
{
...
}
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.
Fields and methods are the most important of the class member types. Fields are data members, and methods are function members.
A field is a variable that belongs to a class.
The minimum syntax for declaring a field is the following:
For example, the following class contains the declaration of field MyField
, which can store an int
value:
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.
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.
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"
}
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";
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:
void
.For example, the following code declares a class with a simple method called PrintNums
. From the declaration, you can tell the following about PrintNums
:
void
.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.
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.
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.
Figure 4-2. Allocating memory for the reference of a class variable
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.
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.new
operator to form an object-creation expression, which consists of the following:
new
.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:
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.
Figure 4-3. Allocating memory for the data of a class variable
You can combine the two steps by initializing the variable with the object-creation expression.
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.
A class declaration acts as a blueprint from which you can create as many instances of the class as you like.
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();
...
}
}
Figure 4-4. Instance members have distinct values between class objects.
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:
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 members are accessible only from within the class in which they are declared—other classes cannot see or access them.
private
access modifier to explicitly declare a member as private.For example, the following two declarations both specify private
int
members:
Public members are accessible to other objects in the program. You must use the public
access modifier to specify public access.
The figures in this text represent classes as labeled boxes, as shown in Figure 4-5.
Figure 4-5. Representing classes and members
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
{
...
}
}
Figure 4-6. Private and public class members
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.
Figure 4-7. Members within a class can freely access each other.
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:
As an example, the following code declares two classes: DaysTemp
and Program
.
DaysTemp
are declared public
, so they can be accessed from outside the class.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.This code produces the following output:
High: 85
Low: 60
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:
This code produces the following output:
t1: 76, 57, 66
t2: 75, 53, 64
Figure 4-8. Memory layout of instances t1 and t2
3.145.103.154