转换运算符过载的后果

Consequences of overloading the conversion operator

本文关键字:后果 运算符 转换      更新时间:2023-10-16

我有一个类有一个重载的转换运算符,如下所示:

template <class T> class Pointer {
T* object;
public:
Pointer (T* object): object(object) {}
operator T* () { return object; }
};

我注意到,一些我通常必须手动过载的操作员现在突然工作起来,就好像PointerT*,但有些操作员不是:

MyClass my_object;
Pointer<MyClass> pointer (&my_object);
if (pointer) { /* ... */ } // works
if (pointer == &my_object) { /* ... */ } // works
(*pointer).some_method (); // works
pointer->some_method (); // doesn't work
pointer = pointer + 1; // works
pointer++; // doesn't work

假设根据标准这是正确的行为,我怎么知道什么有效,什么无效(没有反复试验),更重要的是,为什么会这样?

上面的一些操作之所以有效,是因为编译器可以使用SINGLE用户定义的转换将自定义类型Pointer<MyClass>隐式转换为原始指针MyClass*。这里介绍了隐式转换的严格规则。

每当某个类型的表达式T1用于不接受该类型但接受某些类型的上下文其他类型T2,特别是:

(1) When the expression is used as the argument when calling a function that is declared with T2 as parameter.
(2) When the expression is used as an operand with an operator that expects T2
(3) When initializing a new object of type T2, including return statement in a function returning T2.
(4) When the expression is used in a switch statement (T2 is integral type)
(5) When the expression is used in an if statement or a loop (T2 is bool)

上面例子的一些调查,如果有人能核实或更正我的扣除额,我将不胜感激。

  • 情况(5),if语句:

    if (pointer) { /* ... */ } // works

  • 情况(2),具有可隐式转换为MyClass*:的操作数的operator==

    if (pointer == &my_object) { /* ... */ } // works

  • 情况(2),间接(operator*)取可隐式转换为MyClass*的操作数,然后结构引用(operator.):

    (*pointer).some_method (); // works

  • 与任何情况都不匹配,operator->不接受任何参数,这些参数可以隐式转换:

    pointer->some_method (); // doesn't work

  • 情况(2):operator+取可隐式转换为MyClass*的操作数,使用构造函数和operator=Pointer<MyClass>赋值;注意,将explicit添加到构造函数中会阻止编译,因为表达式的返回类型:pointer + 1MyClass*,所以采用MyClass*的构造函数被隐式调用:

    pointer = pointer + 1; // works

  • 与任何情况都不匹配;注意,即使显式转换为MyClass*(例如static_cast<MyClass*>(pointer)++)也无济于事,因为这里需要左值;解决方法是:auto ptr = &(*pointer); ptr++;:

    pointer++; // doesn't work

请记住,重载转换运算符有时会导致危险的情况,例如MyClass* ptr = pointer; delete ptr;会删除底层资源,编译器甚至不会抱怨。