2.9. static Class Members

Not all members of a class make sense as instance members. Some members provide a service or contain information that is independent of an individual class object. The current value of an integer, for example, is an instance member. The maximum value an integer can hold is not. It holds true for all integer objects.

We would not want each integer object to hold a copy of the maximum value an integer can hold. However, it is information that users of the integer type would like to retrieve and to compare individual instances against.

That is, the maximum integer value makes sense as a member of the class representing the integer type. It does not make sense as an instance member of that class. This is why we declare certain class members as static or const.

A static member represents a class member rather than an instance member. Today and Now, for example, are static properties of the DateTime class. Today represents the current date, with the time set to 0. Now represents the current date and time. The member functions WriteLine() and Read Line() are static member functions of the Console class. MaxValue is a static data member of the Int32 class.

In our WordCount class, the character array of separators with which to split a line of text into individual words makes sense as a static member. Here is how we declare that:

public class WordCount
{
    static public char [] ms_separators;

Only a single instance of a static data member exists in a program. It exists independently of the individual class instances. Within a class member function, we can syntactically access a static member just as we do an instance member—for example,

private void countWords()
{
    // ...
    for( int ix = 0; ix < m_text.Count; ++ix )
    {
        str = ( string )m_text[ ix ];
        m_sentences[ ix ] = str.Split( ms_separators );

Outside the class, we access a static member through the name of the class to which it belongs—for example,

static void Main()
{
   char bang = '!';
   int ix = 0;

   for( ; ix < WordCount.ms_separators.Length; ++ix )
          if ( WordCount.ms_separators[ ix ] == bang )
              break;

   if ( ix == WordCount.ms_separators.Length )
          throw new Exception( "Insufficient separators" );

A static member may not be accessed through an object of the class. Doing so triggers an error—for example,

int len = theObj.ms_separators.Length; // error

A static member is also initialized to the default value of its type—in our example, ms_separators is set to null because an array is a reference type. We can provide an explicit initial value with its declaration —for example,

public class WordCount
{
    static public char [] ms_separators = new char []
           { ' ', '
', '	', '.', '"', ';', ',',
                  '?', '!',')', '(', '<', '>', '[', ']' };

Alternatively, we can initialize the static members of a class within a static constructor—for example,

public struct WordCount
{
   static public char [] ms_separators;
   static WordCount() // static constructor
   {
          ms_separators = new char []
          { ' ', '
', '	', '.', '"', ';', ',',
                 '?', '!',')', '(', '<', '>', '[', ']' };
   }

   // ...
}

Only one static constructor can be defined for a class. We identify a static constructor by prefixing its name with the static keyword. By default, the static constructor is public; however, it is an error to explicitly provide an access level—even that of public. The static constructor must be declared to have an empty parameter list. (This is why we can define only one static constructor. If we want to overload a function, each overloaded instance must have a unique signature.)

The static constructor is invoked only once, and only if an instance of the class is created or a static member of the class is accessed. The exact ordering of static-constructor invocations within the program is undefined.

We can initialize or invoke static members only within the static constructor. An attempt to access an instance member results in an error. A static constructor, however, is not limited to initializing static class members. We can use it to perform any action before we create an initial class object or access a class static member. An interesting example of using static constructors is presented in Section 8.5.

Typically we declare static data members as private, and we provide read and write access through a static property. We can also declare member functions as static. A static member function lacks a this reference and cannot directly access any instance members of its class.

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

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