C Primer Plus (5th Edition)
2.8. Class Types
In C++ we define our own data types by defining a class. A class defines the data that an object of its type contains and the operations that can be executed by objects of that type. The library types string, istream, and ostream are all defined as classes. C++ support for classes is extensivein fact, defining classes is so important that we shall devote Parts III through V to describing C++ support for classes and operations using class types. In Chapter 1 we used the Sales_item type to solve our bookstore problem. We used objects of type Sales_item to keep track of sales data associated with a particular ISBN. In this section, we'll take a first look at how a simple class, such as Sales_item, might be defined. Class Design Starts with the Operations
Each class defines an interface and implementation. The interface consists of the operations that we expect code that uses the class to execute. The implementation typically includes the data needed by the class. The implementation also includes any functions needed to define the class but that are not intended for general use. When we define a class, we usually begin by defining its interfacethe operations that the class will provide. From those operations we can then determine what data the class will require to accomplish its tasks and whether it will need to define any functions to support the implementation. The operations our type will support are the operations we used in Chapter 1. These operations were outlined in Section 1.5.1 (p. 21):
We'll see how to define these operations in Chapters 7 and 14 after we learn how to define functions and operators. Even though we can't yet implement these functions, we can figure out what data they'll need by thinking a bit about what these operations must do. Our Sales_item class must
Looking at this list of tasks, we can see that we'll need an unsigned to keep track of how many books are sold and a double to keep track of the total revenue. From these data we can calculate the average sales price as total revenue divided by number sold. Because we also want to know which book we're reporting on, we'll also need a string to keep track of the ISBN. Defining the Sales_item Class
Evidently what we need is the ability to define a data type that will have these three data elements and the operations we used in Chapter 1. In C++, the way we define such a data type is to define a class: class Sales_item { public: // operations on Sales_item objects will go here private: std::string isbn; unsigned units_sold; double revenue; };
A class definition starts with the keyword class followed by an identifier that names the class. The body of the class appears inside curly braces. The close curly must be followed by a semicolon.
The class body, which can be empty, defines the data and operations that make up the type. The operations and data that are part of a class are referred to as its members. The operations are referred to as the member functions (Section 1.5.2, p. 24) and the data as data members. The class also may contain zero or more public or private access labels. An access label controls whether a member is accessible outside the class. Code that uses the class may access only the public members. When we define a class, we define a new type. The class name is the name of that type. By naming our class Sales_item we are saying that Sales_item is a new type and that programs may define variables of this type. Each class defines its own scope (Section 2.3.6, p. 54). That is, the names given to the data and operations inside the class body must be unique within the class but can reuse names defined outside the class. Class Data Members
The data members of a class are defined in somewhat the same way that normal variables are defined. We specify a type and give the member a name just as we do when defining a simple variable: std::string isbn; unsigned units_sold; double revenue; Our class has three data members: a member of type string named isbn, an unsigned member named units_sold, and a member of type double named revenue. The data members of a class define the contents of the objects of that class type. When we define objects of type Sales_item, those objects will contain a string, an unsigned, and a double. There is one crucially important difference between how we define variables and class data members: We ordinarily cannot initialize the members of a class as part of their definition. When we define the data members, we can only name them and say what types they have. Rather than initializing data members when they are defined inside the class definition, classes control initialization through special member functions called constructors (Section 2.3.3, p. 49). We will define the Sales_item constructors in Section 7.7.3 (p. 262). Access Labels
Access labels control whether code that uses the class may use a given member. Member functions of the class may use any member of their own class, regardless of the access level. The access labels, public and private, may appear multiple times in a class definition. A given label applies until the next access label is seen. The public section of a class defines members that can be accessed by any part of the program. Ordinarily we put the operations in the public section so that any code in the program may execute these operations. Code that is not part of the class does not have access to the private members. By making the Sales_item data members private, we ensure that code that operates on Sales_item objects cannot directly manipulate the data members. Programs, such as the one we wrote in Chapter 1, may not access the private members of the class. Objects of type Sales_item may execute the operations but not change the data directly. Using the struct Keyword
C++ supports a second keyword, struct, that can be used to define class types. The struct keyword is inherited from C. If we define a class using the class keyword, then any members defined before the first access label are implicitly private; ifwe usethe struct keyword, then those members are public. Whether we define a class using the class keyword or the struct keyword affects only the default initial access level. We could have defined our Sales_item equivalently by writing struct Sales_item { // no need for public label, members are public by default // operations on Sales_item objects private: std::string isbn; unsigned units_sold; double revenue; };
There are only two differences between this class definition and our initial class definition: Here we use the struct keyword, and we eliminate the use of public keyword immediately following the opening curly brace. Members of a struct are public, unless otherwise specified, so there is no need for the public label.
|