разъяснение по поводу перегрузки оператора -> - PullRequest
0 голосов
/ 13 декабря 2018

Я пытаюсь понять, как работает перегрузка -> оператор.У меня есть следующие классы

class Message {

public:
    Message(string message) :m_text(message) {}
    void printText() {
        cout << "text is " << m_text << endl;
    }
    string m_text;
};


class MessagePointerWrapper
{
public:

    MessagePointerWrapper(string message)  {
        m_message = std::make_unique<Message>(message);
    }

    Message* operator->() {

        return m_message.get();
    }

    std::unique_ptr<Message> m_message;

};

int main(int argc, char** argv)
{

    MessagePointerWrapper messageWrapper =  MessagePointerWrapper("Hello World");
    messageWrapper.m_message->printText();
    messageWrapper->m_text = "PQR";
    messageWrapper.m_message->printText();
}

Оператор -> класса MessageWrapper перегружен, чтобы вернуть Message*.Так что в методе main, когда я вызываю messageWrapper->, он возвращает Message*.Обычно, когда у меня есть указатель, мне нужно использовать оператор -> или оператор deference для доступа к объекту.Согласно этой логике, чтобы получить доступ к m_text проверяемому объекту Message, код должен быть написан следующим образом:

(messageWrapper->)   // this returns a pointer to Message. so to access the object, I should write as
(messageWrapper->)->m_text = "PQR"

или

*(messageWrapper->).m_Text = "PQR"

, но это не работаеттаким образом, и мне нужно назвать это

messageWrapper->m_text = "PQR";

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

==============

Некоторые дополнительные примечания:

В основном методе Iвидел, как два приведенных ниже метода делают одно и то же

messageWrapper.operator->()->m_text = "JKH";

messageWrapper->m_text = "JKH";

означает ли это, что оператор -> работает не так, как другие операторы, где это означает, что

messageWrapper-> эквивалентно (messageWrapper.operator->())-> ине messageWrapper.operator->(), как в случае других операторов.

Ответы [ 4 ]

0 голосов
/ 13 декабря 2018

-> - бинарный оператор, он работает с обоими аргументами и будет продолжать разрешать левую часть, пока он не является указателем.

То есть в следующем коде после вызоваWrapper2 :: operator -> () компилятор видит, что возвращаемый тип является ссылкой, и вызывает Wrapper1 :: operator ->, только тогда вызов приводит к указателю, и 'm' разрешается для RealType.

struct RealType
{
    int m;
};

class Wrapper1 {
    RealType rt;

public:
    RealType * operator ->() { return &rt; }
};
class Wrapper2 {
    Wrapper1 w1;

public:
    Wrapper1 & operator->() { return w1; }
};

int main()
{
    Wrapper2 w;
    w->m = 1;
};
0 голосов
/ 13 декабря 2018

Стандарт гласит:

13.5.6 Доступ к элементу класса

Выражение x->m интерпретируется как (x.operator->())->m для объекта класса x типа T, если существует T::operator->() и если оператор выбран в качестве функции наилучшего соответствия с помощью механизма разрешения перегрузки

0 голосов
/ 13 декабря 2018

Как указано в стандарте, [over.ref] / 1

Выражение x->m интерпретируется как (x.operator->())->m для объекта класса x типаT, если T::operator->() существует и если оператор выбран в качестве функции наилучшего соответствия с помощью механизма разрешения перегрузки

Это означает, что messageWrapper->m_text является синтаксическим сахаром (messageWrapper.operator->())->m_text.Вы можете применить последний стиль явно, но первый более эффективен.Перегруженный operator-> позволяет использовать класс как необработанные указатели, и именно так работают умные указатели, такие как std::unique_ptr и std::shared_ptr.

0 голосов
/ 13 декабря 2018

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...