C++里的重载包括了函数重载和运算符重载。
先明确一下重载函数的定义:在相同的声明域中的函数名相同的,而参数表不同的,即通过函数的参数表而唯一标识并且来区分函数的一种特殊的函数。
再看看运算符重载:C++中预定义的运算符的操作对象只能是基本数据类型。但实际上,对于许多用户自定义类型(例如类),也需要类似的运算操作。这时就必须在C++中重新定义这些运算符,赋予已有运算符新的功能,使它能够用于特定类型执行特定的操作。
实质上,运算符也可以看成是函数。运算符重载的实质也是函数重载。
运算符重载是通过创建运算符函数实现的。运算符函数的定义与其他函数的定义类似,惟一的区别是运算符函数的函数名是由关键字operator和其后要重载的运算符符号构成的。运算符函数定义的一般格式如下:
<返回类型说明符> operator <运算符符号>(<参数表>)
{
函数体
}
不能重载运算符的包括:
. .* :: ?:
new delete sizeof typeid
static_cast dynamic_cast const_cast reinterpret_cast
其他的运算符可以重载,它们包括了:
operator new operator delete
operator new[] operator delete[]
+ - * / % ^ & | ~
! = < > += -= *= /= %=
^= &= |= << >> >>= <<= == !=
<= >= && || ++ -- , ->* ->
() []
运算符有两种重载形式:成员函数形式和友元函数形式。这两种形式都可访问类中的私有成员。
1.运算符重载为类的成员函数的一般格式为:
函数类型 operator 运算符 (参数表)
{
函数体
}
当运算符重载为类的成员函数时,函数的参数个数比原来的操作数要少一个(后置单目运算符除外),这是因为成员函数用this指针隐式地访问了类的一个对象,它充当了运算符函数最左边的操作数。
<对象名>.operator <运算符>(<参数>) 它等价于
<对象名><运算符><参数>
例如:a+b等价于a.operator +(b)。
2.运算符重载为类的友元函数的一般格式为:
friend 函数类型 operator 运算符(参数表)
{
函数体
}
当运算符重载为类的友元函数时,由于没有隐含的this指针,因此操作数的个数没有变化,所有的操作数都必须通过函数的形参进行传递,函数的参数与操作数自左至右一一对应。
调用友元函数运算符的格式如下:
operator <运算符>(<参数1>,<参数2>) 它等价于
<参数1><运算符><参数2>
例如:a+b等价于operator +(a,b)。
一个操作符一般既可以作为类的成员函数,也可以作为类的友元函数来定义,但是成员函数运算符和友元函数运算符也各自有一些自身的特点:
(1) 一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函数。
(2) 以下一些双目运算符不能重载为类的友元函数:=、()、[]、->。
(3) 类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。
(4) 若一个运算符的操作需要修改对象的状态,选择重载为成员函数较好。
(5) 若运算符所需的操作数(尤其是第一个操作数)希望有隐式类型转换,则只能选用友元函数。
(6) 当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一 个类对象(或者是对该类对象的引用)。如果左边的操作数必须是一个不同类的对象,或者是一个内部 类型的对象,该运算符函数必须作为一个友元函数来实现。
(7) 当需要重载运算符具有可交换性时,选择重载为友元函数。
我们特别要提及的是new,delete,new[] 和delete[]。
1.当我们写下这样的代码:string *ps = new string("Memory Management");
我们使用的new是new操作符。这个操作符就象sizeof一样是语言内置的,你不能改变它的含义,它的功能总是一样的。它要完成的功能分成两部分。第一部分是分配足够的内存以便容纳所需类型的对象。第二部分是它调用构造函数初始化内存中的对象。new操作符总是做这两件事情,你不能以任何方式改变它的行为。
你所能改变的是如何为对象分配内存。new操作符调用一个函数来完成必需的内存分配,你能够重写或重载这个函数来改变它的行为。new操作符为分配内存所调用函数的名字是operator new。
你一般不会直接调用operator new函数,但是一旦这么做,你可以象调用其它函数一样调用它:
void *rawMemory = operator new(sizeof(string));
操作符operator new将返回一个指针,指向一块足够容纳一个string类型对象的内存。就象malloc一样,operator new的职责只是分配内存。它对构造函数一无所知。
我们所谓的重载new,其实不是重载那个new操作符,而是重载operator new 函数。注意到上面红色字体所写的吗?根据那个定义,new应该是个运算符,而operator new组成了一个函数。函数operator new 通常这样声明:
void * operator new(size_t size);
2.同理:当我们使用delete操作符时,它的功能也包括两部分,首先是调用对象的析构函数,然后是调用operator delete函数来释放掉对象所占的内存。我们所谓的重载delete,其实也不是重载那个delete操作符,而是重载了operator delete函数。 函数operator delete 通常这样声明:
void operator delete(void *memoryToBeDeallocated);
3. 我们看这样的代码string *ps = new string[10];
被使用的new仍然是new操作符,但是建立数组时new操作符的行为与单个对象建立有少许不同。第一是内存不再用operator new分配,代替以等同的数组分配函数,叫做operator new[](经常被称为array new)。它与operator new 一样能被重载。
operator new[]
4.同理:
void operator delete[](void* memoryToBeDeallocated)
再有: new操作符是通过全局::operator new()来实现的,重载是重载operator new, 而不是new操作符
两种情况:
1, 控制内存泄露
2, 内存池