我试图了解重载 -> 运算符的工作原理。我有以下课程
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->()
。
正如标准所述,[over.ref]/1
表达式
x->m
被解释为T
类型的类对象x
(x.operator->())->m
(如果存在T::operator->()
并且运算符被重载解析机制选为最佳匹配函数)
这意味着messageWrapper->m_text
是(messageWrapper.operator->())->m_text
的语法糖。您可以显式应用后一种样式,但前一种样式更有效。重载operator->
使得像使用原始指针一样使用类成为可能,这就是像std::unique_ptr
和std::shared_ptr
这样的智能指针的工作方式。
标准说:
13.5.6 类成员访问
表达式
x->m
被解释为类的(x.operator->())->m
类型为T
的对象x
(如果存在T::operator->()
并且运算符是 被过载分辨率选为最佳匹配功能 机制
> -> 是一个二元运算符,它使用这两个参数工作,只要它不是指针,它就会继续解析左侧。
也就是说,在调用 Wrapper2::operator ->() 之后的以下代码中,编译器看到返回类型是引用并调用 Wrapper1::operator ->,只有这样调用才会产生指针,并且针对 RealType 解析"m"。
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;
};
运算符 -> 必须返回一个指针,当使用它时,返回值会自动取消引用,因此您不必自己添加第二个 ->