Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ For Dummies (2004) [eng].pdf
Скачиваний:
84
Добавлен:
16.08.2013
Размер:
8.09 Mб
Скачать

Chapter 19

Static Members: Can Fabric

Softener Help?

In This Chapter

How do I declare static member data?

What about static member functions?

Why can’t my static member function call my other member functions?

By default, data members are allocated on a “per object” basis. For exam­ ple, each person has his or her own name.

You can also declare a member to be shared by all objects of a class by declaring that member static. The term static applies to both data members and member functions, although the meaning is slightly different. This chap­ ter describes these differences, beginning with static data members.

Defining a Static Member

The programmer can make a data member common to all objects of the class by adding the keyword static to the declaration. Such members are called static data members (I would be a little upset if they were called something else).

Why you need static members

Most properties are properties of the object. Using the well-worn (one might say, threadbare) student example, properties such as name, ID number, and courses are specific to the individual student. However, all students share some properties — for example, the number of students currently enrolled, the highest grade of all students, or a pointer to the first student in a linked list.

252 Part III: Introduction to Classes

It’s easy enough to store this type of information in a common, ordinary, garden-variety global variable. For example, you could use a lowly int vari­ able to keep track of the number of Student objects. The problem with this solution is that global variables are outside the class. It’s like putting the volt­ age regulator for my microwave outside the enclosure. Sure, it could be done, and it would probably work — the only problem is that I wouldn’t be too happy if my dog got into the wires, and I had to peel him off the ceiling (the dog wouldn’t be thrilled about it, either).

If a class is going to be held responsible for its own state, objects such as global variables must be brought inside the class, just as the voltage regula­ tor must be inside the microwave lid, away from prying paws. This is the idea behind static members.

You may hear static members referred to as class members; this is because all objects in the class share them. By comparison, normal members are referred to as instance members, or object members, because each object receives its own copy of these members.

Using static members

A static data member is one that has been declared with the static storage class, as shown here:

class Student

{

public:

Student(char *pName = “no name”) : name(pName)

{

noOfStudents++;

}

~Student()

{

noOfStudents--;

}

static int noOfStudents; string name;

};

Student s1;

Student s2;

The data member noOfStudents is part of the class Student but is not part of either s1 or s2. That is, for every object of class Student, there is a separate name, but there is only one noOfStudents, which all Students must share.

Chapter 19: Static Members: Can Fabric Softener Help? 253

“Well then,” you ask, “if the space for noOfStudents is not allocated in any of the objects of class Student, where is it allocated?” The answer is, “It isn’t.” You have to specifically allocate space for it, as follows:

int Student::noOfStudents = 0;

This somewhat peculiar-looking syntax allocates space for the static data member and initializes it to zero. Static data members must be global — a static variable cannot be local to a function.

The name of the class is required for any member when it appears outside its class boundaries.

This business of allocating space manually is somewhat confusing until you consider that class definitions are designed to go into files that are included by multiple source code modules. C++ has to know in which of those .cpp source files to allocate space for the static variable. This is not a problem with non-static variables because space is allocated in each and every object created.

Referencing static data members

The access rules for static members are the same as the access rules for normal members. From within the class, static members are referenced like any other class member. Public static members can be referenced from out­ side the class, whereas well-protected static members can’t. Both types of reference are shown in the following code snippet:

class Student

{

public:

Student()

{

noOfStudents++; // reference from inside the class // ...other stuff...

}

static int noOfStudents;

// ...other stuff like before...

};

void fn(Student& s1, Student& s2)

{

// reference public static cout << “No of students “

<< s1.noOfStudents

// reference from outside

<< endl;

// of the class

}

 

254 Part III: Introduction to Classes

In fn(), noOfStudents is referenced using the object s1. But s1 and s2 share the same member noOfStudents. How did I know to choose s1? Why didn’t I use s2 instead? It doesn’t make any difference. You can reference a static member using any object of that class, as illustrated here:

// ...class defined the same as before...

void fn(Student& s1, Student& s2)

{

// the following produce identical results cout << “ Number of students “

<<s1.noOfStudents

<<endl;

cout << “ Number of students “

<<s2.noOfStudents

<<endl;

}

In fact, you don’t need an object at all. You can use the class name directly instead, if you prefer, as in the following:

// ...class defined the same as before...

void fn(Student& s1, Student& s2)

{

// the following produce identical results

cout << “Number of students “

<<Student::noOfStudents

<<endl;

}

If you do use an object name when accessing a static member, C++ uses only the declared class of the object.

This is a minor technicality, but in the interest of full disclosure: the object used to reference a static member is not evaluated even if it’s an expression. For example, consider the following case:

class Student

{

public:

static int noOfStudents; Student& nextStudent();

// ...other stuff the same...

};

void fn(Student& s)

{

cout << s.nextStudent().noOfStudents << “\n”

}

The member function nextStudent() is not actually called. All C++ needs to access noOfStudents is the return type, and it can get that without bothering