《毕业论文5000字英文文献翻译(c++)》由会员分享,可在线阅读,更多相关《毕业论文5000字英文文献翻译(c++)(12页珍藏版)》请在金锄头文库上搜索。
1、. 1 / 12 英文翻译 英语原文: . Introducing Classes The only remaining feature we need to understand before solving our bookstore problem is how to write a data structure to represent our transaction data. In C+ we define our own data structure by defining a class. The class mechanism is one of the most impor
2、tant features in C+. In fact, a primary focus of the design of C+ is to make it possible to define class types that behave as naturally as the built-in types themselves. The library types that weve seen already, such as istream and ostream, are all defined as classesthat is,they are not strictly spe
3、aking part of the language. Complete understanding of the class mechanism requires mastering a lot of information. Fortunately, it is possible to use a class that someone else has written without knowing how to define a class ourselves. In this section, well describe a simple class that we canuse in
4、 solving our bookstore problem. Well implement this class in the subsequent chapters as we learn more about types,expressions, statements, and functionsall of which are used in defining classes. To use a class we need to know three things: What is its name? Where is it defined? What operations does
5、it support? For our bookstore problem, well assume that the class is named Sales_item and that it is defined in a header named Sales_item.h. The Sales_item Class The purpose of the Sales_item class is to store an ISBN and keep track of the number of copies sold, the revenue, and average sales price
6、for that book. How these data are stored or computed is not our concern. To use a class, we need not know anything about how it is implemented. Instead, what we need to know is what operations the class provides. As weve seen, when we use library facilities such as IO, we must include the associated
7、 headers. Similarly, for our own classes, we must make the definitions associated with the class available to the compiler. We do so in much the same way. Typically, we put the class definition into a file. Any program that wants to use our class must include that file. Conventionally, class types a
8、re stored in a file with a name that, like the name of a program source file, has two parts: a file name and a file suffix. Usually the file name is the same as the class defined in the header. The suffix usually is .h, but some programmers use .H, .hpp, or .hxx. Compilers usually arent picky about
9、header file names, but IDEs sometimes are. Well assume that our class is defined in a file named Sales_item.h. Operations on Sales_item Objects . 2 / 12 Every class defines a type. The type name is the same as the name of the class. Hence, our Sales_item class defines a type named Sales_item. As wit
10、h the built-in types, we can define a variable of a class type. When we write Sales_item item we are saying that item is an object of type Sales_item. We often contract the phrase an object of type Sales_item toaSales_ item object or even more simply to a Sales_item. In addition to being able to def
11、ine variables of type Sales_item, we can perform the following operations on Sales_item objects: Use the addition operator, +, to add two Sales_items, Use the input operator, to write a Sales_item object, Use the assignment operator, =, to assign one Sales_item object to another, Call the same_isbn
12、function to determine if two Sales_items refer to the same book. Classes are central to most C+ programs: Classes let us define our own types that are customizedfor the problems we need to solve, resulting in applications that are easier to write and understand.Well-designed class types can be as ea
13、sy to use as the built-in types. A class defines data and function members: The data members store the state associated with objectsof the class type, and the functions perform operations that give meaning to the data. Classeslet us separate implementation and interface. The interface specifies the
14、operations that the classsupports. Only the implementor of the class need know or care about the details of the implementation. This separation reduces the bookkeeping aspects that make programming tedious anderror-prone. Class types often are referred to as abstract data types. An abstract data typ
15、e treats the data and operations on that state as a single unit. We can think abstractly about what the classd oes, rather than always having to be aware of how the class operates. Abstract data types arefundamental to both object-oriented and generic programming. Data abstraction is a programming t
16、echnique that relies on the separation of interfaceand implementation. The class designer must worry about how a class is implemented, but programmersthat use the class need not know about these details. Instead, programmers who use a type need to know only the types interface; they can think abstra
17、ctly about what the type does rather than concretely about how the type works. Encapsulation is a term that describes the technique of combining lower-level elements to forma new, higher-level entity. A function is one form of encapsulation: The detailed actions performedby the function are encapsul
18、ated in the larger entity that is the function itself. Encapsulated elements hide the details of their implementationwe may call a function but have no access to the statements that it executes. In the same way, a class is an encapsulated entity: It represents an aggregation of several members, and
19、most class types hide the members that implement the type. If we think about the library vector type, it is an example of both data abstraction and . 3 / 12 encapsulation. It is abstract in that to use it, we think about its interfaceabout the operations that it can perform. It is encapsulated becau
20、se we have no access to the details of how the type is representated nor to any of its implementation artifacts. An array, on the other hand, is similar in concept to a vector but is neither abstract nor encapsulated. We manipulate an array directly by accessing the memory in which the array is stor
21、ed. Not all types need to be abstract. The library pair class is a good example of a useful, well-designed class that is concrete rather than abstract. A concrete class is a class that exposes, rather than hides, its implementation. Some classes, such as pair, really have no abstract interface. The
22、pair type exists to bundle two data members into a single object. There is no need or advantage to hiding the data members. Hiding the members in a class like pair would only complicate the use of the type. Even so, such types often have member functions. In particular, it is a good idea for any cla
23、ss that has data members of built-in or compound type to define constructor to initialize those members. The user of the class could initialize or assign to the data members but it is less error-prone for the class to do so. Programmers tend to think about the people who will run their applications
24、as users. Applicationsare designed for and evolve in response to feedback from those who ultimately use the applications. Classes are thought of in a similar way: A class designer designs and implements a class for users of that class. In this case, the user is a programmer, not the ultimate user of
25、 the application. Authors of successful applications do a good job of understanding and implementing the needs ofthe applications users. Similarly, well-designed, useful classes are designed with a close attention to the needs of the users of the class. In another way, the division between class des
26、igner and class user reflects the division betweenusers of an application and the designers and implementors of the application. Users care only if the application meets their needs in a cost-effective way. Similarly, users of a class care only about its interface. Good class designers define a clas
27、s interface that is intuitive and easy to use. Users care about the implementation only in so far as the implementation affects their use of the class. If the implementation is too slow or puts burdens on users of the class, then the users must care. In well-designed classes, only the class designer
28、 worries about the implementation. In simple applications, the user of a class and the designer of the class might be one and the same person. Even in such cases, it is useful to keep the roles distinct. When designing the interface to a class, the class designer should think about how easy it will
29、be to use the class. When using the class, the designer shouldnt think about how the class works. When referring to a user, the context makes it clear which kind of user is meant. If we speak of user code or the user of the Sales_item class, we mean a programmer who . 4 / 12 is using a class in writ
30、ing an application. If we speak of the user of the bookstore application, we mean the manager of the store who is running the application. Data abstraction and encapsulation provide two important advantages: 1.Class internals are protected from inadvertent user-level errors, which might corrupt the
31、state of the object. 2.The class implementation may evolve over time in response to changing requirements or bug reports without requiring change in user-level code. By defining data members only in the private section of the class, the class author is free to make changes in the data. If the implem
32、entation changes, only the class code needs to be examined to see what affect the change may have. If data are public, then any function that directly accesses the data members of the old representation might be broken. It would be necessary to locate and rewrite all those portions of code that reli
33、ed on the old pesentation before the program could be used again. Similarly, if the internal state of the class is private, then changes to the member data can happen in only a limited number of places. The data is protected from mistakes that users might introduce. If there is a bug that corrupts t
34、he objects state, the places to look for the bug are localized: When data are private, only a member function could be responsible for the error. The search for the mistake is limited, greatly easing the problems of maintenance and program correctness. If the data are private and if the interface to
35、 the member functions does not change, then user functions that manipulate class objects require no change. Because changing a class definition in a header file effectively changes the text of every source file that includes that header, code that uses a class must be recompiled when the class chang
36、es. Classes are the most fundamental feature in C+. Classes let us define new types that are tailored to our own applications, making our programs shorter and easier to modify. Data abstractionthe ability to define both data and function membersand encapsulationthe ability to protect class members f
37、rom general accessare fundamental to classes. Member functions define the interface to the class. We encapsulate the class by making the data and functions used by the implementation of a class private. Classes may define constructors, which are special member functions that control how objects of t
38、he class are initialized. Constructors may be verloaded. Every constructor should initialize every data member. Constructors should use a constructor initializer list to initialize the data members. Initializer lists are lists of namevalue pairs where the name is a member and the value is an initial
39、 value for that member. Classes may grant access to their nonpublic members to other classes or functions. A class grants access by making the class or function a friend. Classes may also define mutable or static members. A mutable member is a data member that is never const; its value may be change
40、d inside a const member function. A . 5 / 12 static member can be either function or data; static members exist independently of the objects of the class type. Copy Control Each type, whether a built-in or class type, defines the meaning of a set of operations on objects of that type. We can add two
41、 int values, run size on a vector, and so on. These operations define what can be done with objects of the given type. Each type also defines what happens when objects of the type are created. Initialization of objects of class type is defined by constructors. Types also control what happens when ob
42、jects of the type are copied, assigned, or destroyed. Classes control these actions through special member functions: the copy constructor, the assignment operator, and the destructor. This chapter covers these operations. When we define a new type, we specifyexplicitly or implicitlywhat happens whe
43、n objects of that type are copied, assigned, and destroyed. We do so by defining special members: the copy constructor, the assignment operator, and the destructor. If we do not explicitly define the copy constructor or the assignment operator, the compiler will define them for us. The copy construc
44、tor is a special constructor that has a single parameter that is a reference to the class type. The copy constructor is used explicitly when we define a new object and initialize it from an object of the same type. It is used implicitly when we pass or return objects of that type to or from function
45、s. Collectively, the copy constructor, assignment operator, and destructor are referred to as copy control. The compiler automatically implements these operations, but the class may define its own versions. Copy control is an essential part of defining any C+ class. Programmers new to C+ are often c
46、onfused by having to define what happens when objects are copied, assigned, or destroyed. This confusion is compounded because if we do not explicitly define these operations, the compiler defines them for usalthough they might not behave as we intend. Often the compiler-synthesized copy-control fun
47、ctions are finethey do exactly the work that needs to be done. But for some classes, relying on the default definitions leads to disaster. Frequently,the most difficult part of implementing the copy-control operations is recognizing when we need to override the default versions. One especially commo
48、n case that requires the class to define its own the copy-control members is if the class has a pointer member. The Copy Constructor The constructor that takes a single parameter that is a reference to an object of the class type itself is called the copy constructor. Like the default constructor, t
49、he copy constructor can be implicitly invoked by the compiler. The copy constructor is used to: . 6 / 12 1.Explicitly or implicitly initialize one object from another of the same type; 2.Copy an object to pass it as an argument to a function; 3.Copy an object to return it from a function; 4.Initiali
50、ze the elements in a sequential container; 5.Initialize elements in an array from a list of element initializers. Forms of Object Definition Recall that C+ supports two forms of initialization : direct and copy.Copy-initialization uses the = symbol, and direct-initialization places the initializer i
51、n parentheses. The copy and direct forms of initialization, when applied to objects of class type, are subtly different. Direct-initialization directly invokes the constructor matched by the arguments. Copy-initialization always involves the copy constructor. Copy-initialization first uses the indic
52、ated constructor to create a temporary object . It then uses the copy constructor to copy that temporary into the one we are creating: string null_book = 9-999-99999-9; / copy-initialization string dots; / direct-initialization string empty_copy = string; / copy-initialization string empty_direct; /
53、 direct-initialization For objects of class type, copy-initialization can be used only when specifying a single argument or when we explicitly build a temporary object to copy. When dots is created, the string constructor that takes a count and a character is called and directly initializes the memb
54、ers in dots. To create null_book, the compiler first creates a temporary by invoking the string constructor that takes a C-style character string parameter. The compiler then uses the string copy constructor to initialize null_book as a copy of that temporary. The initialization of empty_copy and em
55、pty_direct both call the string default constructor. In the first case, the default constructor creates a temporary object, which is then used by the copy constructor to initialize empty_copy. In the second case, the default constructor is run directly on empty_direct. The copy form of initializatio
56、n is primarily supported for compatibility with C usage. When it can do so, the compiler is permitted to skip the copy constructor and create the object directly. Usually the difference between direct- or copy-initialization is at most a matter of low-level optimization. However, for types that do n
57、ot support copying, or when using a constructor that is nonexplicit the distinction can be essential: ifstream file1; / ok: direct initialization ifstream file2 = filename; / error: copy constructor is private / This initialization is okay only if / the Sales_item constructor is not explicit . 7 / 1
58、2 Sales_item item = string; The initialization of file1 is fine. The ifstream class defines a constructor that can be called with a C-style string. That constructor is used to initialize file1. The seemingly equivalent initialization of file2 uses copy-initialization. That definition is not okay. We
59、 cannot copy objects of the IO types , so we cannot use copy-initialization on objects of these types. Whether the initialization of item is okay depends on which version of our Sales_item class we are using. Some versions define the constructor that takes a string as explicit. If the constructor is
60、 explicit, then the initialization fails. If the constructor is not explicit, then the initialization is fine. If a class does not define one or more of these operations, the compiler will define them automatically. The synthesized operations perform memberwise initialization, assignment, or destruc
61、tion: Taking each member in turn, the synthesized operation does whatever is appropriate to the members type to copy, assign, or destroy that member. If the member is a class type, the synthesized operation calls the corresponding operation for that class . If the member is a built-in type or a poin
62、ter, the member is copied or assigned directly; the destructor does nothing to destroy members of built-in or pointer type. If the member is an array, the elements in the array are copied, assigned, or destroyed in a manner appropriate to the element type. 中文译文 类的简介 解决书店问题之前,还需要弄明白如何编写数据结构来表示交易数据.C+
63、 中我们通过定义类来定义自己的数据结构.类机制是 C+ 中最重要的特征之一.事实上,C+ 设计的主要焦点就是使所定义的类类型的行为可以像内置类型一样自然.我们前面已看到的像 istream 和 ostream 这样的库类型,都是定义为类的,也就是说,它们严格说来不是语言的一部分. 完全理解类机制需要掌握很多内容.所幸我们可以使用他人写的类而无需掌握如何定义自己的类.在这一节,我们将描述一个用于解决书店问题的简单类.当我们学习了更多关于类型、 表达式、 语句和函数的知识 所有这些在类定义中都将用到 后,将会在后面的章节实现这个类. 使用类时我们需要回答三个问题: 类的名字是什么? 它在哪里定义?
64、 它支持什么操作? 对 于 书 店 问 题 , 我 们 假 定 类 命名为 Sales_item 且 类定义在 命名 为 Sales_item.h 的头文件中. Sales_item 类 . 8 / 12 Sales_item 类的目的是存储 ISBN 并保存该书的销售册数、 销售收入和平均售价.我们不关心如何存储或计算这些数据.使用类时我们不需要知道这个类是怎样实现的,相反,我们需要知道的是该类提供什么操作. 正如我们所看到的,使用像 IO 一样的库工具,必须包含相关的头文件.类似地,对于自定义的类,必须使得编译器可以访问和类相关的定义.这几乎可以采用同样的方式.一般来说,我们将类定义放入一
65、个文件中,要使用该类的任何程序都必须包含这个文件. 依据惯例,类类型存储在一个文件中,其文件名如同程序的源文件名一样,由文件名和文件后缀两部分组成.通常文件名和定义在头文件中的类名是一样的.通常后缀是 .h,但也有一些程序员用 .H、.hpp 或 .hxx.编译器通常并不挑剔头文件名,但 IDE 有时会.假设我们的类定义在名为 Sale_item.h 的文件中. Sales_item 对象上的操作 每个类定义一种类型,类型名与类名相同.因此,我们的 Sales_item 类定义了一种命名为 Sales_item 的类型.像使用内置类型一样,可以定义类类型的变量.当写下 Sales_item i
66、tem,就表示 item 是类型 Sales_item 的一个对象.通常将类型 Sales_item 的一个对象简称为一个 Sales_item 对象,或者更简单地简称为一个 Sales_item. 除了可以定义 Sales_item 类型的变量,我们还可以执行 Sales_item 对象的以下操作: 使用加法操作符,+,将两个 Sales_item 相加; 使用输入操作符,来输出一个 Sales_item 对象; 使用赋值操作符,=,将一个 Sales_item 对象赋值给另一个 Sales_item 对象; 调用 same_isbn 函数确定两个 Sales_item 是否指同一本书. 在
67、大多数 C+ 程序中,类都是至关重要的:我们能够使用类来定义为要解决的问题定制的数据类型,从而得到更加易于编写和理解的应用程序.设计良好的类类型可以像内置类型一样容易使用. 类定义了数据成员和函数成员:数据成员用于存储与该类类型的对象相关联的状态,而函数成员则负责执行赋予数据意义的操作.通过类我们能够将实现和接口分离,用接口指定类所支持的操作,而实现的细节只需类的实现者了解或关心.这种分离可以减少使编程冗长乏味和容易出错的那些繁琐工作. 类类型常被称为抽象数据类型abstract data types.抽象数据类型将数据即状态 和作用于状态的操作视为一个单元.我们可以抽象地考虑类该做什么,而无
68、须知道何去完成这些操作.抽象数据类型是面向对象编程和泛型编程的基础. 数据抽象是一种依赖于接口和实现分离的编程 和设计 技术.类设计者必须关心类是如何实现的,但使用该类的程序员不必了解这些细节.相反,使用一个类型的程序员仅需了解类型的接口,他们可以抽象地考虑该类型做什么,而不必具体地考虑该类型如何工作. . 9 / 12 封装是一项低层次的元素组合起来的形成新的、 高层次实体珠技术.函数是封装的一种形式:函数所执行的细节行为被封装在函数本身这个更大的实体中.被封装的元素隐藏了它们的实现细节可以调用一个函数但不能访问它所执行的语句.同样地,类也是一个封装的实体:它代表若干成员的聚焦,大多数良好设
69、计的类类型隐藏了实现该类型的成员. 标准库类型 vector 同时具备数据抽象和封装的特性.在使用方面它是抽象的,只需考虑它的接口,即它能执行的操作.它又是封装的,因为我们既无法了解该类型如何表示的细节,也无法访问其任意的实现制品.另一方面,数组在概念上类似于 vector, 但既不是抽象的,也不是封装的.可以通过访问存放数组的内存来直接操纵数组. 并非所有类型都必须是抽象的.标准库中的 pair 类就是一个实用的、设计良好的具体类而不是抽象类.具体类会暴露而非隐藏其实现细节. 一些类,例如 pair,确实没有抽象接口.pair 类型只是将两个数据成员捆绑成单个对象.在这种情况下,隐藏数据成员
70、没有必要也没有明显的好处.在像 pair 这样的类中隐藏数据成员只会造成类型使用的复杂化. 尽管如此,这样的类型通常还是有成员函数.特别地,如果类具有内置类型或复合类型数据成员,那么定义构造函数来初始化这些成员就是一个好主意.类的使用都也可以初始化或赋值数据成员,但由类来做更不易出错. 程序员经常会将运行应用程序的人看作用户.应用程序为最终使用它的用户而设计,并响应用户的反馈而完善.类也类似:类的设计者为类的用户设计并实现类.在这种情况下,用户是程序员,而不是应用程序的最终用户. 成功的应用程序的创建者会很好地理解和实现用户的需求.同样地,良好设计的、实用的类,其设计也要贴近类用户的需求 .
71、另一方面,类的设计者与实现者之间的区别,也反映了应用程序的用户与设计和实现者之间的区分.用户只关心应用程序能否以合理的费用满足他们的需求.同样地,类的使用者只关心它的接口.好的类设计者会定义直观和易用的类接口,而使用者只关心类中影响他们使用的部分实现.如果类的实现速度太慢或给类的使用者加上负担,则必然引起使用者的关注.在良好设计的类中,只有类的设计者会关心实现. 在简单的应用程序中,类的使用者和设计者也许是同一个人.即使在这种情况下,保持角色区分也是有益的.设计类的接口时,设计者应该考虑的是如何方便类的使用;使用类的时候,设计者就不应该考虑类如何工作. 提到用户时,应该由上下文清楚地标明所指的
72、是哪类用户.如果提到用户代码或 Sales_item 类的用户,指的就是使用类编写应用程序的程序员.如果提到书店应用程序的用户,那么指的是运行应用程序的书店管理人员. 数据抽象和封装提供了两个重要优点: 1.避免类内部出现无意的、可能破坏对象状态的用户级错误. 2.随时间推移可以根据需求改变或缺陷bug报告来完美类实现,而无须改变用户级代码. 仅在类的私有部分定义数据成员,类的设计者就可以自由地修改数据.如果实现. 10 / 12 改变了,那么只需检查类代码来了解此变化可能造成的影响.如果数据为仅有的,则任何直接访问原有数据成员的函数都可能遭到破坏.在程序可重新使用之前,有必要定位和重写依赖原
73、有表示的那部分代码. 同样地,如果类的内部状态是私有的,则数据成员的改变只可能在有限的地方发生.避免数据中出现用户可能引入的错误.如果有缺陷会破坏对象的状态,就在局部位置搜寻缺陷: 如果数据是私有的,那么只有成员函数可能对该错误负责.对错误的搜寻是有限的,从而大大方便了程序的维护和修正. 如果数据是私有的并且没有改变成员函数的接口,则操纵类对象的用户函数无须改变. 改变头文件中的类定义可有效地改变包含该头文件的每个源文件的程序文本,所以,当类发生改变时,使用该类的代码必须重新编译 . 类是 C+ 中最基本的特征,允许定义新的类型以适应应用程序的需要,同时使程序更短且更易于修改. 数据抽象是指定
74、义数据和函数成员的能力,而封装是指从常规访问中保护类成员的能力,它们都是类的基础.成员函数定义类的接口.通过将类的实现所用到的数据和函数设置为 private 来封装类. 类可以定义构造函数,它们是特殊的成员函数,控制如何初始化类的对象.可以重载构造函数.每个构造函数就初始化每个数据成员.初始化列表包含的是名值对,其中的名是一个成员,而值则是该成员的初始值. 类可以将对其非 public 成员的访问权授予其他类或函数,并通过将其他的类或函数设为友元来授予其访问权 . 类也可以定义 mutable 或 static 成员.mutable 成员永远都不能为 const;它的值可以在 const 成
75、员函数中修改.static 成员可以是函数或数据,独立于类类型的对象而存在. 拷贝控制 每种类型,无论是内置类型还是类类型,都对该类型对象的一组可能为空的操作的含义进行了定义.比如,我们可以将两个 int 值相加,运行 vector 对象的 size 操作,等等.这些操作定义了用给定类型的对象可以完成什么任务. 每种类型还定义了创建该类型的对象时会发生什么构造函数定义了该类类型对象的初始化.类型还能控制复制、赋值或撤销该类型的对象时会发生什么类通过特殊的成员函数:复制构造函数、赋值操作符和析构函数来控制这些行为.本章将介绍这些操作. 当定义一个新类型的时候,需要显式或隐式地指定复制、 赋值和撤
76、销该类型的对象时会发生什么这是通过定义特殊成员: 复制构造函数、 赋值操作符和析构函数来达到的.如果没有显式定义复制构造函数或赋值操作符,编译器通常会为我们定义. 拷贝构造函数是一种特殊构造函数,具有单个形参,该形参常用 const 修饰是对该类类型的引用.当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数.当将该类型的对象传递给函数或函数返回该类型的对象时 ,. 11 / 12 将隐式使用复制构造函数. 复制构造函数、 赋值操作符和析构函数总称为复制控制.编译器自动实现这些操作,但类也可以定义自己的版本. 复制控制是定义任意 C+ 类必不可少的部分.初学 C+ 的程
77、序员常对必须定义在复制、 赋值或撤销对象时发生什么感到困惑.因为如果我们没有显式定义这些操作,编译器将为我们定义它们尽管它们也许不像我们期望的那样工作,这往往使初学者更加困惑. 通常,编译器合成的复制控制函数是非常精练的它们只做必需的工作.但对某些类而言,依赖于默认定义会导致灾难.实现复制控制操作最困难的部分,往往在于识别何时需要覆盖默认版本.有一种特别常见的情况需要类定义自己的复制控制成员的:类具有指针成员. 拷贝构造函数 只有单个形参,而且该形参是对本类类型对象的引用常用 const 修饰,这样的构造函数称为复制构造函数.与默认构造函数一样,复制构造函数可由编译器隐式调用.复制构造函数可用
78、于: 1.根据另一个同类型的对象显式或隐式初始化一个对象 . 2.复制一个对象,将它作为实参传给一个函数. 3.从函数返回时复制一个对象. 4.初始化顺序容器中的元素. 5.根据元素初始化式列表初始化数组元素. 对象的定义形式 回忆一下,C+ 支持两种初始化形式第 节 :直接初始化和复制初始化.复制初始化使用 = 符号,而直接初始化将初始化式放在圆括号中. 当用于类类型对象时,初始化的复制形式和直接形式有所不同: 直接初始化直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数.复制初始化首先使用指定构造函数创建一个临时对象第 节,然后用复制构造函数将那个临时对象复制到正在创建的对象:
79、string null_book = 9-999-99999-9; / copy-initialization string dots; / direct-initialization string empty_copy = string; / copy-initialization string empty_direct; / direct-initialization 对于类类型对象,只有指定单个实参或显式创建一个临时对象用于复制时,才使用复制初始化. 创建 dots 时,调用参数为一个数量和一个字符的 string 构造函数并直接初始化 dots 的成员.创建 null_book 时,编
80、译器首先调用接受一个 C 风格字符串形参的 string 构造函数,创建一个临时对象,然后,编译器使用 string 复制构造函数将 null_book 初始化为那个临时对象的副本. empty_copy 和 empty_direct 的初始化都调用默认构造函数.对前者初始化时,默认构造函数函数创建一个临时对象,然后复制构造函数用该对象初始化 empty_copy.对后者初始化时,直接运行 empty_direct 的默认构造函数. . 12 / 12 支持初始化的复制形式主要是为了与 C 的用法兼容.当情况许可时,可以允许编译器跳过复制构造函数直接创建对象,但编译器没有义务这样做. 通常直接
81、初始化和复制初始化仅在低级别上存在差异.然而,对于不支持复制的类型,或者使用非 explicit 构造函数第 节的进修,它们有本质区别: ifstream file1; / ok: direct initialization ifstream file2 = filename; / error: copy constructor is private / This initialization is okay only if / the Sales_item constructor is not explicit Sales_item item = string; file1 的初始化是正确的
82、.ifstream 类定义了一个可用 C 风格字符串调用的构造函数,使用该构造函数初始化 file1. 看上去等效的 file2 初始化使用复制初始化,但该定义不正确.由于不能复制 IO 类型的对象第 8.1 节,所以不能对那些类型的对象使用复制初始化 . item 的初始化是否正确,取决于正在使用哪个版本的 Sales_item 类.某些版本将参数为一个 string 的构造函数定义为 explicit.如果构造函数是显式的,则初始化失败;如果构造函数不是显式的,则初始化成功. 如果类没有定义这些操作中的一个或多个,编译器将自动定义它们.合成操作执行逐个成员初始化、赋值或撤销:合成操作依次取得每个成员,根据成员类型进行成员的复制、赋值或撤销.如果成员为类类型的,合成操作调用该类的相应操作即,复制构造函数调用成员的复制构造函数,析构函数调用成员的析构函数,等等.如果成员为内置类型或指针,则直接复制或赋值,析构函数对撤销内置类型或指针类型的成员没有影响.如果成员为数组,则根据元素类型以适当方式复制、 赋值或撤销数组中的元素.