Note05

书:C++大学教程(第七版)
1. 运算符重载
(1) 重载不能改变运算符的优先级;
(2) 重载不能改变运算符的结合律;
(3) 重载不能改变元素运算符的“元数”;
(4) 不能创建新的运算符,只有现有的运算符才可以重载;
(5) 运算符重载不能改变运算符对于基本类型对象操作的含义;
(6) 运算符重载只能对用户自定义类型的对象,或者用户自定义类型对象和基本类型对象的混合使用起作用;

class Complex
{
   friend ostream &operator<<( ostream &, const Complex & );
   friend istream &operator>>( istream &, Complex & );
public:
   Complex( double = 0.0, double = 0.0 ); // constructor
   Complex operator+( const Complex& ) const; // addition
   Complex operator-( const Complex& ) const; // subtraction
   Complex operator*( const Complex& ) const; // multiplication
   Complex& operator=( const Complex& ); // assignment
   bool operator==( const Complex& ) const;
   bool operator!=( const Complex& ) const;
private:
   double real; // real part
   double imaginary; // imaginary part
}; // end class Complex
  1. 类成员函数和全局函数的运算符函数的比较
    (1) 运算符函数可以是成员函数或全局函数。出于性能方面的考虑,全局函数通常指定为友元函数。成员函数用this指针隐式获得类对象的某个参数(对二元运算符而言即为左操作数),而二元运算符的两个操作数参数在全局函数调用中必须显示列出。
    (2) 必须作为类的成员函数进行重载的运算符:()、[]、->、任何赋值运算符;
    (3) 当运算符函数作为成员函数实现时,最左边(或者只有最左边)的操作数必须是运算符的一个类对象(或者是该类对象的一个引用)。如果左操作数必须是一个不同类的对象或者是一个基本类型对象,那么该运算符函数必须作为全局函数来实现。如果全局运算符函数必须直接访问类的private或者protected成员,那么该函数可以指定成该类的友元函数。
    (4) 一个特定类的运算符成员函数仅在下面两种情形下(由编译器隐式)调用:当二元运算符的左操作数的确是该类的对象时,或者当一元运算符唯一的操作数是该类的对象时。
  2. 流插入运算符(<<)和流提取运算符(>>)为何作为全局函数来重载?
    重载的流插入运算符(<<)用在其左操作数的类型为ostream&之类的表达式中,如cout<<classObject。如果要在右操作数是用户自定义类的对象的情况下使用该运算符,那么该运算符必须重载成全局函数。要以成员函数重载,运算符<<就必须成为ostream类的成员。用户自定义的类不可能做到这一点,因为我们不能修改C++标准库中的类。重载流提取运算符同理。
    这两个重载运算符函数都可能需要访问要输出或输入的类对象的private数据成员,因此出于性能原因,可以把这些重载运算符函数制定为类的友元函数。
  3. 返回对自动变量或者其他临时队形的引用时很危险的额,相当于对不存在的对象创建了“虚悬引用”。
  4. 重载一元运算符
    类的一元运算符可以重载为不带参数的非static成员函数或者带有一个参数的全局函数。全局函数的参数必须是该类的对象或者是该类对象的引用。实现重载运算符的成员函数必须是非static的,这样它们可以访问该类每个对象中的非static数据。
  5. 重载二元运算符
    二元运算符可以重载为带有一个参数的非static成员函数,或者两个参数(其中一个必须是类的对象或者是类对象的引用)的全局函数。
  6. 复制构造函数
    (1) 无论何时需要对象的副本,例如在向函数按值传递对象时,从函数按值返回对象时,或者用同一个类的另一对象的副本初始化一个对象时,都会调用复制构造函数。
    (2) 复制构造函数必须按引用接收参数,而非按值。否则,复制构造函数的调用会导致无穷递归。因为按值接收对象时,需要复制构造函数生成实参对象的副本。回想一下,无论何时需要对象的副本,都会调用类的复制构造函数。所以如果复制构造函数按值接收参数,那么为了生成其参数的副本,它会递归地调用自己。
  7. 通常会为任何一个使用动态分配内存的类同时提供一组函数:复制构造函数、析构函数和重载的复制运算符函数。
  8. 阻止类的一个对象赋给另一个对象,只要把复制运算符声明为这个类的private成员即可。
  9. 阻止类对象的复制
    只需把这个类重载的赋值运算符和复制构造函数声明成private。
  10. 转换运算符
    转换运算符也称为强制类型转换运算符,可用于将某一类的对象转换成另一类的对象,或者转换成基本类型的对象。这种转换运算符必须是非static成员函数。
 A::operator char *() const;
声明了一个重载的强制类型转换运算符函数,可以把用户自定义类型A的对象转换成一个临时的char*对象。这个运算符函数声明为const,因为它并不修改原始的对象。重载的强制类型转换运算符函数不指定返回类型,因为返回类型其实就是对象正要转换成的目标类型。如果s是某个类的对象,当编译器遇到表达式static_cast<char*>(s)时,它会产生函数调用:
s.operator char *()
操作数s是正在调用成员函数operator char* 的类对象s。
强制类型转换运算符和转换构造函数的优点之一是:必要时,编译器可以隐式地调用这些函数来创建临时的对象。

12. 重载前置的自增运算符
遇到++d1,会产生d1.operator++()调用;
函数原型:Date &operator++();
如果以全局函数实现前置的自增运算符,那么当编译器遇到表达式++d1,将产生函数调用operator++(d1);这个运算符函数的原型将在Date类中声明为:Date &operator(Date &);
13. 重载后置的自增运算符
遇到d1++,会产生d1.operator++(0)调用;
函数原型:Date &operator++(int );
实参0纯粹是个“哑值”,它使编译器能够区分前置的后置的自增运算符函数。
如果以全局函数实现前置的自增运算符,那么当编译器遇到表达式++d1,将产生函数调用operator++(d1, 0);这个运算符函数的原型将在Date类中声明为:Date &operator(Date &, int );
后置的自增运算符按值返回Date对象,而前置的自增运算符按引用返回Date对象。这是因为在进行自增前,后置的自增运算符通常先返回一个包含对象原始值的临时对象。C++将这样的对象作为右值处理,使其不能用在赋值运算符的左侧。前置的自增运算符返回实际自增后的具有新值的对象,这种对象在连续的表达式中可以作为左值使用。
由后置的自增(或自减)运算符创建的临时对象会对性能造成很大的影响,尤其是在循环中使用这个运算符时。出于这个原因,仅当程序的逻辑要求后置自增(或后置自减)操作时,才应该使用后置自增(或自减)运算符。
14. explicit构造函数
outputArray( 3 ); // convert 3 to an Array and output Array’s contents
main函数中将3隐式调用含有一个int参数的构造函数,产生Array对象,再打印Array对象
使用explicit,禁止不应该允许的由转换构造函数完成的隐式转换。

#ifndef ARRAY_H
#define ARRAY_H
#include <iostream>
using namespace std;
class Array
{
   friend ostream &operator<<( ostream &, const Array & );
   friend istream &operator>>( istream &, Array & );
public:
   Array( int = 10 ); // default constructor
   Array( const Array & ); // copy constructor
   ~Array(); // destructor
   int getSize() const; // return size
   const Array &operator=( const Array & ); // assignment operator
   bool operator==( const Array & ) const; // equality operator
   // inequality operator; returns opposite of == operator
   bool operator!=( const Array &right ) const  
   { 
      return ! ( *this == right ); // invokes Array::operator==
   } // end function operator!=

   // subscript operator for non-const objects returns modifiable lvalue
   int &operator[]( int );              
   // subscript operator for const objects returns rvalue
   int operator[]( int ) const;  
private:
   int size; // pointer-based array size
   int *ptr; // pointer to first element of pointer-based array
}; // end class Array
#endif
// Array class member- and friend-function definitions.
#include <iostream>
#include <iomanip>
#include <cstdlib> // exit function prototype
#include "Array.h" // Array class definition
using namespace std;
// default constructor for class Array (default size 10)
Array::Array( int arraySize )
{
   size = ( arraySize > 0 ? arraySize : 10 ); // validate arraySize
   ptr = new int[ size ]; // create space for pointer-based array
   for ( int i = 0; i < size; i++ )
      ptr[ i ] = 0; // set pointer-based array element
} // end Array default constructor
// copy constructor for class Array;
// must receive a reference to prevent infinite recursion
Array::Array( const Array &arrayToCopy ) 
   : size( arrayToCopy.size )
{
   ptr = new int[ size ]; // create space for pointer-based array
   for ( int i = 0; i < size; i++ )
      ptr[ i ] = arrayToCopy.ptr[ i ]; // copy into object
} // end Array copy constructor
// destructor for class Array
Array::~Array()
{
   delete [] ptr; // release pointer-based array space
} // end destructor
// return number of elements of Array
int Array::getSize() const
{
   return size; // number of elements in Array
} // end function getSize
// overloaded assignment operator;
// const return avoids: ( a1 = a2 ) = a3
const Array &Array::operator=( const Array &right )
{
   if ( &right != this ) // avoid self-assignment
   {
      // for Arrays of different sizes, deallocate original
      // left-side array, then allocate new left-side array
      if ( size != right.size )
      {
         delete [] ptr; // release space
         size = right.size; // resize this object
         ptr = new int[ size ]; // create space for array copy
      } // end inner if
      for ( int i = 0; i < size; i++ )
         ptr[ i ] = right.ptr[ i ]; // copy array into object
   } // end outer if
   return *this; // enables x = y = z, for example
} // end function operator=
// determine if two Arrays are equal and
// return true, otherwise return false
bool Array::operator==( const Array &right ) const
{
   if ( size != right.size )
      return false; // arrays of different number of elements
   for ( int i = 0; i < size; i++ )
      if ( ptr[ i ] != right.ptr[ i ] )
         return false; // Array contents are not equal
   return true; // Arrays are equal
} // end function operator==
// overloaded subscript operator for non-const Arrays;
// reference return creates a modifiable lvalue
int &Array::operator[]( int subscript )
{
   // check for subscript out-of-range error
   if ( subscript < 0 || subscript >= size )
   {
      cerr << "\nError: Subscript " << subscript 
         << " out of range" << endl;
      exit( 1 ); // terminate program; subscript out of range
   } // end if
   return ptr[ subscript ]; // reference return
} // end function operator[]
// overloaded subscript operator for const Arrays
// const reference return creates an rvalue
int Array::operator[]( int subscript ) const
{
   // check for subscript out-of-range error
   if ( subscript < 0 || subscript >= size )
   {
      cerr << "\nError: Subscript " << subscript 
         << " out of range" << endl;
      exit( 1 ); // terminate program; subscript out of range
   } // end if
   return ptr[ subscript ]; // returns copy of this element
} // end function operator[]
// overloaded input operator for class Array;
// inputs values for entire Array
istream &operator>>( istream &input, Array &a )
{
   for ( int i = 0; i < a.size; i++ )
      input >> a.ptr[ i ];
   return input; // enables cin >> x >> y;
} // end function 
// overloaded output operator for class Array 
ostream &operator<<( ostream &output, const Array &a )
{
   int i;
   // output private ptr-based array 
   for ( i = 0; i < a.size; i++ )
   {
      output << setw( 12 ) << a.ptr[ i ];
      if ( ( i + 1 ) % 4 == 0 ) // 4 numbers per row of output
         output << endl;
   } // end for
   if ( i % 4 != 0 ) // end last line of output
      output << endl;
   return output; // enables cout << x << y;
} // end function operator<<
// Driver for simple class Array.
#include <iostream>
#include "Array.h"
using namespace std;
void outputArray( const Array & ); // prototype
int main()
{
   Array integers1( 7 ); // 7-element array
   outputArray( integers1 ); // output Array integers1
   outputArray( 3 ); // convert 3 to an Array and output Array’s contents
}  // end main
// print Array contents
void outputArray( const Array &arrayToOutput )
{
   cout << "The Array received has " << arrayToOutput.getSize() 
      << " elements. The contents are:\n" << arrayToOutput << endl;
} // end outputArray
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值