運算符重載

運算符重載

運算符重載,就是對已有的運算符重新進行定義,賦予其另一種功能,以適應不同的數據類型。

函數


義類賦值運算符重載函數的作用與內置賦值運算符的作用類似,但是要注意的是,它與拷貝構造函數析構函數一樣,要注意深拷貝淺拷貝的問題,在沒有深拷貝淺拷貝的情況下,如果沒有指定默認的賦值運算符重載函數,那麼系統將會自動提供一個賦值運算符重載函數。

示例


義——包含段、構造函(),查容,運算符載:
 ..
struct Vector
public double x,y,z;
public Vector(double x,double y,double z)
this.x = x;this.y = y;
this.z = z;
public Vector(Vector rhs)
x = rhs.x;
y = rhs.y;
z = rhs.z;
public override string ToString()
return "( " + x + "," + y + "," + z + " )";
這裡提供了兩個構造函數,通過傳遞每個元素的值,或者提供另一個複製其值的Vector,來指定矢量的初始值。第二個構造函數帶一個Vector參數,通常稱為複製構造函數,因為它們允許通過複製另一個實例來初始化一個類或結構實例。注意,為了簡單起見,把欄位設置為public。也可以把它們設置為private,編寫相應的屬性來訪問它們,這樣做不會改變這個程序的功能,只是代碼會複雜一些。
下面是Vector結構的有趣部分—— 為+運算符提供支持的運算符重載:
public static Vector operator + (Vector lhs,Vector rhsVector result = new Vector(lhs);
result.x += rhs.x;
result.y += rhs.y;
result.z += rhs.z;
return result;
運算符重載的聲明方式與方法的聲明方式相同,但operator關鍵字告訴編譯器,它實際上是一個運算符重載,後面是相關運算符的符號,在本例中就是+。返回類型是在使用這個運算符時獲得的類型。在本例中,把兩個矢量加起來會得到另一個矢量,所以返回類型就是Vector。對於這個+運算符重載,返回類型與包含類一樣,但這種情況並不是必需的。兩個參數就是要操作的對象。對於二元運算符(帶兩個參數),如+和-運算符,第一個參數是放在運算符左邊的值,第二個參數是放在運算符右邊的值。
C#要求所有的運算符重載都聲明為public和static,這表示它們與它們的類或結構相關聯,而不是與實例相關聯,所以運算符重載的代碼體不能訪問非靜態類成員,也不能訪問this標識符;這是可以的,因為參數提供了運算符執行任務所需要知道的所有數據。
前面介紹了聲明運算符+的語法,下面看看運算符內部的情況:
Vector result = new Vector(lhs);
result.x += rhs.x;
result.y += rhs.y;
result.z += rhs.z;
return result;
這部分代碼與聲明方法的代碼是完全相同的,顯然,它返回一個矢量,其中包含前面定義的lhs和rhs的和,即把x、y和z分別相加。

簡單代碼

下面需要編寫一些簡單的代碼,測試Vector結構:
static void Main()
Vector vect1,vect2,vect3;
vect1 = new Vector(3.0,3.0,1.0);
vect2 = new Vector(2.0,­­­;–4.0,–4.0);
vect3 = vect1 + vect2;
Console.WriteLine("vect1 = " + vect1.ToString());
Console.WriteLine("vect2 = " + vect2.ToString());
Console.WriteLine("vect3 = " + vect3.ToString());
把這些代碼保存為Vectors.cs,編譯並運行它,結果如下:
Vectors
vect1 = ( 3,3,1 )
vect2 = ( 2,–4,–4 )
vect3 = ( 5,–1,–3 )
運算符重載不能用於Java
下面舉一個TICPP中的例子……
一元的:
//: C12:OverloadingUnaryOperators.cpp
// From Thinking in C++,2nd Edition
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#include
using namespace std;
// Non-member functions:
class Integer
long i;
Integer* This() return this;
public:
Integer(long ll = 0) : i(ll)
// No side effects takes const& argument:
friend const Integer&
operator+(const Integer& a);
friend const Integer
operator-(const Integer& a);
friend const Integer
operator~(const Integer& a);
friend Integer*
operator&(Integer& a);
friend int
operator!(const Integer& a);
// Side effects have non-const& argument:
// Prefix:
friend const Integer&
operator++(Integer& a);
// Postfix:
friend const Integer
operator++(Integer& a,int);
// Prefix:
friend const Integer&
operator--(Integer& a);
// Postfix:
friend const Integer
operator--(Integer& a,int);
// Global operators:
const Integer& operator+(const Integer& a)
cout << "+Integer\n";
return a; // Unary + has no effect
const Integer operator-(const Integer& a)
cout << "-Integer\n";
return Integer(-a.i);
const Integer operator~(const Integer& a)
cout << "~Integer\n";
return Integer(~a.i);
Integer* operator&(Integer& a)
cout << "&Integer\n";
return a.This(); // &a is recursive!
int operator!(const Integer& a)
cout << "!Integer\n";
return !a.i;
// Prefix; return incremented value
const Integer& operator++(Integer& a)
cout << "++Integer\n";
a.i++;
return a;
// Postfix; return the value before increment:
const Integer operator++(Integer& a,int)
cout << "Integer++\n";
Integer before(a.i);
a.i++;
return before;
// Prefix; return decremented value
const Integer& operator--(Integer& a)
cout << "--Integer\n";
a.i--;
return a;
// Postfix; return the value before decrement:
const Integer operator--(Integer& a,int)
cout << "Integer--\n";
Integer before(a.i);
a.i--;
return before;
// Show that the overloaded operators work:
void f(Integer a)
+a;
-a;
~a;
Integer* ip = &a;
!a;
++a;
a++;
--a;
a--;
// Member functions (implicit "this"):
class Byte
unsigned char b;
public:
Byte(unsigned char bb = 0) : b(bb)
// No side effects: const member function:
const Byte& operator+() const
cout << "+Byte\n";
return *this;
const Byte operator-() const
cout << "-Byte\n";
return Byte(-b);
const Byte operator~() const
cout << "~Byte\n";
return Byte(~b);
Byte operator!() const
cout << "!Byte\n";
return Byte(!b);
Byte* operator&()
cout << "&Byte\n";
return this;
// Side effects: non-const member function:
const Byte& operator++() // Prefix
cout << "++Byte\n";
b++;
return *this;
const Byte operator++(int) // Postfix
cout << "Byte++\n";
Byte before(b);
b++;
return before;
const Byte& operator--() // Prefix
cout << "--Byte\n";
--b;
return *this;
const Byte operator--(int) // Postfix
cout << "Byte--\n";
Byte before(b);
--b;
return before;
void g(Byte b)
+b;
-b;
~b;
Byte* bp = &b;
!b;
++b;
b++;
--b;
b--;
int main()
Integer a;
f(a);
Byte b;
g(b);
///:~
二元的:
//: C12:Integer.h
// From Thinking in C++,2nd Edition
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
// Non-member overloaded operators
#ifndef INTEGER_H
#define INTEGER_H
#include
// Non-member functions:
class Integer
long i;
public:
Integer(long ll = 0) : i(ll)
// Operators that create new,modified value:
friend const Integer
operator+(const Integer& left,
const Integer& right);
friend const Integer
operator-(const Integer& left,
const Integer& right);
friend const Integer
operator*(const Integer& left,
const Integer& right);
friend const Integer
operator/(const Integer& left,
const Integer& right);
friend const Integer
operator%(const Integer& left,
const Integer& right);
friend const Integer
operator^(const Integer& left,
const Integer& right);
friend const Integer
operator&(const Integer& left,
const Integer& right);
friend const Integer
operator|(const Integer& left,
const Integer& right);
friend const Integer
operator<<(const Integer& left,
const Integer& right);
friend const Integer
operator>>(const Integer& left,
const Integer& right);
// Assignments modify & return lvalue:
friend Integer&
operator+=(Integer& left,
const Integer& right);
friend Integer&
operator-=(Integer& left,
const Integer& right);
friend Integer&
operator*=(Integer& left,
const Integer& right);
friend Integer&
operator/=(Integer& left,
const Integer& right);
friend Integer&
operator%=(Integer& left,
const Integer& right);
friend Integer&
operator^=(Integer& left,
const Integer& right);
friend Integer&
operator&=(Integer& left,
const Integer& right);
friend Integer&
operator|=(Integer& left,
const Integer& right);
friend Integer&
operator>>=(Integer& left,
const Integer& right);
friend Integer&
operator<<=(Integer& left,
const Integer& right);
// Conditional operators return true/false:
friend int
operator==(const Integer& left,
const Integer& right);
friend int
operator!=(const Integer& left,
const Integer& right);
friend int
operator<(const Integer& left,
const Integer& right);
friend int
operator>(const Integer& left,
const Integer& right);
friend int
operator<=(const Integer& left,
const Integer& right);
friend int
operator>=(const Integer& left,
const Integer& right);
friend int
operator&&(const Integer& left,
const Integer& right);
friend int
operator||(const Integer& left,
const Integer& right);
// Write the contents to an ostream:
void print(std::ostream& os) const os << i;
#endif // INTEGER_H ///:~
//: C12:Integer.cpp O
// From Thinking in C++,2nd Edition
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
// Implementation of overloaded operators
#include "Integer.h"
#include "../require.h"
const Integer
operator+(const Integer& left,
const Integer& right)
return Integer(left.i + right.i);
const Integer
operator-(const Integer& left,
const Integer& right)
return Integer(left.i - right.i);
const Integer
operator*(const Integer& left,
const Integer& right)
return Integer(left.i * right.i);
const Intege
operator/(const Integer& left,
const Integer& right)
require(right.i != 0,"divide by zero");
return Integer(left.i / right.i);
const Integer
operator%(const Integer& left,
const Integer& right)
require(right.i != 0,"modulo by zero");
return Integer(left.i % right.i);
const Integer
operator^(const Integer& left,
const Integer& right)
return Integer(left.i ^ right.i);
const Integer
operator&(const Integer& left,
const Integer& right)
return Integer(left.i & right.i);
const Integer
operator|(const Integer& left,
const Integer& right)
return Integer(left.i | right.i);
const Integer
operator<<(const Integer& left,
const Integer& right)
return Integer(left.i << right.i);
const Integer
operator>>(const Integer& left,
const Integer& right)
return Integer(left.i >> right.i);
// Assignments modify & return lvalue:
Integer& operator+=(Integer& left,
const Integer& right)
if(&left == &right)
left.i += right.i;
return left;
Integer& operator-=(Integer& left,
const Integer& right)
if(&left == &right)
left.i -= right.i;
return left;
Integer& operator*=(Integer& left,
const Integer& right)
if(&left == &right)
left.i *= right.i;
return left;
Integer& operator/=(Integer& left,
const Integer& right)
require(right.i != 0,"divide by zero");
if(&left == &right)
left.i /= right.i;
return left;
Integer& operator%=(Integer& left,
const Integer& right)
require(right.i != 0,"modulo by zero");
if(&left == &right)
left.i %= right.i;
return left;
Integer& operator^=(Integer& left,
const Integer& right)
if(&left == &right)
left.i ^= right.i;
return left;
Integer& operator&=(Integer& left,
const Integer& right)
if(&left == &right)
left.i &= right.i;
return left;
Integer& operator|=(Integer& left,
const Integer& right)
if(&left == &right)
left.i |= right.i;
return left;
Integer& operator>>=(Integer& left,
const Integer& right)
if(&left == &right)
left.i >>= right.i;
return left;
Integer& operator<<=(Integer& left,
const Integer& right)
if(&left == &right)
left.i <<= right.i;
return left;
// Conditional operators return true/false:
int operator==(const Integer& left,
const Integer& right)
return left.i == right.i;
int operator!=(const Integer& left,
const Integer& right)
return left.i != right.i;
int operator<(const Integer& left,
const Integer& right)
return left.i < right.i;
int operator>(const Integer& left,
const Integer& right)
return left.i > right.i;
int operator<=(const Integer& left,
const Integer& right)
return left.i <= right.i;
int operator>=(const Integer& left,
const Integer& right)
return left.i >= right.i;
int operator&&(const Integer& left,
const Integer& right)
return left.i && right.i;
int operator||(const Integer& left,
const Integer& right)
return left.i || right.i;
///:~
//: C12:IntegerTest.cpp
// From Thinking in C++,2nd Edition
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
//L Integer
#include "Integer.h"
#include
using namespace std;
ofstream out("IntegerTest.out");
void h(Integer& c1,Integer& c2)
// A complex expression:
c1 += c1 * c2 + c2 % c1;
#define TRY(OP) \
out << "c1 = "; c1.print(out); \
out << ",c2 = "; c2.print(out); \
out << "; c1 " #OP " c2 produces "; \
(c1 OP c2).print(out); \
out << endl;
TRY(+) TRY(-) TRY(*) TRY(/)
TRY(%) TRY(^) TRY(&) TRY(|)
TRY(<<) TRY(>>) TRY(+=) TRY(-=)
TRY(*=) TRY(/=) TRY(%=) TRY(^=)
TRY(&=) TRY(|=) TRY(>>=) TRY(<<=)
// Conditionals:
#define TRYC(OP) \
out << "c1 = "; c1.print(out); \
out << ",c2 = "; c2.print(out); \
out << "; c1 " #OP " c2 produces "; \
out << (c1 OP c2); \
out << endl;
TRYC(<) TRYC(>) TRYC(==) TRYC(!=) TRYC(<=)
TRYC(>=) TRYC(&&) TRYC(||)
int main()
cout << "friend functions" << endl;
Integer c1(47),c2(9);
h(c1,c2);
///:~

基本模型


終止模型

一種稱為"終止模型"(它是Java與C++所支持的模型).在這種模型中,將假設錯誤非常關鍵,將以致於程序無法返回到異常發生的地方繼續執行。一旦異常被拋出,就表明錯誤已無法挽回,也不能回來繼續執行.

恢復模型

另一種稱為"恢復模型".意思是異常處理程序的工作是修正錯誤,然後重新嘗試調動出問題的方法,並認為的二次能成功. 對於恢復模型,通常希望異常被處理之後能繼續執行程序。在這種情況下,拋出異常更像是對方法的調用--可以在Java里用這種方法進行配置,以得到類似恢復的行為.(也就是說,不是拋出異常,而是調用方法修正錯誤.)或者,把try塊放在while循環里,這樣就可以不斷的進入try塊,直到得到滿意的結果.

各有千秋

雖然恢復模型開始顯得很吸引人,並且人們使用的操作系統也支持恢復模型的異常處理,但程序員們最終還是轉向了使用類似"終止模型"的代碼。因為:處理程序必須關注異常拋出的地點,這勢必要包含依賴於拋出位置的非通用性代碼。這增加了代碼編寫和維護的困難,對於異常可能會從許多地方拋出的大型程序來說,更是如此. 下面我寫的一個簡單的例子 VC++6.0下通過
#include
using namespace std;
class Error
public:
virtual void show()=0;
class DenoError:public Error
public:
void show()cout<<"分母不可以為0!"<
void main()
int a,b;
cin>>a>>b;
try
DenoError e;
if(b==0) throw e;
int c=a/b;
cout<
catch(DenoError & e)
e.show();

分類


支持運算符重載和定義新運算符的語言:
• PostgreSQL的SQL方言
• Ruby
• Haskell
支持運算符重載的語言:
• Ada
• C++
• C#
• D
• Perl
• Python
• Pico(某種程度上)
• Pascal(僅Free Pascal Dialect)
• FreeBASIC
• Visual Basic(需要 Visual Basic .NET 2008 或更高版本)
不支持運算符重載的語言:
• C
• Delphi
• Java
• Objective-C
  • 目錄