Section 12.6. static Class Members


12.6. static Class Members

It is sometimes necessary for all the objects of a particular class type to access a global object. Perhaps a count is needed of how many objects of a particular class type have been created at any one point in the program, or the global object may be a pointer to an error-handling routine for the class, or it may be a pointer to the free-store memory for objects of this class type.

However, making the object global violates encapsulation: The object exists to support the implementation of a particular class abstraction. If the object is global, general user code can modify the value. Rather than defining a generally accessible global object, a class can define a class static member.

Ordinary, nonstatic data members exist in each object of the class type. Unlike ordinary data members, a static data member exists independently of any object of its class; each static data member is an object associated with the class, not with the objects of that class.

Just as a class may define shared static data members, it may also define static member functions. A static member function has no this parameter. It may directly access the static members of its class but may not directly use the nonstatic members.

Advantages of Using Class static Members

There are three advantages to using static members rather than globals:

  1. The name of a static member is in the scope of the class, thereby avoiding name collisions with members of other classes or global objects.

  2. Encapsulation can be enforced. A static member can be a private member; a global object cannot.

  3. It is easy to see by reading the program that a static member is associated with a particular class. This visibility clarifies the programmer's intentions.

Defining static Members

Amember ismade static by prefixing the member declaration with the keyword static. The static members obey the normal public/private access rules.

As an example, consider a simple class intended to represent a bank account. Each account has a balance and an owner. Each account earns interest monthly, but the interest rate applied to each account is always the same. We could write this class as

      class Account {      public:          // interface functions here          void applyint() { amount += amount * interestRate; }          static double rate() { return interestRate; }          static void rate(double); // sets a new rate      private:          std::string owner;          double amount;          static double interestRate;          static double initRate();      }; 

Each object of this class has two data members: owner and amount. Objects do not have data members that correspond to static data members. Instead, there is a single interestRate object that is shared by all objects of type Account.

Using a Class static Member

A static member can be invoked directly from the class using the scope operator or indirectly through an object, reference, or pointer to an object of its class type.

      Account ac1;      Account *ac2 = &ac1;      // equivalent ways to call the static member rate function      double rate;      rate = ac1.rate();        // through an Account object or reference      rate = ac2->rate();       // through a pointer to an Account object      rate = Account::rate();   // directly from the class using the scope operator 

As with other members, a class member function can refer to a class static member without the use of the scope operator:

      class Account {      public:           // interface functions here           void applyint() { amount += amount * interestRate; }      }; 

Exercises Section 12.6

Exercise 12.36:

What is a static class member? What are the advantages of static members? How do they differ from ordinary members?

Exercise 12.37:

Write your own version of the Account class.


12.6.1. static Member Functions

Our Account class has two static member functions named rate, one of which was defined inside the class. When we define a static member outside the class, we do not respecify the static keyword. The keyword appears only with the declaration inside the class body:

      void Account::rate(double newRate)      {          interestRate = newRate;      } 

static Functions Have No this Pointer

A static member is part of its class but not part of any object. Hence, a static member function does not have a this pointer. Referring to this either explicitly or implicitly by using a nonstatic member is a compile-time error.

Because a static member is not part of any object, static member functions may not be declared as const. After all, declaring a member function as const is a promise not to modify the object of which the function is a member. Finally, static member functions may also not be declared as virtual. We'll learn about virtual functions in Section 15.2.4 (p. 566).

12.6.2. static Data Members

static data members can be declared to be of any type. They can be consts, references, arrays, class types, and so forth.

static data members must be defined (exactly once) outside the class body. Unlike ordinary data members, static members are not initialized through the class constructor(s) and instead should be initialized when they are defined.

Exercises Section 12.6.1

Exercise 12.38:

Define a class named Foo that has a single data member of type int. Give the class a constructor that takes an int value and initializes the data member from that value. Give it a function that returns the value of its data member.

Exercise 12.39:

Given the class Foo defined in the previous exercise, define another class Bar with two static data elements: one of type int and another of type Foo.

Exercise 12.40:

Using the classes from the previous two exercises, add a pair of static member functions to class Bar. The first static, named FooVal, should return the value of class Bar's static member of type Foo. The second member, named callsFooVal, should keep a count of how many times xval is called.


The best way to ensure that the object is defined exactly once is to put the definition of static data members in the same file that contains the definitions of the class noninline member functions.



static data members are defined in the same way that other class members and other variables are defined. The member is defined by naming its type followed by the fully qualified name of the member.

We might define interestRate as follows:

      // define and initialize static class member      double Account::interestRate = initRate(); 

This statement defines the static object named interestRate that is a member of class Account and has type double. Like other member definitions, the definition of a static member is in class scope once the member name is seen. As a result, we can use the static member function named initRate directly without qualification as the initializer for rate. Note that even though initRate is private, we can use this function to initialize interestRate. The definition of interestRate, like any other member definition, is in the scope of the class and hence has access to the private members of the class.

As with any class member, when we refer to a class static member outside the class body, we must specify the class in which the member is defined. The static keyword, however, is used only on the declaration inside the class body. Definitions are not labeled static.



Integral const static Members Are Special

Ordinarily, class static members, like ordinary data members, cannot be initialized in the class body. Instead, static data members are normally initialized when they are defined.

One exception to this rule is that a const static data member of integral type can be initialized within the class body as long as the initializer is a constant expression:

      class Account {      public:          static double rate() { return interestRate; }          static void rate(double);  // sets a new rate      private:          static const int period = 30; // interest posted every 30 days          double daily_tbl[period]; // ok: period is constant expression      }; 

A const static data member of integral type initialized with a constant value is a constant expression. As such, it can be used where a constant expression is required, such as to specify the dimension for the array member daily_tbl.

When a const static data member is initialized in the class body, the data member must still be defined outside the class definition.



When an initializer is provided inside the class, the definition of the member must not specify an initial value:

      // definition of static member with no initializer;      // the initial value is specified inside the class definition      const int Account::period; 

static Members Are Not Part of Class Objects

Ordinary members are part of each object of the given class. static members exist independently of any object and are not part of objects of the class type. Because static data members are not part of any object, they can be used in ways that would be illegal for nonstatic data members.

As an example, the type of a static data member can be the class type of which it is a member. A nonstatic data member is restricted to being declared as a pointer or a reference to an object of its class:

      class Bar {      public:          // ...      private:          static Bar mem1; // ok          Bar *mem2;       // ok          Bar mem3;        // error      }; 

Similarly, a static data member can be used as a default argument:

      class Screen {      public:          // bkground refers to the static member          // declared later in the class definition          Screen& clear(char = bkground);      private:          static const char bkground = '#';      }; 

A nonstatic data member may not be used as a default argument because its value cannot be used independently of the object of which it is a part. Using a nonstatic data member as a default argument provides no object from which to obtain the member's value and so is an error.

Exercises Section 12.6.2

Exercise 12.41:

Given the classes Foo and Bar that you wrote for the exercises to Section 12.6.1 (p. 470), initialize the static members of Foo. Initialize the int member to 20 and the Foo member to 0.

Exercise 12.42:

Which, if any, of the following static data member declarations and definitions are errors? Explain why.

      // example.h      class Example {      public:          static double rate = 6.5;          static const int vecSize = 20;          static vector<double> vec(vecSize);      };      // example.C      #include "example.h"      double Example::rate;      vector<double> Example::vec; 




C++ Primer
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2006
Pages: 223
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net