操作符重载
1.有四个操作符不允许重载,它们是:: .* . ?:
2.程序员只能为类类型或枚举类型的操作数定义重载操作符
3.除了operator()之外,对其他重载操作符提供缺省实参都是非法的
4.c++要求,=,[],()和->四个操作符必须被定义为类成员操作符,否则会编译错误
5.操作符->被重载为一元操作符,即它没有参数。比如如下代码:
class Aptr{
public:
A* operator->(){return ptr;}
};
Aptr p;
那么就可以用p->a;来访问类A的成员变量a。
class Aptr{
public:
A* operator->(){return ptr;}
};
Aptr p;
那么就可以用p->a;来访问类A的成员变量a。
6.operator new()和new表达式的区别。
c++primer上多次提到new操作符和new表达式。google一下,似乎是这样的,我们平时写下的new A();其实是一个new表达式,这个表达式会做两件事情: 调用operator new()分配空间;调用构造函数初始化对象。从这里也可以看出,我们在重载new操作符时只要分配空间即可,无须为其调用构造函数或者进行初始化。同理,operator delete()也只需要释放空间即可,delete表达式会先调用析构函数,然后调用delete操作符。
c++primer上多次提到new操作符和new表达式。google一下,似乎是这样的,我们平时写下的new A();其实是一个new表达式,这个表达式会做两件事情: 调用operator new()分配空间;调用构造函数初始化对象。从这里也可以看出,我们在重载new操作符时只要分配空间即可,无须为其调用构造函数或者进行初始化。同理,operator delete()也只需要释放空间即可,delete表达式会先调用析构函数,然后调用delete操作符。
7.delete操作符重载的参数。
delete操作符重载返回值必须为void,但是参数可以有两种形式:(void *)或者(void *, size_t)。如果为后者,则编译器会自动将第二个参数设置为对象大小。经过测试,如果两个形式都提供,delete表达式似乎会调用一个参数的那个。
实际上,delete操作符还可以重载为其他形式,参数表也可以任意,只是第一个参数必须为void *。而且由delete表达式调用的只能是前面两种形式。虽然不能被delete表达式隐式调用,但是重载的delete操作符还是非常有用,因为它可以被异常处理代码隐式调用。有时new操作符分配空间会失败,这时会抛出一个异常,如何保证new操作符所作的操作被撤销呢?这种情况下,编译器会自动寻找与所调用的new操作符参数表相同的delete操作符,并且调用它,注意这里所说的参数表相同不包括第一个参数,因为new第一个参数总是size_t,而delete总是void *。一般来说,如果用户提供了定位new操作符的重载版本,也应该提供同参数表的delete,以便在分配失败的时候撤销所作的操作。
delete操作符重载返回值必须为void,但是参数可以有两种形式:(void *)或者(void *, size_t)。如果为后者,则编译器会自动将第二个参数设置为对象大小。经过测试,如果两个形式都提供,delete表达式似乎会调用一个参数的那个。
实际上,delete操作符还可以重载为其他形式,参数表也可以任意,只是第一个参数必须为void *。而且由delete表达式调用的只能是前面两种形式。虽然不能被delete表达式隐式调用,但是重载的delete操作符还是非常有用,因为它可以被异常处理代码隐式调用。有时new操作符分配空间会失败,这时会抛出一个异常,如何保证new操作符所作的操作被撤销呢?这种情况下,编译器会自动寻找与所调用的new操作符参数表相同的delete操作符,并且调用它,注意这里所说的参数表相同不包括第一个参数,因为new第一个参数总是size_t,而delete总是void *。一般来说,如果用户提供了定位new操作符的重载版本,也应该提供同参数表的delete,以便在分配失败的时候撤销所作的操作。
8.new操作符重载的参数
与delete一样,new操作符也可以有各种参数表,但是有一个要求是它的第一个参数必须是size_t类型。与delete不同的是,new操作符的各种形式都可以通过new表达式隐式调用,这些参数可以通过参数表传进去,例如:
new(4) A;
就会调用void *A::operator new(size_t, int);这个函数。定位new操作符其实只是其中的一种特例,就是参数表如(size_t, void *)类型的new操作符重载
与delete一样,new操作符也可以有各种参数表,但是有一个要求是它的第一个参数必须是size_t类型。与delete不同的是,new操作符的各种形式都可以通过new表达式隐式调用,这些参数可以通过参数表传进去,例如:
new(4) A;
就会调用void *A::operator new(size_t, int);这个函数。定位new操作符其实只是其中的一种特例,就是参数表如(size_t, void *)类型的new操作符重载
9.重载new和delete操作符都是静态函数。因为它们发生在对象构造之前和析构之后,无法与具体的对象相关联。
10.类型转换函数 operator type()中type可以是类类型,内置类型或typedef类型,但是不能是数组或函数,且转换函数必须是类成员函数,它不能带有任何的参数和返回值,默认参数也不可以,注意这里没有返回值不代表不能使用return,应该认为返回值已经被指定,必须是转换的目标类型。
11.调用operator type() 并不要求目标类型于type精确匹配,只要目标类型可以通过一系列标准类型转换到达即可,也就是说,假如我们只为类A声明了operator int()而没有operator double(),那么A a; a+3.14会先转换为int类型,然后在通过标准类型转换转换为double类型。还要注意,这里是通过一系列标准转换,在一次自定义转换之后就不会再隐式调用自定义转换了,希望通过类A隐式转换为B再隐式转换为int的写法是无法编译通过的。
以上条款对于通过构造函数进行的类型转换同样适用。
以上条款对于通过构造函数进行的类型转换同样适用。
12."->"操作符重载没有参数,返回类型必须是一个类类型指针或者是重载了"->"的一个类的对象,然后会对返回值继续调用->操作符,直到得出最终结果。例如:
class D{
public:
D():ddd(43){};
int ddd;
};
class D{
public:
D():ddd(43){};
int ddd;
};
class C{
public:
D d;
D* operator->(){return &d;}
};
class A{
public:
C operator->(){return C();}
};
public:
D d;
D* operator->(){return &d;}
};
class A{
public:
C operator->(){return C();}
};
对于A的对象a,表达式a->ddd访问的是临时对象C中的成员d的成员ddd,其中调用了两次重载的->操作符,还调用了一次类对象指针的->操作符。