关于重载 -> 运算符的澄清

6

我正在尝试理解重载->运算符的工作原理。我有以下类:

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*类型。因此,在主方法中调用messageWrapper->时返回的是一个Message*类型指针。通常情况下,当有一个指针时,需要使用->操作符或解引用操作符来访问对象。 根据这个逻辑,要访问Message对象的m_text变量,代码应该写成以下形式。
(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";

我不理解这里的逻辑,请您给予一些解释。

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

进一步的说明:

在主方法中,我看到以下两个方法执行了相同的操作。

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

messageWrapper->m_text = "JKH";

这是否意味着操作符->与其他操作符的工作方式不同,其中它的意思是messageWrapper-> 相当于 (messageWrapper.operator->())-> 而不是 messageWrapper.operator->(),这是其他操作符的情况。

1
*(messageWrapper->).m_Text 语法错误。 - Jabberwocky
请问您能否解释一下为什么?这就是我不理解的地方。 (messageWrapper->) 是一个指向消息的指针。对该指针进行取消引用以访问对象应该是 (messageWrapper->)-> 或 *(messageWrapper->)。 - 3mr
可能是[overloading-member-access-operators-c][1]的重复问题。 [1]: https://dev59.com/fmoy5IYBdhLWcg3wF6ML - P.W
4个回答

9

根据标准,[over.ref]/1,

如果类型为T的类对象x存在T::operator->()函数,并且该运算符被重载决议机制选为最佳匹配函数,则表达式x->m被解释为(x.operator->())->m

这意味着messageWrapper->m_text(messageWrapper.operator->())->m_text的语法糖。您可以显式地应用后者,但前者更有效率。重载的operator->使得类可以像原始指针一样使用,这就是智能指针如std::unique_ptrstd::shared_ptr的工作方式。


5
标准规定:
13.5.6 类成员访问
如果类对象 x 的类型为 T,且 T::operator->() 存在,并且该运算符被重载决策机制选为最佳匹配函数,则表达式 x->m 被解释为 (x.operator->())->m。

3

-> 是一个二元运算符,它使用两个参数并且只要左侧不是指针类型就会继续解析左侧。

也就是说,在下面的代码中,在调用 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;
};

2

当使用运算符 -> 时,它必须返回一个指针。当返回值被自动解引用时,你不需要再添加第二个 -> 进行手动解引用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接