2014-02-05 7 views
16

Я относительно новичок в C++, все еще пытаюсь получить синтаксис. Я рассматриваю несколько примеров перегрузки операторов, а в последнее время - реализации интеллектуальных указателей. Вот действительно общий пример я смотрю на:Перегрузка операторов разыменования C++

template < typename T > class SP 
{ 
    private: 
    T* pData; // Generic pointer to be stored 
    public: 
    SP(T* pValue) : pData(pValue) 
    { 
    } 
    ~SP() 
    { 
     delete pData; 
    } 

    T& operator*() 
    { 
     return *pData; 
    } 

    T* operator->() 
    { 
     return pData; 
    } 
}; 

При перегрузке оператора разыменования почему тип T &? Аналогичным образом, при перегрузке разложения структуры, почему это тип T *?

+4

'* p = 2' часто желаемый синтаксис. Было бы обидно, если бы он ничего не сделал. – chris

+0

Люди обычно, по крайней мере, пытаются подделать согласованность с перегрузками. C++ 11 5.3.1p1 [expr.unary.op] выдает оператор '*' для типов указателей, и его не редкость имитировать (включая перегрузки для 'const', если вы хотите запустить полный гамбит). – WhozCraig

ответ

6

Целью оператора разыменования является разыменование указателя и возврат ссылки на объект. Следовательно, он должен вернуть ссылку. Вот почему это T &.

Назначение оператора ссылки (->) - вернуть указатель и, следовательно, вернуть T *.

+0

Я думаю, что этот вопрос проистекает из идеи, что «цель operator-> - вернуть указатель» является контринтуитивной. Путаница в том, что: «(* x)». и "x->" оба в конечном счете разыгрывают x и получают доступ к элементу разыменованного указателя. Таким образом, тот факт, что один оператор «должен» вернуть указатель, а другой, ссылка не сразу очевидна. – johnb003

29

Оператор разыменования (*) перегрузка работает как любая другая перегрузка оператора. Если вы хотите изменить значение разыменования, вам нужно вернуть неконстантную ссылку. Таким образом, *sp = value фактически изменит значение, на которое указывает sp.pData, а не временное значение, сгенерированное компилятором.

Оператор разукрупнения структуры (->) Перегрузка - это особый случай перегрузки оператора. Оператор фактически вызывается в цикле до тех пор, пока не будет возвращен реальный указатель, а затем этот реальный указатель будет разыменован. Я предполагаю, что это был единственный способ, которым они могли придумать, чтобы реализовать его, и это оказалось немного хаки. Однако у него есть некоторые интересные свойства. Предположим, вы имели следующие классы:

struct A { 
    int foo, bar; 
}; 

struct B { 
    A a; 
    A *operator->() { return &a; } 
}; 

struct C { 
    B b; 
    B operator->() { return b; } 
}; 

struct D { 
    C c; 
    C operator->() { return c; } 
}; 

Если у вас объект d типа D, вызывая d->bar бы сначала вызвать D::operator->(), затем C::operator->(), а затем B::operator->(), который, наконец, возвращает реальный указатель на структуру A, и его bar Элемент разыменовывается обычным образом. Следует отметить, что в следующем:

struct E1 { 
    int foo, bar; 
    E1 operator->() { return *this; } 
}; 

Вызов e->bar, где e имеет тип E1, производит бесконечную петлю. Если вы хотите на самом деле разыменовать e.bar, вам нужно будет сделать это:

struct E2 { 
    int foo, bar; 
    E2 *operator->() { return this; } 
}; 

Резюмируя:

  1. При перегрузке оператора разыменования, тип должен быть T&, потому что это необходимо изменить значение, на которое указывает pData.
  2. При перегрузке разыменования структуры тип должен быть T*, потому что этот оператор является особым случаем, и именно так оно и работает.
+2

Не следует возвращать a; 'быть' return & a; '? –

+0

@RadonRosborough: Да, спасибо! Исправлена. – Matt

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