2015-04-14 2 views
2

У меня есть класс с перегруженным оператором преобразования, как это:Последствия перегрузки оператора преобразования

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 

Предполагая, что это правильное поведение в соответствии со стандартом, как я знаю, что работает, а что нет (без проб и ошибок), и что более важно, почему это именно так ?

+0

Кстати, создание конструктора 'explicit' приведет к ошибке' pointer = pointer + 1; '. – molbdnilo

ответ

0

Некоторые из вышеперечисленных операций работают, потому что компилятор может преобразовать нестандартный тип: Pointer<MyClass> необработанному указателю: MyClass* неявно использовать ОДИНОЧНОЕ пользовательское преобразование. Существуют строгие правила для неявных преобразований, описанные here.

Неявные преобразования выполняются всякий раз, когда выражение некоторого типа Т1 используется в контексте, который не принимает этот тип, но принимает некоторый другой тип 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), operator== с операндом, который может быть неявно преобразован в MyClass*:

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

  • кейс (2), косвенный ()) принимает операнд, который может быть неявно преобразован в MyClass*, то ссылка структура (operator.):

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

  • не соответствует ни одному из случаев, operator-> не принимает каких-либо аргументов (ы), который может быть неявно конвертирована:

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

  • корпус (2): operator+ принимать операнд, который может быть неявно преобразован в MyClass* и назначить возврат значение - Pointer<MyClass> с использованием конструктора и operator=; обратите внимание, что добавление explicit в конструктор предотвращает компиляции, потому что тип возвращаемого значения выражения: pointer + 1 является MyClass*, поэтому конструктор принимает MyClass* неявно вызывается:

    pointer = pointer + 1; // works

  • не соответствует ни одному из случаев; обратите внимание, что даже явное преобразование в MyClass* (например,static_cast<MyClass*>(pointer)++) не поможет, потому что здесь нужна lvalue; обходной путь является: auto ptr = &(*pointer); ptr++;:

    pointer++; // doesn't work

Помните, что перегрузка оператора преобразования иногда может привести к возникновению опасных ситуаций, напр. MyClass* ptr = pointer; delete ptr; удалит основной ресурс, и компилятор даже не пожалуется.

+0

Почему 'pointer-> some_method();' требуется более одного неявного преобразования? 'pointer' может быть преобразован в' T * ', и этого должно быть достаточно, чтобы оператор работал – eyelash

+0

Добавление класса' operator-> 'to' Pointer' помогает: 'T * operator ->() {return object; } ' – pstanisz

Смежные вопросы