📄 07章 类与数据抽象(二).txt
字号:
42 Time::Time( int hr, int min, int sec )
43 { setTime( hr, min, sec ); }
45 // Set the values of hour, minute, and second.
46 Time &Time::setTime{ int h, int m, int s )
47 {
48 setHour( h );
49 setMinute( m );
50 setSecond( s );
51 return *this; // enables CaScading
52 }
53
54 // Set the hour value
55 Time &Time::setHour( int h )
56 {
57 hour = ( h >= 0 && h < 24 ) ? h : 0;
59 return *this; // enables cascading
60 }
62 // Set the minute value
63 Time &Time::setMinute( int m )
64 {
68 minute = ( m >= 0 && m < 60 ) ? m : 0;
67 return *this; // enables cascading
68 }
70 // Set the second value
71 Time &Time::setSecond( int s )
72 {
73 second = ( s >= 0 && s < 60 ) ? s : 0;
74
75 return *this; // enables cascading
76 }
77
78 // Get the hour value
79 int Time::getHour() const { return hour;}
80
81 // Get the minute value
82 int Time::getMinute() const { return minute; }
83
84 // Get the second value
85 int Time::getSecond() const {eturn second;}
86
87 // Display military format time: HH:MM:
88 void Time::printMilitary() const
89 {
90 cout << (hour < 10 ? "0": "") << hour <<":"
91 << ( minute < 10 ? "0": "" ) << minute;
92 }
93
94 // Display standard format time: HH:MM:SS AM (or PM)
95 void Time::printStandard() const
96 {
97 cout << ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 )
98 << ":" << ( minute < 10 ? "0" : "" ) << minute
99 << ":" << ( second < 10 ? "0" : "" ) << second
100 << ( hour < 12 ? "AM" : "PM" );
101 }
102 // Fig. 7.8: fig07_08.cpp
103 // cascading member function calls together
104 // with the this pointer
105 #include <iostream.h>
106 #include "time6.h"
107
108 int main()
109 {
110 Time t;
111
112 t.setMour( 18 ).setMinute( 30 ).setSecond( 22 );
113 cout << "Military time: ";
114 t.printMilitaryO;
115 cout << "\nStandard time: ";
116 t.printStandard();
117
118 cout << "\n\nNew standard time: ";
119 t.setTime( 20, 20, 20 ).printStandard();
120 cout << endl;
121
122 return 0;
123 }
输出结果:
Military time: 18:30
standard time: 6:30:22 PM
New standard time: 8:20:20 PM
图 7.8 连续使用成员函数调用
为什么可以将*this作为引用返回呢? 圆点运算符(.)的结合律为从左向右,因此下列表达式:
t.setHour( 18 ).setMinute( 30 ).setSecond( 22 );
首先求值t.setHour(18),然后返回对象t的引用,作为这个函数调用的值。其余表达式解释如下:
t.setMinute(30).setSecond(22);
执行setMinute(30)调用并返回t的等价值,其余表达式解释为:
t.setSecond(22);
注意:
t.setTime(20,20,20).printStandard();
调用也体现了连续使用的特性。这些调用在这个表达式中必须按这个顺序出现,因为类中定义的
printStandard并不返回t的引用,将上述语句中的printStandard调用放在setTime调用之前是个语
法错误。
7.6 动态内存分配与new和delete运算符
new和delete运算符提供了比C语言的malloc和free函数调用更好的动态分配内存方法(对任何内部或用户自定义类型)。考虑下列代码:
TypeName *typeNamePtr;
在ANSI C语言中,要为TypeName类型对象动态分配内存,可以用下列语句:
typeNamePtr = malloc(sizeof(TypeName));
这就要求调用malloc函数和显式使用sizeof运算符,在ANSI C之前的C语言版本中,还要将malloc返回的指针进行类型转换(TypeName *)。malloe函数中没有提供初始化所分配内存块的方法。而在C++中,只要用下列语句;
typeNamePtr = new TypeName;
new运算符自动生成正确长度的对象并调用对象构造函数和返回正确类型的指针。如果new无法找到内存空间,则它在ANSI/ISO C++草案标准之前的C++版本中返回。指针(注意,第13章介绍了如何在ANSI/ISO C++草案标准中处理New故障。我们要显示new如何“抛出”异常,如何”捕获”与处理异常)。要在C++中释放这个对象的空间,就要用delete运算符,如下所示:
delete typeNamePtr;
C++允许对新生成的对象提供初始化值,如下所示:
float *thingPtr = new float(3.14159);
将新生成的对象float初始化为3.14159。
可以生成10个元素的整型数组并赋给arrayPtr,如下所示:
int *arrayPtr = new int[lO];
这个数组可以用下列语句删除:
delete [] arrayPtr;
可以看出,使用neW和delete而不用malloc和free还有其他好处。neW自动调用构造函数,delete自动调用析构函数。
常见编程错误7. 8
将new和delete动态分配内存的方法与malloc和free动态分配内存的方法混合使用是个逻辑错误:malloc分配的空间无法用delete释放,new生成的对象无法用free删除。
常见编程错误7. 9
用delete而不是delete[]删除数组可能导致运行时的逻辑错误。为了避免这个问题,数组生成的内存空间要用delete[]运算符删除,各个元素生成的内存空间要用delete运算符删除。
编程技巧7. 3
C++程序也可以包含用malloc生成和用free删除的存储空间以及用new生成和用delete删除的对象。但最好还是使用new和delete。
7.7 static类成员
类的每个对象有自己的所有数据成员的副本,有时类的所有对象应共享变量的一个副本,因此可以使用static类变量。stattic类变量表示的是类范围中所有对象共享的信息。static类成员的声明以static关键字开始。
下面用一个视频游戏的例子说明static类共享数据的作用。假设视频游戏中有Martian和其他太空人。每个Martian都很勇敢,只要有5个Martian存在,就可以攻击其他太空人。如果Martian的人数不到5个,则不能进行攻击。因此每个Martian都要知道martianCount。我们在Martian类中提供一个martianCount数据成员,这样,每个Martian有该数据成员的副本,每次生成新Martian时,都要更新每个Martian中的martianCount,这样既浪费空间又浪费时间。为此,我们将martianCount声明为static,这样就使martianCount成为类中共享的数据。每个Martian都可以访问martianCount,就像是自己的数据成员一样,但C++只需维护martianCount的一个静态副本,这样可以节省空间。让Martian构造函数递增静态martianCount还能节省时间,因为只有一个副本,不需要对每个Martian对象递增martianCount。
性能提示7.4
如果一个数据副本就足够使用,用static数据成员可以节省存储空间。
数据成员count维护Employee类实例化的对象个数。Employee类的对象存在时,可以通过Employee对象的任何成员函数引用成员count,本例中,构造函数和析构函数都引用了count。
常见编程错误 7. 10
在文件范围的static类变量定义中包括satic关键字是个语法错误。
1 // Fig. 7.9: employl.h
2 // An employee class
3 #ifndef EMPLOY1_H
4 #define EMPLOy1_H
5
6 class Employee {
7 public:
8 Employee( const char*, const char* ); // constructor
9 ~Employee(); // destructor
10 const char *getFirstName() const; // return first name
11 const char *getLastName() const; // return last name
12
13 // static member function
14 static int getCount(); // return # objects instantiated
15
16 private:
17 char *firstName;
18 char *lastName;
19
20 // static data member
21 static int count; // number of objects instantiated
22 };
23
24 #endif
25 // Fig. 7.9: employl.cpp
26 // Member function definitions for class Employee
27 #include <iostream.h>
28 #include <string.h>
29 #include <assert.h>
30 #include "employ1.h"
31
32 // Initialize the static data member
33 int Employee::count = O;
34
35 // Define the static member function that
36 // returns the number of employee objects instantiated.
37 int Employee::getCount() { return count; }
38
39 // Constructor dynamically allocates space for the
40 // first and last name and uses strcpy to copy
41 // the first and last names into the object
42 Employee::Employee( const char *first, const char *last )
43 {
44 firstName = new char[ strlen( first ) + 1 ];
45 assert( firstName != 0 ); // ensure memory allocated
46 strcpy( firstName, first );
47
48 lastName = new char[ strlen( last ) + 1 ];
49 assert( lastName ! = 0 ); // ensure memory allocated
50 strcpy( lastName, last );
52 ++count; // increment static count of employees
53 cout << "Employee constructor for" << firstName
54 << ' ' << lastName <<" called." << endl;
55 }
56
57 // Destructor deallocates dynamically allocated memory
58 Employee::~Employee()
59 {
60 cout << "~Employee() called for" << firstName
61 << ' ' << lastName << endl;
62 delete [] firstName; // recapture memory
63 delete [] lastName; // zecapture memory
64 --count; // decrement static count of employees
65 }
66
67 // Return first name of employee
68 const char *Employee::getFirstName() const
69 {
70 // Const before return type prevents client modifying
71 // private data. Client should copy returned string before
73 return firstName;
74 }
75
76 // Return last name of employee
77 const char *Employee::getLastName() const
78 {
79 // Const before return type prevents client modifying
80 // private data. Client should copy returned string before
81 // destructor deletes storage to prevent undefined pointer.
82 return lastName;
83 }
84 // Fig. 7.9: fig0709.cpp
85 // Driver to tast the employee class
86 #include <iostream.h>
83 #inelude "employ1.h"
89 int main()
90 {
91 cout << "Number of employees before instantiation is"
92 << Employee::getCount() << endl; // use class
93
94 Employee *e1Ptr = new Employee( "Susan", "Baker" );
95 Employee *e2Ptr = new Employee( "Robert", "Jones" );
96
97 cout << "Number of employees after instantiation is"
98 << e1Ptr->getCount();
99
100 cout << "\n\nEmployee 1:"
101 << e1Ptr ->getFirstName()
102 << " " << e1Ptr->getLastName()
103 << "\nEmployee 2:"
104 << e2Ptr->getFirstName()
105 << " "<< e2Ptr -> getLastName() << "\n\n";
106
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -