Как создать и использовать оператор стрелки класса?

Итак, после исследования повсюду для этого я не могу найти, как создать оператор стрелки класса, т.е.

class Someclass
{
  operator-> ()  /* ? */
  {
  }
};

Мне просто нужно знать, как с ним работать и правильно его использовать. - каковы его входы? - что возвращает? - как мне правильно объявить/прототипировать его?


person Codesmith    schedule 08.02.2011    source источник
comment
нет входов. Тип возвращаемого значения должен быть указателем. Обычно это используется для создания интеллектуальных указателей, поэтому он возвращает указатель на обернутый объект.   -  person Tim    schedule 08.02.2011


Ответы (4)


Оператор -> используется для перегрузки доступа к членам. Небольшой пример:

#include <iostream>
struct A 
{
    void foo() {std::cout << "Hi" << std::endl;}
};

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

int main() {
    B b;
    b->foo();
}

Это выводит:

Hi
person gr0v3r    schedule 08.02.2011
comment
оператор стрелки также работает для возврата членов структуры, как и членов класса? - person Codesmith; 08.02.2011
comment
Он может возвращать члены структуры так же легко, как и члены класса. Что происходит, когда вы используете стрелку, определяется телом функции-члена operator-›(). Возврат строки можно изменить, чтобы возвращать то, что вы считаете подходящим. - person Darryl; 08.02.2011

Оператор стрелки не имеет входных данных. Технически он может возвращать все, что вы хотите, но он должен возвращать что-то, что либо является указателем, либо может стать указателем через цепочки операторов ->.

Оператор -> автоматически разыменовывает возвращаемое значение перед вызовом своего аргумента, используя встроенную разыменовку указателя, а не operator*, поэтому у вас может быть следующий класс:

class PointerToString
{
    string a;

public:
    class PtPtS
    {
    public:
        PtPtS(PointerToString &s) : r(s) {}
        string* operator->()
        {
            std::cout << "indirect arrow\n";
            return &*r;
        }
    private:
        PointerToString & r;
    };

    PointerToString(const string &s) : a(s) {}
    PtPtS operator->()
    {
        std::cout << "arrow dereference\n";
        return *this;
    }
    string &operator*()
    {
        std::cout << "dereference\n";
        return a;
    }
};

Используйте это как:

PointerToString ptr(string("hello"));
string::size_type size = ptr->size();

который преобразуется компилятором в:

string::size_type size = (*ptr.operator->().operator->()).size();

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

arrow dereference
indirect dereference
dereference

Однако обратите внимание, что вы можете сделать следующее:

PointerToString::PtPtS ptr2 = ptr.operator->();

запустить онлайн: https://wandbox.org/permlink/Is5kPamEMUCA9nvE

Из Строупструпа:

Преобразование объекта p в указатель p.operator->() не зависит от члена, на который указывает m. В этом смысле operator->() является унарным постфиксным оператором. Однако новый синтаксис не введен, поэтому после -> по-прежнему требуется имя элемента.

person Daniel Gallagher    schedule 08.02.2011
comment
Этот код никак не скомпилируется приличным компилятором. - person Sebastian Redl; 30.03.2015
comment
@SebastianRedl, ты прав. Я обновил объяснение и пример, чтобы он компилировался. - person Daniel Gallagher; 03.04.2015
comment
Интересно, а какой смысл в ненужной косвенности? почему бы просто не вернуть ссылку на базовый объект? (ссылка string a в вашем случае). Зачем усложнять простые вещи? Я бы понизил ваш голос за усложнение, но сначала у вашего подхода должна быть причина. - person metablaster; 24.04.2020

class T {
    public:
        const memberFunction() const;
};

// forward declaration
class DullSmartReference;

class DullSmartPointer {
    private:
        T *m_ptr;
    public:
        DullSmartPointer(T *rhs) : m_ptr(rhs) {};
        DullSmartReference operator*() const {
            return DullSmartReference(*m_ptr);
        }
        T *operator->() const {
            return m_ptr;
        }
};

http://en.wikibooks.org/wiki/C++_Programming/Operators/Operator_Overloading#Address_of.2C_Reference.2C_and_Pointer_operators

person Anycorn    schedule 08.02.2011

Оператор "стрелка" может быть перегружен:

a->b

будет переведено на

return_type my_class::operator->()
person Foo Bah    schedule 08.02.2011
comment
Это не так просто, return_type{}->()->()->() ... ->() должен быть указателем, чтобы это был действительный код. - person alfC; 13.05.2017