📄 08章 运算符重载.txt
字号:
编译器通过生成如下代码来调用operator == 成员函数:
integers1.operator==(integers2)
如果数组的size成员不相等,则operator==成员函数立即返回false,否则,成员函数开始成对比较相应的元素。如果它们全都相等,则返回true,一旦发现某一对元素不同则立即返回false。
第21到第22行:
bool operator!=(const Array &right)const
{ return ! ( *this == right);}
声明了重载的不相等运算符(!=)。成员函数中oprator!=根据重载的相等运算符定义。该函数定义用重载operator==函数确定一个Array是否等于另一个Array,然后返回结果的相反值。这样编写oprator!=函数使程序员可以复用operator==函数,减少类中需要编写的代码量。另外,operator!=的完整函数定义在Array头文件中,使编译器可以内联operator!=的定义,消除额外函数调用的开销。
第24到第25行:
int &operator[](int); // subscript operator
const int &operator[](int)const; // subscript operator
声明了两个重载的下标运算符(分别在第118和128行定义)。当编译器遇到main函数中的如下表达式时:
integers1[ 5]
编译器通过生成下列代码来调用重载的operator[]成员函数:
integers1.operator[] (5)
constArray对象使用下标运算符时,编译器调用operator的[]的const版本。operator[]成员函数首先测试下标是否越界。如果越界,则程序异常中止。如果没有越界,则对operator==的非const版本返回相应的数组元素作为引用,以便使它能用作左值(如用在赋值语句的左边)。而对operator[]的const版本返回右值。
第26行:
static int getArrayCount(); // return count of Arrays
声明了static成员函数getArrayCount。即使在不存在类Array的对象中,该成员函数也返回静态数据成员arrayCount的值。
8.9 类型之间的转换
大多数程序能处理各种数据类型的信息。有时候所有的操作还会集中于某一种类型上,例如,整数加整数还是整数(只要结果不是太大,能用整数表示出来)。但是,常常需要将一种类型的数据转换为另外一种类型的数据,赋值、计算、给函数传值以及从函数返回值都可能会发生这种情况。对于内部的类到,编译器知道如何转换类型。程序员也可以用强制类型转换运算符实现内部类型之间的强制转换。
但是怎样转换用户自定义类型呢?编译器不知道怎样实现用户自定义类型和内部类型之间的转换,程序员必须明确地指明如何转换。这种转换可以用转换构造函数实现,也就是使用单个参数的构造函数,这种函数仅仅把其他类型(包括内部类型)的对象转换为某个特定类的对象。本章梢后要用一个转换构造函数把正常的char*类型的字符串转换为类Siring的对象。
转换运算符(也称为强制类型转换运算符)可以把一种类的对象转换为其他类的对象或内部类型的对象。这种运算符必须是一个非static成员函数,而不能是友元函数。
函数原型:
A::operator char *() const;
声明了一个重载的强制类型转换运算符函数,它根据用户自定义类型A的对象建立一个临时的char*类型的对象。重载的强制类型转换运算符函数不能指定返回类型(返回类型是要转换后的对象类型)。如果s是某个类对象,当编译器遇到表达式(char*),时,会产生函数调用s.operator char*(),操作数s是调用成员函数operator char*的类对象s。
为了把用户自定义类型的对象转换为内部类型的的对象或用户自定义的其他类型的对象,我们可以定义重载的强制类型转换运算符函数。函数原型:
A::operator int()const;
A::operator otherClass()const;
声明了两个重载的强制类型转换运算符函数,分别用来把用户自定义类型A的对象转换为一个整数和用户自定义类型otherClass的对象。
强制类型转换运算符和转换构造函数一个很好的特点就是:当需要的时候,编译器可以为建立一个临时对象而自动地调用这些函数。例如,如果用户自定义的类String的某个对象s出现在程序中需要使用char*类型的对象的位置上,例如:
cout << s;
编译器调用重载的强制类型转换运算符函数operator char*将对象转换为char*类型,并在表达式中使用转换后的char*类型的结果。String类提供该转换运算符后,不需要重载流插入运算符用cout输出String。
8.10 实例研究:String类
作为学习重载的练习,本节要建立一个能够处理字符串的建立和操作的类(图8.5)。string类已是C++标准库中的一部分,第19章将详细介绍string类。现在我们用运算符重载建立一个String类。我们首先列出String类的首部,并讨论表示String的对象的private数据。然后,分析类的Public接口,讨论该类提供的每一种服务。
接着分析了main函数中的驱动程序。讨论了令人感兴趣的编码风格,也就是用新String类的对象和该类的重载运算符集编写的各种运算符表达式。
然后我们讨论了类String的成员函数的定义。对于每个重载的运算符函数,驱动程序都有调用重载的运算符的代码,并解释了这些函数的工作原理。
1 // Fig. 8.5: string1.h
2 // Definitien of a String class
3 #ifndef STRING1_H
4 #define STRING1_H
5
6 #include <iostream.h>
7
8 class String {
9 friend ostream &operator<<( ostream &, const String & );
10 friend istream &operator>>( istream &, String & );
11
12 public:
13 String( const char * ="" ); // conversion/default ctor
14 String( const String & ); // copy constructor
15 ~String(); // destructor
16 const String &operator=( const String & ); // assignment
17 const String &operator+=( const String & ); // concatenation
18 bool operator!() const; // is String empty?
19 bool operator==( const String & ) const; // test sl - s2
20 bool operator<( coost String & ) const; // test sl < s2
21
22 // test s1 != s2
23 bool operator!=( const String & right ) const
24 { return !( *this == right ); }
25
26 // test si > S2
27 bool operator>( const String &right ) const
28 { return right < *this; }
29
30 // test s1 <= s2
31 bool operator<=( const String &right ) const
32 { return !( right < *this ); (
33
34 // test s1 >= s2
35 bool operator>=( const String &right ) const
36 { return !( *this < right ); }
37
38 char &operator[] ( int ); // subscript operator
39 const char &operator[]( int ) const; // subscript operator
40 String &operator()( int, int ); // return a substring
41 int getLength() const; // return string length
42
43 private:
44 int length; // string length
45 char *sPtr; // pointer to start of string
46
47 void setString( const char * ); // utility function
48 };
50 #endif
51 // Fig. 8.5: string1.cpp
52 // Member function definitions for class String
53 #include <iostream.h>
54 #include <iomanip.h>
55 #include <string.h>
57 #include "string1.h"
58
59 // Conversion constructor: Convert char * to String
60 String::String( const char *s ) : length( strlen( s ))
61 {
62 cout << "Conversion constructor: "<< s << '\n';
63 setString( s ); // call utility function
64 }
65
66 // Copy constructor
67 String::String( const String © ) : length( copy.length )
68 {
69 cout << "Copy constructor: " << copy.sPtr << '\n';
70 setString( copy.sPtr ); // call utility function
71 }
72
73 // Destructor
74 String::~string()
75 {
76 cout << "Destructor: "<< sPtr << '\n';
77 delete [] sPtr; // reclaim string
78 }
79
80 // Overloaded = operator; avoids self assignment
81 const String &String::operator=( const String &right )
82 {
83 cout << "operator= called\n";
85 if ( &right != this ) { // avoid self assignment
86 delete [] sPtr; // prevents memory leak
87 length = right.length; // new String length
88 setString( right.sPtr ); // call utility function
89 }
90 else
91 cout << "Attempted assignment of a String to itself\n";
92
93 return *this; // enables cascaded assignments
94 }
95
96 // Concatenate right operand to this object and
97 // store in this object.
98 const String &String::operator+=( const String &right )
99 {
100 char *tempPtr = sPtr; // hold to be able to delete
101 length += right.length; // new String length
102 sPtr= new char[ length + 1 ]; // create space
103 assert( sPtr != 0 ); // terminate if memory not allocated
104 strcpy( sPtr, tempPtr ); // left part of new String
105 strcat( sPtr, right.sPtr ); // right part of new String
106 delete [] tempPtr; // reclaim old space
107 return *this; // enables cascaded calls
108 }
109
110 // Is this String empty?
111 bool String::operator!() const { return length == 0; }
112
113 // Is this String equal to right String?
114 bool String::oprator==( const String &right ) const
115 { return strcmp( sPtr, right.sPtr ) == 0; }
116
117 // Is this String less than right String?
118 bool String::oprator<( const String &right ) const
119 { return strcmp( sPtr, right.sPtr ) < 0; }
120
121 // Return a reference to a character in a String as an lvalue.
122 char &String::operator[] ( int subscript )
123 {
124 // First test for subscript out of range
125 assert( subscript >= 0 && subscript < length );
126
127 return sPtr[ subscript ]; // creates lvalue
128 }
129
130 // Return a reference to a character in a String as an rvalue.
131 const char &String::oprator[]( int subscript ) const
132 {
133 // First test for subscript out of range
134 assert( subscript >= 0 && subscript < length );
135
136 return sPtr[ subscript ]; // creates rvalue
137 }
138
139 // Return a substring beginning at index and
140 // of length subLength as a reference to a String object.
141 String &String::operator()( int index, int subLength )
142 {
143 // ensure index is in range and substring length >= 0
144 assert( index >= 0 && index < length && subLength >= 0 );
145
146 String *subPtr = new String; // empty String
147 assert( subPtr != 0 ); // ensure new String allocated
148
149 // determine length of substring
150 if ( ( subLength == 0 ) || ( index + subLength > length ) )
151 subPtr->length = length - index + 1;
152 else
153 subPtr->length = subnength + 1;
154
155 // allocate memory for substring
156 delete subPtr->sPtr; // delete character array from object
157 subPtr->sPtr = new char [ subPtr->length ];
158 assert( subPtr -> sPtr != 0 ); // ensure space allocated
159
160 // copy substring into new String
161 strncpy( subPtr->sPtr, &sPt[ index ], subPtr->length );
162 subPtr->sPtr[ subPtr -> length ] = '\0'; // terminate String
163
164 return *subPtr; // return new String
165 }
166
167 // Return string length
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -