重载转换运算符的后果
Consequences of overloading the conversion operator
我有一个 class 有一个像这样的重载转换运算符:
template <class T> class Pointer {
T* object;
public:
Pointer (T* object): object(object) {}
operator T* () { return object; }
};
我注意到一些我通常必须手动重载的运算符现在突然像 Pointer
一样工作 T*
但有些运算符不是:
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*
。
隐式转换有严格的规则,如 here.
所述
Implicit conversions are performed whenever an expression of some type
T1 is used in context that does not accept that type, but accepts some
other type T2, in particular:
(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
case (2), operator==
with operand which can be implicitly converted to MyClass*
:
if (pointer == &my_object) { /* ... */ } // works
情况(2),间接(operator*
)取操作数可以隐式转换为MyClass*
,然后结构引用(operator.
):
(*pointer).some_method (); // works
不匹配任何情况,operator->
不接受任何参数,可以隐式转换:
pointer->some_method (); // doesn't work
case (2): operator+
获取可以隐式转换为 MyClass*
的操作数,并使用构造函数将 return 值赋给 Pointer<MyClass>
和operator=
;请注意,将 explicit
添加到构造函数会阻止编译,因为 return 类型的表达式:pointer + 1
是 MyClass*
,因此隐式调用采用 MyClass*
的构造函数:
pointer = pointer + 1; // works
不符合任何一种情况;请注意,即使显式转换为 MyClass*
(例如 static_cast<MyClass*>(pointer)++
)也无济于事,因为这里需要左值;解决方法是:auto ptr = &(*pointer); ptr++;
:
pointer++; // doesn't work
请记住,重载转换运算符有时会导致危险情况,例如。 MyClass* ptr = pointer; delete ptr;
将删除基础资源,编译器甚至不会抱怨。
我有一个 class 有一个像这样的重载转换运算符:
template <class T> class Pointer {
T* object;
public:
Pointer (T* object): object(object) {}
operator T* () { return object; }
};
我注意到一些我通常必须手动重载的运算符现在突然像 Pointer
一样工作 T*
但有些运算符不是:
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*
。
隐式转换有严格的规则,如 here.
Implicit conversions are performed whenever an expression of some type T1 is used in context that does not accept that type, but accepts some other type T2, in particular:
(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
case (2),
operator==
with operand which can be implicitly converted toMyClass*
:if (pointer == &my_object) { /* ... */ } // works
情况(2),间接(
operator*
)取操作数可以隐式转换为MyClass*
,然后结构引用(operator.
):(*pointer).some_method (); // works
不匹配任何情况,
operator->
不接受任何参数,可以隐式转换:pointer->some_method (); // doesn't work
case (2):
operator+
获取可以隐式转换为MyClass*
的操作数,并使用构造函数将 return 值赋给Pointer<MyClass>
和operator=
;请注意,将explicit
添加到构造函数会阻止编译,因为 return 类型的表达式:pointer + 1
是MyClass*
,因此隐式调用采用MyClass*
的构造函数:pointer = pointer + 1; // works
不符合任何一种情况;请注意,即使显式转换为
MyClass*
(例如static_cast<MyClass*>(pointer)++
)也无济于事,因为这里需要左值;解决方法是:auto ptr = &(*pointer); ptr++;
:pointer++; // doesn't work
请记住,重载转换运算符有时会导致危险情况,例如。 MyClass* ptr = pointer; delete ptr;
将删除基础资源,编译器甚至不会抱怨。