+ | - | * | / | % |
^ | & | | | ~ | ! |
= | > | < | += | -= |
*= | /= | %= | ^= | &= |
|= | >> | << | >>= | <<= |
== | != | >= | <= | && |
|| | ++ | -- | ->* | , |
-> | [] | () | operator new | operator new[] |
operator delete | operator delete [] |
:: | . | .* | ? : |
sizeof | typeid | new | delete |
static_cast | dynamic_cast | const_cast | reinterpret_cast |
operator=、operator[]、operator()、operator->只能定義爲成員函數[1]。安全
operator->的返回值必須是一個指針或能使用->的對象。函數
重載 operator++ 和 operator-- 時帶一個 int 參數表示後綴,不帶參數表示前綴。this
除 operator new 和 operator delete 外,重載的操做符參數中至少要有一個非內建數據類型。spa
x@y 搜索範圍爲:x 成員函數--> 全局函數/X所在名字空間中的函數/Y所在名字空間中的函數/X的友元函數/Y的友元函數。.net
重載的的操做符應儘可能模擬操做符對內建類型的行爲。指針
只將會改變第一個參數的值的操做符(如: +=)定義爲成員函數,而將返回一個新對象的操做符(如: +)定義爲非成員函數(並使用 += 來實現)。日誌
只有非成員函數才能在左參數上實施性別轉換,若是須要進行轉換則應將操做符定義爲非成員函數。orm
對一元操做符, 爲避免隱式轉換最好將其重載爲成員函數。
對二元操做符, 爲能在左操做數上能進行和右操做數同樣的隱式轉換, 最好將其重載爲非成員函數。
爲了遵守使用習慣,operator>>、operator<< 應定義爲非成員函數。
重載 operator[] 之類的操做符, 應儘可能提供 const 版本和非 const 版本。
關於將操做符定義爲成員或非成員可參考如下建議:
|
||||||||||||
|
若是默認操做符已經能夠施用於你的型別上, 則應儘可能避免重載此操做符. 如 operator, 、operator&(取地址) 等等.
爲何要重載 operator new ?
[效率問題] 一般系統默認提供的分配器速度極慢, 並且分配小型對象時空間浪費嚴重.
[改變行爲] 默認的分配器失敗時會拋出異常, 或許你想改變這種行爲.
perator new 的行爲
[區分三個不一樣的 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 函數必須具有如下行爲之一:
找到可用的內存.
安裝其它的 new-handler 函數.
卸除 new-handler, 即 set_new_hanlder(0), 這樣下此循環將恢復默認行爲拋出異常或返回 0.
拋出異常.
保存錯誤日誌, 退出程序.
準備重載 operator new
重載 operator new 時須要兼容默認的 operator new 錯誤處理方式. 另外, C++ Standard 規定當要求的內存爲 0 byte 時也應該返回有效的內存地址. 因此 operator new 的重載實現應大體以下:
重載 operator delete 簡單許多, 只需注意 C++ Standard 要求刪除一個 NULL 是安全的便可.
void * ... 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();
}
}
重載 operator new
opeator new 的重載和其它操做符大不相同. 首先, 即便你不重載, 默認的 operator new 也可施用於你的自定義型別上(operator, 也具備此特性), 而其它操做符若是不進行重載就沒法使用. 其次, 其它重載其它操做符時參數個數都是固定的, 而 operator new 的參數個數是能夠任意的, 只須要保證第一個參數爲 size_t, 返回類型爲 void * 便可, 並且其重載的參數類型也沒必要包含自定義類型. 更通常的說, operator new 的重載更像是一個函數的重載, 而不是一個操做符的重載.
[★ 用不一樣的參數重載 operator new]
經過使用不一樣的參數類型, 能夠重載 operator new, 例如 :
你還能夠爲 operator new 的重載使用默認值, 其原則和普通函數重載同樣, 只要不形成和已存在的形式發生衝突便可. 可能你已經想到了, 你甚至還能夠在 operator new 中使用不定參數, 若是你真的須要的話.
在全局空間中也可直接重載 void * operator new(size_t size) 函數, 這將改變全部默認的 new 操做符的行爲, 不建議使用.
[★ 重載 class 專屬的 operator new]
爲某個 class 重載 operator new 時必須定義爲類的靜態函數[4], 由於 operator new 會在類的對象被構建出來以前調用. 便是說調用 operator new 的時候還不存在 this 指針, 所以重載的 operator new 必須爲靜態的. 固然在類中重載 operator new 也能夠添加額外的參數, 並可使用默認值.另外, 和普通函數同樣, operator new 也是能夠繼承的.
class X{
...
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)
void * operator new( size_t size, int x, int y = 0, int z = 0)
{
...
}
X * pX = new (10) X;
Y * pY = new (10, 10) Y;
Z * pZ = new (10, 10, 10) Z;
...
void * operator new(size_t size, ...)
...
void * operator new(size_t size, int x, int y, int z)
{
...
}
X * pX = new (1, 2, 3) X;
重載 operator delete
若是你重載了一個 operator new, 記得必定要在相同的範圍內重載 operator delete. 由於你分配出來的內存只有你本身才知道如何釋放. 若是你忘記了, 編譯器不會給你任何提示, 它將會使用默認的 operator delete 來釋放內存. 這種忘記的代價是慘重的, 你得時刻在寫下 operator new 的同時寫下 operator delete.
若是在類中使用 operator delete, 也必須將其聲明爲靜態函數. 由於調用 operator delete 時對象已經被析構掉了. operator delete 的重載能夠有兩種形式:
而且這兩種形式的 operator delete 能夠同時存在, 當調用 delete px 時, 若是 (1) 式存在的話將調用 (1) 式. 只有在 (1) 式不存在時纔會調用 (2) 式. 對第 (2) 種形式的 operator delete, 若是用基類指針刪除派生類對象, 而基類的析構函數沒有虛擬的時候, size 的值多是錯誤的.
void operator delete(void * mem)
void operator delete(void * mem, size_t size)