Team LiB
Previous Section Next Section

2.8. Class Types

2.8. 类类型

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++ 中,通过定义来自定义数据类型。类定义了该类型的对象包含的数据和该类型的对象可以执行的操作。标准库类型string、istream和ostream都定义成类。

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.

C++对类的支持非常丰富——事实上,定义类是如此重要,我们把第三第五部分全部用来描述 C++ 对类及类操作的支持。

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.

第一章中,我们使用 Sales_item 类型来解决书店问题。使用 Sales_item 类型的对象来记录对应于特定 ISBN 的销售数据。在这节中,我们先了解如何定义简单的类,如 Sales_item 类。

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):

我们将要定义的类型所支持的操作,就是我们在第一章中所用到的操作。这些操作如下(参见第 1.5.1 节):

  • The addition operator to add two Sales_items

    加法操作符,将两个 Sales_item 相加。

  • The input and output operators to read and write Sales_item objects

    输入和输出操作符,读和写 Sales_item 对象。

  • The assignment operator to assign one Sales_item object to another

    赋值操作符,把 Sales_item 对象赋给另一个 Sales_item 对象。

  • The same_isbn function to determine if two objects refer to the same book

    same_isbn 函数,检测两个对象是否指同一本书。

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

在学完怎样定义函数和操作符后,我们将会在第七章第十四章看到该怎样来定义这些操作。虽然现在不能实现这些函数,但通过思考这些操作必须要实现的功能,我们可以看出该类需要什么样的数据。Sales_item 类必须

  1. Keep track of how many copies of a particular book were sold

    记录特定书的销售册数。

  2. Report the total revenue for that book

    记录该书的总销售收入。

  3. Calculate the average sales price for that book

    计算该书的平均售价。

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.

查看以上所列出的任务,可以知道需要一个 unsigned 类型的对象来记录书的销售册数,一个 double 类型的对象来记录总销售收入,然后可以用总收入除以销售册数计算出平均售价。因为我们还想知道是在记录哪本书,所以还需要定义一个 string 类型的对象来记录书的 ISBN。

Defining the Sales_item Class

定义 Sales_item

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:

很明显,我们需要能够定义一种包含这三个数据元素和在第一章所用到的操作的数据类型。在 C++ 语言中,定义这种数据类型的方法就是定义类:

     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.

类定义以关键字 class 开始,其后是该类的名字标识符。类体位于花括号里面。花括号后面必须要跟一个分号。

It is a common mistake among new programmers to forget the semicolon at the end of a class definition.

编程新手经常会忘记类定义后面的分号,这是个很普遍的错误!

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.

类体可以为空。类体定义了组成该类型的数据和操作。这些操作和数据是类的一部分,也称为类的成员。操作称为成员函数(第 1.5.2 节),而数据则称为数据成员

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.

类也可以包含 0 个到多个 privatepublic 访问标号。访问标号控制类的成员在类外部是否可访问。使用该类的代码可能只能访问 public 成员。

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.

定义了类,也就定义了一种新的类型。类名就是该类型的名字。通过命名 Sales_item 类,表示 Sales_item 是一种新的类型,而且程序也可以定义该类型的变量。

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.

每一个类都定义了它自己的作用域(第 2.3.6 节)。也就是说,数据和操作的名字在类的内部必须唯一,但可以重用定义在类外的名字。

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.

这个类含有三个数据成员:一个名为 isbnstring 类型成员,一个名为 units_soldunsigned 类型成员,一个名为 revenuedouble 类型成员。类的数据成员定义了该类类型对象的内容。当定义 Sales_item 类型的对象时,这些对象将包含一个 string 型变量,一个 unsigned 型变量和一个 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).

定义变量和定义数据成员存在非常重要的区别:一般不能把类成员的初始化作为其定义的一部分。当定义数据成员时,只能指定该数据成员的名字和类型。类不是在类定义里定义数据成员时初始化数据成员,而是通过称为构造函数(第 2.3.3 节)的特殊成员函数控制初始化。我们将在第 7.7.3 节定义 Sales_item 的构造函数。

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.

访问标号负责控制使用该类的代码是否可以使用给定的成员。类的成员函数可以使用类的任何成员,而不管其访问级别。访问标号 publicprivate 可以多次出现在类定义中。给定的访问标号应用到下一个访问标号出现时为止。

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.

类中public 部分定义的成员在程序的任何部分都可以访问。一般把操作放在 public 部分,这样程序的任何代码都可以执行这些操作。

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.

不是类的组成部分的代码不能访问 private 成员。通过设定 Sales_item 的数据成员为 private,可以保证对 Sales_item 对象进行操作的代码不能直接操纵其数据成员。就像我们在第一章编写的程序那样,程序不能访问类中的 private 成员。Sales_item 类型的对象可以执行那些操作,但是不能直接修改这些数据。

Using the struct Keyword

使用 struct 关键字

C++ supports a second keyword, struct, that can be used to define class types. The struct keyword is inherited from C.

C++ 支持另一个关键字 struct,它也可以定义类类型。struct 关键字是从 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.

如果使用 class 关键字来定义类,那么定义在第一个访问标号前的任何成员都隐式指定为 private;如果使用 struct 关键字,那么这些成员都是 public。使用 class 还是 struct 关键字来定义类,仅仅影响默认的初始访问级别。

We could have defined our Sales_item equivalently by writing

可以等效地定义 Sales_item 类为:

     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.

本例的类定义和前面的类定义只有两个区别:这里使用了关键字 struct,并且没有在花括号后使用关键字 publicstruct 的成员都是 public,除非有其他特殊的声明,所以就没有必要添加 public 标号。

The only difference between a class defined with the class keyword or the struct keyword is the default access level: By default, members in a struct are public; those in a class are private.

classstruct 关键字定义类的唯一差别在于默认访问级别:默认情况下,struct 的成员为 public,而 class 的成员为 private

Exercises Section 2.8

Exercise 2.28:

Compile the following program to determine whether your compiler warns about a missing semicolon after a class definition:

编译以下程序,确定你的编译器是否会警告遗漏了类定义后面的分号。

     class Foo  {
           // empty
     } // Note: no semicolon
     int main()
     {
         return 0;
     }

If the diagnostic is confusing, remember the message for future reference.

如果编译器的诊断结果难以理解,记住这些信息以备后用。

Exercise 2.29:

Distinguish between the public and private sections of a class.

区分类中的 public 部分和 private 部分。

Exercise 2.30:

Define the data members of classes to represent the following types:

定义表示下列类型的类的数据成员:

     (a) a phone number            (b) an address
     (c) an employee or a company  (d) a student at a university


Team LiB
Previous Section Next Section