+ | - | * | / | % |
^ | & | | | ~ | ! |
= | > | < | += | -= |
*= | /= | %= | ^= | &= |
|= | >> | << | >>= | <<= |
== | != | >= | <= | && |
|| | ++ | -- | ->* | , |
-> | [] | () | operator new | operator new[] |
operator delete | operator delete [] |
:: | . | .* | ? : |
sizeof | typeid | new | delete |
static_cast | dynamic_cast | const_cast | reinterpret_cast |
1.一元操作符可以是不帶參數的成員函數[1]或帶一個參數的非成員函數[1]。
2.二元操作符可以是帶一個參數的成員函數[1]或帶兩個參數的非成員函數[1]。
3.operator=、operator[]、operator()、operator->只能定義爲成員函數[1]。
4.operator->的返回值必須是一個指針或能使用->的對象。
5.重載 operator++ 和 operator-- 時帶一個 int 參數表示後綴,不帶參數表示前綴。
6.除 operator new 和 operator delete 外,重載的操作符參數中至少要有一個非內建數據類型。
7.x@y 搜索範圍爲:x 成員函數--> 全局函數/X所在名字空間中的函數/Y所在名字空間中的函數/X的友元函
數/Y的友元函數。
8.重載的的操作符應儘量模擬操作符對內建類型的行爲。
1.只將會改變第一個參數的值的操作符(如: +=)定義爲成員函數,而將返回一個新對象的操作符(如: +)定義爲非成員函數(並使用 += 來實現)。
2.只有非成員函數才能在左參數上實施性別轉換,如果需要進行轉換則應將操作符定義爲非成員函數。
3.對一元操作符, 爲避免隱式轉換最好將其重載爲成員函數。
4.對二元操作符, 爲能在左操作數上能進行和右操作數一樣的隱式轉換, 最好將其重載爲非成員函數。
5.爲了遵照使用習慣,operator>>、operator<< 應定義爲非成員函數。
6.重載 operator[] 之類的操作符, 應儘量提供 const 版本和非 const 版本。
7.關於將操作符定義爲成員或非成員可參考以下建議:
|
||||||||||||
|
8.如果默認操作符已經可以施用於你的型別上, 則應儘量避免重載此操作符. 如 operator, 、operator&(取地址) 等等.
1.爲什麼要重載 operator new ?
[改變行爲] 默認的分配器失敗時會拋出異常, 或許你想改變這種行爲.
2. operator new 的行爲
new 操作符(new 表達式, new operator, new expression): 通常我們調用 X * pX = new X 時使用的就是這個操作符, 它由語言內建, 不能重載, 不能改變其行爲. 它包括分配內存的 operator new 和調用構造函數的 placement new.
operator new :opeator new 是一個函數, void * operator new(size_t size) . 它分配指定大小的內存, 可以被重載, 可以添加額外的參數, 但第一個參數必須爲 size_t. operator new 除了被 new operator 調用外也可以直接被調用: void * rawMem = operator new(sizeof(X)).
placement new : placement new 在一塊指定的內存上使用構造函數, 包含頭文件 <new> 之後也可以直接使用 placement new: X * pX = new (rawMem) X. [2]
與 new operator 類似, 對於 delete operator, 也存在 operator delete: void operator delete(void *), 析構方法 pX->~X().
[operator new 的錯誤處理]
默認的 operator new 在內存分配失敗時將會拋出 std::bad_alloc 異常; nothrow new [3]
(X * pX = new (nothrow) X) 在內存分配失敗時將會返回 0 . 這種行爲可以通過設置 new-handler 來改變. new-handler 是一個回調函數指針, typedef void(*new_handler)(void). 通過 set_new_handler(new_handler) 函數設置回調句柄後, 如果分配內存失敗, operator new 將會不斷的調用 new-handler 函數, 直到找到足夠的內存爲止. 爲了避免死循環, new-handler 函數必須具備以下行爲之一:
(1).找到可用的內存.
(2).安裝其它的 new-handler 函數.
(3).卸除 new-handler, 即 set_new_hanlder(0), 這樣下此循環將恢復默認行爲拋出異常或返回 0.
(4).拋出異常.
(5).保存錯誤日誌, 退出程序.
3.準備重載 operator new
{
if(size == 0)
size = 1;
while(1)
{
... // allocate memery
if(allocate sucessfull)
return ... // return the pointer.
new_handler curhandler = set_new_handler(0);
set_new_handler(curhandler); // get current new handler
if(curhandler == 0)
(*curhandler)();
else
throw std::bad_alloc();
}
}
4.重載 operator new
[★ 用不同的參數重載 operator new]
通過使用不同的參數類型, 可以重載 operator new, 例如 :
{
...
}
X * pX = new (1, 2, 3) X;
{
...
}
X * pX = new (10) X;
Y * pY = new (10, 10) Y;
Z * pZ = new (10, 10, 10) Z;
...
void * operator new(size_t size, ...)
...
[★ 重載 class 專屬的 operator new]
爲某個 class 重載 operator new 時必須定義爲類的靜態函數[4], 因爲 operator new 會在類的對象被構建出來之前調用. 即是說調用 operator new 的時候還不存在 this 指針, 因此重載的 operator new 必須爲靜態的. 當然在類中重載 operator new 也可以添加額外的參數, 並可以使用默認值.另外, 和普通函數一樣, operator new 也是可以繼承的.
...
static void * operator new(size_t size); // ... (1)
static void * operator new(size_t size, int); // ... (2)
};
class Y : public X{
...
};
class Z : public X{
...
static void * operator new(size_t size); // ... (3)
};
X * pX1 = new X; // call (1)
X * pX2 = ::new X; // call default operator new
X * pX3 = new (0) X; // call (2)
Y * pY1 = new Y; // call (1)
Z * pZ1 = new Z; // call (3)
Z * pZ2 = ::new Z; // call default operator new
Z * pZ3 = X::new Z; // error, no way to call (1)
Z * pZ4 = new (0) Z; // error, no way to call (2)
5.重載 operator delete
如果在類中使用 operator delete, 也必須將其聲明爲靜態函數. 因爲調用 operator delete 時對象已經被析構掉了. operator delete 的重載可以有兩種形式:
(1) void operator delete(void * mem)
(2) void operator delete(void * mem, size_t size)
並且這兩種形式的 operator delete 可以同時存在, 當調用 delete px 時, 如果 (1) 式存在的話將調用 (1) 式. 只有在 (1) 式不存在時纔會調用 (2) 式. 對第 (2) 種形式的 operator delete, 如果用基類指針刪除派生類對象, 而基類的析構函數沒有虛擬的時候, size 的值可能是錯誤的.
展開全部
+ const Carrot operator+(const Carrot& lhs, const Carrot& rhs)
Carrot result = lhs;
return result += rhs;
}
【注】1. 如果可能, 應考慮使用 operator+= 來實現 operator+ .
2. operator+ 不能返回引用, 應返回值類型.
3. 爲了阻止形如 (a + b) = c 的調用, 應將返回值聲明爲 const .
· const Carrot operator-(const Carrot& lhs, const Carrot& rhs)
+ const Carrot operator*(const Carrot& lhs, const Carrot& rhs)
· const Carrot operator/(const Carrot& lhs, const Carrot& rhs)
· const Carrot operator%(const Carrot& lhs, const Carrot& rhs)
· const Carrot operator^(const Carrot& lhs, const Carrot& rhs)
+ const Carrot operator&(const Carrot& lhs, const Carrot& rhs)
· const Carrot operator|(const Carrot& lhs, const Carrot& rhs)
+ const Carrot Carrot::operator-() const
Carrot result = (*this);
... // chang the value to negative
return result;
}
【注】1. 一元操作符, 取負.
· const Carrot Carrot::operator~() const
· bool Carrot::operator!() const
· bool operator>(const Carrot& lhs, const Carrot& rhs)
· bool operator<(const Carrot& lhs, const Carrot& rhs)
+ Carrot& Carrot::operator=(const Carrot& rhs)
if(this == &rhs)
return *this; // may be (*this) == rhs if needs.
Barley::operator=(rhs); // if Carrot derived from Barley
... // assignments every memeber of Carrot.
return *this;
}
【注】1. 爲了實現形如 x=y=z=0 的串聯賦值操作, operator= 必須傳回 *this 的非常量引用.
2. 在賦值時應注意檢查是否爲自賦值 ( a = a ).
+ Carrot& Carrot::operator+=(const Carrot& rhs)
...
return *this;
}
【注】1. C++ 允許 (x += 1) = 0 形式的賦值操作, operator+= 必須傳回 *this 的非常量引用.
· Carrot& Carrot::operator-=(const Carrot& rhs)
· Carrot& Carrot::operator*=(const Carrot& rhs)
· Carrot& Carrot::operator/=(const Carrot& rhs)
· Carrot& Carrot::operator%=(const Carrot& rhs)
· Carrot& Carrot::operator^=(const Carrot& rhs)
· Carrot& Carrot::operator&=(const Carrot& rhs)
· Carrot& Carrot::operator|=(const Carrot& rhs)
+ istream& operator>>(istream& _IStr, Carrot& rhs)
...
return _IStr;
}
【注】1. 爲了遵照使用習慣(cin>>x 而不是 x>>cin), 對流操作的 operator>> 應爲非成員函數.
+ ostream& operator<<(ostream& _OStr, const Carrot& rhs)
...
return _OStr;
}
+ const Carrot operator>>(const Carrot& lhs, int rhs)
Carrot result = lhs;
...
return result;
}
【注】1. 移位操作的重載方式.
· const Carrot operator<<(const Carrot& lhs, int rhs)
+ Carrot& Carrot::operator>>=(int rhs)
...
return *this;
}
【注】1. 移位操作.
· Carrot& Carrot::operator<<=(int rhs)
+ bool operator==(const Carrot& lhs, const Carrot& rhs)
...
}
· bool operator!=(const Carrot& lhs, const Carrot& rhs)
· bool operator>=(const Carrot& lhs, const Carrot& rhs)
· bool operator<=(const Carrot& lhs, const Carrot& rhs)
+ bool operator&&(const Carrot& lhs, const Carrot& rhs) X
...
}
【注】1. 基於以下原因, 你應該避免重載 operator&& 和 operator|| :
(1). && 和 || 是一個邏輯操作符, 只對 bool 型別有才有明確的語意.
(2). 重載的 operator&& 和 operator|| 無法模擬操作符默認的驟死式語義[5].
(3). 你無法保證重載後操作符的參數求值次序(C++ Stand 保證了默認的 && 和 || 按從左到右求值).
2.自定義型別可以考慮提供到 bool 的轉型操作來支持此操作符.
· bool operator||(const Carrot& lhs, const Carrot& rhs) X
+ Carrot& Carrot::operator++()
(*this) += 1; // or other implement
return *this;
}
【注】1. 前置操作(prefix): ++carrot
+ const Carrot Carrot::operator++(int)
Carrot oldValue = *this;
++(*this);
return oldValue;
}
【注】1. 後置操作(postfix): carrot++ 調用時編譯器自動生成一個 0 作爲參數.
2. 爲了禁止 carrot++++ 操作, 返回值應爲 const.
3. 從實現和參數可以看出,後置操作的效率遠遠低於前置操作, 所以如非必要儘量使用前置操作.
4. 爲了保證遞增行爲一致, 並便於維護後置操作最好使用前置操作來完成遞增行爲.
· Carrot& Carrot::operator--()
· const Carrot Carrot::operator--(int)
+ const Carrot operator,(const Carrot& lhs, const Carrot& rhs) X
...
}
【注】1. 基於以下原因, 你應該避免重載 operator, :
(1). 即使沒有重載, 默認,號操作符也可以施用於自定義型別上.
(2). C++ 保證 , 操作符的求值是從左到右的, 而重載後無法保證此行爲.
+ const PMFC Carrot::operator->*(ReturnType (T::*pmf)()) const
+ const Carrot* Carrot::operator&() const X
...
}
【注】1. 你應該儘量避免重載取地址操作符.
+ Coca& Carrot::operator*()
...
}
【注】1. 重載提領操作符應提供 const 版和非 const 版.
· const Coca& Carrot::operator*() const
+ Coca* Carrot::operator->()
...
}
【注】1. 重載 operator-> 應提供 const 版和非 const 版.
2. operator-> 的返回值必須爲一個指針或可以應用 -> 操作的類型.
3. 如果 operator-> 的返回的不是一個指針, C++ 會繼續在返回類型上應用 -> 直到得到一個指針爲止.
· const Coca* Carrot::operator->() const
+ Coca& Carrot::operator[](KeyType index)
...
}
【注】1. operator[] 應提供 const 版本和非 const 版.
2. KeyType 可以爲任意類型, 但通常爲 int 型.
· const Coca& Carrot::operator[](KeyType index) const
+ AnyType Carrot::operator()(...)
...
}
【注】1. operator () 重載的是函數運算符, 改變表達式優先級的 () 是不能重載的.
2. 重載了 operator() 的對象被成爲仿函數, 使用方法和函數指針類似.
+ static void* Carrot::operator new(size_t size, ...)
if(size == 0)
size = 1;
while(1)
{
... // allocate memery
if(allocate sucessfull)
return ... // return the pointer.
new_handler curhandler = set_new_handler(0);
set_new_handler(curhandler); // get current new handler
if(curhandler == 0)
(*curhandler)();
else
throw std::bad_alloc();
}
· static void* Carrot::operator new[](size_t size, ...)
+ static void Carrot::operator delete(void * memory, size_t size)
· static void Carrot::operator delete[](void * momery, size_t size)
▲注:
inline void *__cdecl operator new(size_t, void *_Where) _THROW0()
{ // construct array with placement at _Where
return (_Where);
}
struct nothrow_t
{ // placement new tag type to suppress exceptions
};
extern const nothrow_t nothrow; // constant for placement new tag
...
void *__cdecl operator new(size_t, const std::nothrow_t&)
_THROW0();
if( (p != NULL) && strlen(p) < 10 )...
如果 p == NULL, strlen 就不會被調用. 但是重載的 operator&& 和 operator|| 是作爲一個函數, 要在所有的參數求值完成後纔會調用此操作符.←
▲參考資料:
2. Scott Meyers.Effective C++(2nd Edition)
3. Andrei Alexandrescu.Modern C++ Design
4. Robert B.Murray.C++ Strategies and Tactics
5. Scott Meyers.More Effective C++
6. John Lakos.Large-Scale C++ Software Design
7. Scott Meyers.Implementing operator->* for Smart Pointers