ITEEDU

自测练习

8.1 填空:

a)设a和b是两个整型变量,我们用a+b的形式求这两个变量的和;设c和d为浮点型变量,我们用c+d的形式求这两个变量的和。显然,运算符+具有不同的用途,这是——的例子。

b)关键字——引出了重载运算符函数的定义。

c)要在类的对象上使用运算符,除了运算符——和——以外,其他的必须都要被重载。

d)重载不能改变运算符的——、——和——。

8.2 解释C++中的运算符 <<和>>的多层含义。

8.3 C++中,在什么时候可以使用名字operator/

8.4(判断对错)在C++中,只能重载已有的运算符。

8.5 在C++中,重载运算符的优先级和原先未重载的运算符的优先级相比,哪一个优先级高

自测练习答案

8.1 a)运算符重载。b)operator。c)=、&。d)优先级、结合律和数量。

8.2 根据上下文,运算符>>可能是右移位运算符,也可能是流读取运算符。同样,运算符<<可能是左移位运算符,也可能是流插入运算符。

8.3 运算符重载时可以使用operator/,它可以是提供运算符/的重载版本的函数名。

8.4 正确。

8.5 相同。

练 习

8.6 尽可能多地举出C和C++中隐式运算符重载的例子。给出需要在C++中显式重载运算符的具有说服性的例子。

8.7 C++中不能被重载的运算符有——、——、——、——和——。

8.8 字符串连接需要两个操作敷,即两个要被连接的字符串。本章介绍了如何实现将第二个String对象连接到第一个String对象右边的一个重载的连接运算符,这种连接会修改第一个String对象。在有些实际应用中,需要在不修改String参数的情况下产生一个已连接的String对象,请实现允许如下操作的operator+:string1 = string2 + string3;

8.9(基本运算符重载练习)列出C++的所有可重载的运算符,并对每个可重载的运算符,列出它们在用于几个不同的类时的一种或者几种可能的含义。建议试试下面的类:

a)数组

b)堆栈

c)字符串

完成后,说明哪些运算符的含义可适用于大量的类,哪些运算符重载的价值极小,哪些运算符具有歧义性。

8.10现在将上一个问题所描述的过程反过来,列出C++中每个可重载的运算符,对于每个运算符,列出你认为它应该代表的基本操作。如果有非常好的操作,把它们列出来。

8.11(项目)C++是一门正在发展中的语言,并且总是有许多新的语言开发出来。除了现有的运算符以外,你认为还有哪些运算符可以添加到C++或者添加到像C++这样既支持过程化编程又支持面向对象编程的未来语言中呢,请将你的建议寄给ANSIC++委员会。

8. 12重载函数调用运算符()的一个较好的例子是将以下的二维数组的下标表示方法:

chessBoard[ row ][ column ]

改为常用的表示方法:

chessboard( row,column )

试重载函数调用运算符()支持上述表示方法。

8.13生成DoubleSubscriptedArray类,与图8.4的Array类的特性相似。构造时,类应生成任意行数和列数的数组。类用operator()进行双下标操作。例如,在3 x 5的DoubleSubscriptedArray数组a中,用户可以用s(1,3)访问行1列3的元素。记住,operator()可以接收任何参数(关于operator()的例子,见图8.5的String类)。双下标数组的基本表达方式为rows*columns个元素的单下标数组。函数operator()应通过正确的指针算法访问数组的每个元素。实际上,

operator()应有两个版本,一个返回int &,使DoubleSubscriptedArray的元素可以用作左值,一个返回cons int&,使const DoubleSubscfiptedArray的元素可以用作右值。这个类还应提供下列运算符==;!=、=、<<(以行和列格式输出数组)和>>(输入整个数组内容)。

8.14重载下标运算符使之返回集合中最大的元素、次最大的元素以及第三大的元素等等。

8.15考虑图8.7中的类Complex,该类可以执行复数操作,复数的格式为:

realPart + imaginaryPart * i

其中i是 -1 的平方根。

a)修改该类,使之能用重载的 >>和<<输入和输出复数(当然要从Complex类中删除打印函数)。

b)重载乘法运算符,使之能执行两个复数的代数乘法。

c)重载运算符==和!=,使之能比较两个复数。

 // Fig. 8.7: complex1.h
 // Definition of class Complex
 #ifndef COMPLEX1_H
 #define COMPLEX1_H
 class Complex {
 public:
    Complex( double = 0.0, double = 0.0 );      // constructor
    Complex operator+( const Complex & ) const;  // addition
   Complex operator-( const Complex & ) const;  // subtraction
   const Complex &operator=( const Complex & ); // assignment
   void print() const;                     // output
 private:
   double real;      // real part
   double imaginary;  // imaginary part
 };
 #endif
 // Fig. 8.7:complex1.cpp
 // Member function definitions for class Complex
 #include < iostream.h>
 #include "complex1.h"
 // Constructor
 Complex::Complex( double r, double i )
     : real( r ), imaginary( i ) { }
 // Overloaded addition operator
 Complex Complex::operator+( const Complex &operand2 ) const
O {
   return Complex( real + operand2.real,
                   imaginary + operand2.imaginary );
 }
 // Overloaded subtraction operator
 Complex Complex::operator-( const Complex &operand2 ) const
 {
   return Complex( real - operand2.real,
                   imaginary - operand2.imaginary );
}
 // Overloaded = operator
 const Complex& Complex::operator=( const Complex &right )
 {
   real = right.real;
   imaginary = right.imaginary;
   return *this;  // enables cascading
 }
 void Complex::print() const
   { cout << '(' << real << ", "<< imaginary << ')'; }
 // Fig. 8.7:fig08_07.cpp
 // Driver for class Complex
 #include < iostream.h>
 #include "complex1.h"
 int main()
 {
     Complex x, y( 4.3, 8.2 ), z( 3.3, 1.1 );
     cout << "x: ";
     x.print();
     cout << "\ny: ";
     y.print();
     cout << "\nZ: ";
     z.print();
     x = y + z;
     cout << "\n\nx = y + z:\n";
     x.print();
     cout << " = ";
     y.print();
     cout <<" + ";
   z.print();
   x = y - z;
   cout << "\n\nx = y - z:\n";
   x.print();
   cout << "="  ;
   y.print();
   cout << " - "  :
   z.print();
   cout << endl;
   return 0;
 }

输出结果:

x: (0,0)

y: (4.3, 8.2)

z: (3.3, 1.1)

x = y + z:

(7.6, 9.3) = (4.3, 8.2) + (3.3, 1.1)

x = y - z:

(1, 7.1) = (4.3, 8.2) - (3.3, 1.1)

图 8.7 演示Complex类

8.16 32位整数的机器所能表示的整数范围大致是-20亿到+20亿,在这个范围内的操作一般不会出现问题。但是有很多应用程序可能要使用超出上述范围的整数,C++可以满足这个需求,这需要建立一个新的数据类型。考虑图8.8中的类HugeInt,仔细研究以后,完成下列问题:

a)准确描述它是如何操作的。

b)该类有什么限制,

c)重载乘法运算符*。

d)重载除法运算符/。

e)重载所有的关系运算符和相等运算符。

// Fig. 8.8: hugeintl.h
 // Definition of the Hugelnt clas~
 #ifndef HUGEINT1_H
 #define HUGEINT1_H
 #include < iostream.h>
 class HugeInt {
   friend ostream &operator<<( ostream &, HugeInt & );
 public:
   HugeInt( long = 0 );      // conversion/default constructor
   HugeInt( const char * );         // conversion constructor
   HugeInt operator+( HugeInt & );   // add another HugeInt
   HugeInt operator+( int );        // add an int
   HugeInt operator+( const char * ); // add an int in a char *
 private:
 };
 #endif
 // Fig. 8.8: nugeintl.cpp
 // Member and friend function definitions for class HugeInt
 #include < string.h>
 #include "hugeint1.h"
 // Conversion constructor
 HugeInt::HugeInt( long val )
 {
   int i;
   for( i = 0; i <= 29;i ++ )
      integer[ i ] = 0;  // initialize array to zero
   for ( i = 29; val != 0 && i >= 0; i-- ) {
     integer[ i ] = val % 10;
     val /= 10;
   }
 }
 HugeInt::HugeInt( const char *string )
 {
   int i, j;
   fori( i =O i <= 29; i++ )
      integer[ i ] = 0;
   for ( i = 30 - strlen( string ), j = 0; i <= 29; i++, j++ )
     integer[ i ] = string[ j ] - '0';
 }
 // Addition
 HugeInt HugeInt::operator+( HugeInt &op2 )
 {
   HugeInt temp;
   int carry = 0;
   for( int i = 29; i >= 0; i --){
      temp.integer[ i ] = integer[ i ] +
                      ep2.integer[ i ] + carry;
O
      if ( temp.integer[ i ] > 9 ) {
        temp.integer[ i ] %= 10;
        carry = 1;
      else
        carry = 0;
   }
   return temp;
 }
 // Addition
 HugeInt HugeInt::operator+( int op2 )
   { return *this + HugeInt( op2 ); }
 // Addition
 HugeInt HugeInt::operator+( const char *op2 )
  { return *this + HugeInt( op2 ); }
 ostream& operator<<( ostream &output, HugeInt &num )
 {
   int i;
    for ( i = 0; { num.integer[ i ] == 0 ) && ( i <= 29 ); i++ )
      ; // skip leading zeros
   if ( i == 30 )
      output << 0;
   else
     for ( ; i <= 29; i++ )
        output << num.integer[ i ];
   return output;
 }
 // Fig. 8.8: figO8_08.cpp
 // Test driver for HugeInt 
 #include < iostream.h>
 #include "hugeint1.h"
 
 int main()
 {
    HugeInt n1( 7654321 ), n2( 7891234 ),
           n3( "99999999999999999999999999999" ),
            n4( "1" ), n5;
   cout << "n1 is "<< n1 << "\nn2 is "<< n2
        << "\nn3 is" << n3 << "\nn4 is" << n4
        << "\nn5 is" << n5 << "\n\n";
   n5 = n1 + n2;
   cout << n1 <<" + "<< n2 << " = "  << n5 << "\n\n";
   cout << n3 <<" +" << n4 << "\n= "<< ( n3 + n4 )
        << "\n\ n";
   n5 = n1 + 9;
   cout << n1 <<" + " << 9 << "=" << n5 << "\n\n";
   n5 = n2 + "10000";
   cout << n2 << " + " << "10000" << " = " << n5 << endl;
   return 0;
 }

输出结果:

n1 is 7654321

n1 is 7891234

n1 is 99999999999999999999999999999

n1 is 1

n1 is O

7654321 + 7891234 = 15545555

99999999999999999999999999999 +1

= 1OO000000000000000000000000000

7654321 + 9 = 7654330

7891234 + 10000 = 7901234

图8.8 用户自定义的巨型整数类

8.17建立类RationalNumber(分数类),使之具有下述功能:

a)建立构造函数,它能防止分母为0、当分数不是最简形式时进行约分以及避免分母为负数。

b)重载加法、减法、乘法以及除法运算符。

c)重载关系运算符和相等运算符。

8.18仔细研究C的字符串处理库函数,分别把这些函数作为类String的一部分予以实现,然后用这些函数执行文本操作。

8.19开发多项式类Polynomial,多项式的每一项用数组表示,每项包含一个系数和一个指数。

例如:

2x4

的指数为4,系数为2。请开发一个完整的Polynomial类,包括构造函数、析构函数以及”get”函数和“set”函数。该类还要提供下述重载的运算符:

a)重载加法运算符+,将两个多项式相加。

b)重载减法运算符-,将两个多项式相减。

c)重载赋值运算符=,将一个多项式赋给另外一个多项式。

d)重载乘法运算符*,将两个多项式相乘。

c)重载加法赋值运算符+=、减法赋值运算符-=以及乘法赋值运算符*=。

8.20 图8.3的程序包含下列注释语句:

// Overloaded stream-insertion operator(cannot be 

// a member function if we would like to invoke it with 

// cout << somePhoneNumber;)

实际上,它不能是ostream类的成员函数,但可以是PhoneNumber类的成员函数,只要以下列方式调用:

somePhoneNumber.operator <<(cout);
或 
somePhoneNumber << cout;

改写图8.3的程序.用重载的流插入operator <<作为成员函数,试在程序中使用上述语句以证明程序能够运行。