简体   繁体   中英

Consequences of overloading the conversion operator

I have a class with an overloaded conversion operator like this:

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

I noticed that some operators that I would normally have to manually overload now suddenly work as if Pointer were a T* but some operators don'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

Assuming this is correct behaviour according to the standard, how do I know what works and what doesn't (without trial and error) and more importantly, why is it that way?

Some of above operations work because compiler can convert custom type: Pointer<MyClass> to raw pointer: MyClass* implicitly using SINGLE user-defined conversion. There are strict rules for implicit conversions, described 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) 

Some investigation with above example, I'll be grateful if someone could verify or correct my deductions.

  • case (5), if statement:

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

  • case (2), operator== with operand which can be implicitly converted to MyClass* :

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

  • case (2), indirection ( operator* ) taking operand which can be implicitly converted to MyClass* , then structure reference ( operator. ):

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

  • does not match any of cases, operator-> does not take any argument(s), which can be implicitly converted:

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

  • case (2): operator+ taking operand which can be implicitly converted to MyClass* and assign return value to Pointer<MyClass> using constructor and operator= ; note that adding explicit to constructor prevents from compiling because return type of expression: pointer + 1 is MyClass* , so constructor taking MyClass* is implicitly called:

    pointer = pointer + 1; // works

  • does not match any of cases; note that even explicit convertion to MyClass* (ex. static_cast<MyClass*>(pointer)++ ) won't help, because lvalue is needed here; the workaround is: auto ptr = &(*pointer); ptr++; auto ptr = &(*pointer); ptr++; :

    pointer++; // doesn't work

Remember, that overloading the conversion operator could sometimes lead to dangerous situations, ex. MyClass* ptr = pointer; delete ptr; will delete underlying resource and compiler won't even complain.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM