This creates a single constant called Months that is stored with other static variables rather than in an object. Thus, there is only one Months constant shared by all Bakery objects. Chapter 12 looks further into static class members. In C++98 you can use this technique only for declaring static constants with integral and enumeration values. Thus, C++98 doesn’t allow you to store a double constant this way. C++11 removes that restriction.

Scoped Enumerations (C++11)

Traditional enumerations have some problems. One is that enumerators from two different enum definitions can conflict. Suppose you were working on a project involving eggs and T-shirts. You might try something like this:

enum egg {Small, Medium, Large, Jumbo};

enum t_shirt {Small, Medium, Large, Xlarge};

This won’t fly because the egg Small and the t_shirt Small would both be in the same scope, and the names conflict. C++11 provides a new form of enumeration that avoids this problem by having class scope for its enumerators. The declarations for this form look like this:

enum class egg {Small, Medium, Large, Jumbo};

enum class t_shirt {Small, Medium, Large, Xlarge};

Alternatively, you can use the keyword struct instead of class. In either case, you now need to use the enum name to qualify the enumerator:

egg choice = egg::Large;        // the Large enumerator of the egg enum

t_shirt Floyd = t_shirt::Large; // the Large enumerator of the t_shirt enum

Now that the enumerators have class scope, enumerators from different enum definitions no longer have potential name conflicts, and your egg-and-T-shirt project can proceed.

C++11 also tightens up type security for scoped enumerations. Regular enumerations get converted to integer types automatically in some situations, such as assignment to an int variable or being used in a comparison expression, but scoped enumerations have no implicit conversions to integer types:

enum egg_old {Small, Medium, Large, Jumbo};        // unscoped

enum class t_shirt {Small, Medium, Large, Xlarge}; // scoped

egg_old one = Medium;                              // unscoped

t_shirt rolf = t_shirt::Large;                     // scoped

int king = one;      // implicit type conversion for unscoped

int ring = rolf;     // not allowed, no implicit type conversion

if (king < Jumbo)    // allowed

    std::cout << "Jumbo converted to int before comparison.\n";

if (king < t_shirt::Medium)   // not allowed

    std::cout << "Not allowed: < not defined for scoped enum.\n";

But you can do an explicit type conversion if you feel you have to:

int Frodo = int(t_shirt::Small); // Frodo set to 0

Enumerations are represented by some underlying integer type, and under C98 that choice was implementation-dependent. Thus, a structure containing an enumeration might be of different sizes on different systems. C++11 removes that dependency for scoped enumerations. By default, the underlying type for C++11 scoped enumerations is int. Furthermore, there’s a syntax for indicating a different choice:

// underlying type for pizza is short

enum class : short pizza {Small, Medium, Large, XLarge};

The : short specifies the underlying type to be short. The underlying type has to be an integer type. Under C++11, you also can use this syntax to indicate the underlying type for an unscoped enumeration, but if you don’t choose the type, the choice the compiler makes is implementation-dependent.

Abstract Data Types

The Stock class is pretty specific. Often, however, programmers define classes to represent more general concepts. For example, using classes is a good way to implement what computer scientists describe as abstract data types (ADTs). As the name suggests, an ADT describes a data type in a general fashion without bringing in language or implementation details. Consider, for example, the stack. By using the stack, you can store data so that data is always added to or deleted from the top of the stack. For example, C++ programs use a stack to manage automatic variables. As new automatic variables are generated, they are added to the top of the stack. When they expire, they are removed from the stack.

Let’s look at the properties of a stack in a general, abstract way. First, a stack holds several items. (That property makes it a container, an even more general abstraction.) Next, a stack is characterized by the operations you can perform on it:

• You can create an empty stack.

• You can add an item to the top of a stack (that is, you can push an item).

• You can remove an item from the top (that is, you can pop an item).

• You can check whether the stack is full.

• You can check whether the stack is empty.

You can match this description with a class declaration in which the public member functions provide an interface that represents the stack operations. The private data members take care of storing the stack data. The class concept is a nice match to the ADT approach.

Перейти на страницу:

Все книги серии Developer's Library

Похожие книги