12.6. static Class MembersIt 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 MembersThere are three advantages to using static members rather than globals:
Defining static MembersAmember 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 MemberA 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; }
};
12.6.1. static Member FunctionsOur 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 PointerA 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 Membersstatic 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.
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.
Integral const static Members Are SpecialOrdinarily, 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 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 ObjectsOrdinary 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.
![]() |