+ | - | * | / | % |
^ | & | | | ~ | ! |
= | > | < | += | -= |
*= | /= | %= | ^= | &= |
|= | >> | << | >>= | <<= |
== | != | >= | <= | && |
|| | ++ | -- | ->* | , |
-> | [] | () | 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)