【问题标题】:Why overloaded de-reference operator doesn't work the same way as the arrow operator?为什么重载的取消引用运算符与箭头运算符的工作方式不同?
【发布时间】:2020-08-02 04:57:56
【问题描述】:

再次阅读 C++ Primer 5 ed。由 lipmann 现在我已经阅读了有关成员访问运算符重载的信息。一切对我来说都很清楚,除了:

struct A
{
    int& operator* () {return *p;}
    void foo()const{cout << "A::foo()\n";}
    int* p = new int(5);
};

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

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


int main()
{

    C c;
    //cout << *c << endl; // error.
    c->foo(); // works

}
  • 我学到的是箭头操作符可以重载,而且必须是成员函数。如果我看到像 main c-&gt;foo() 这样的表达式,我可以认为 c 是一个内置指针,指向一个类类型的对象,它有一个名为 foo 的成员函数,因此可以获取它。或者(如 main 中的情况)c 是定义了自己的-&gt; 的类类型的对象。所以因为c 这里是一个表达式调用c 的箭头运算符的对象,它返回一个类B 类型的对象,它本身调用它的箭头运算符,直到它返回B 对象,它的-&gt; 返回一个构建在指向A 对象的指针中,在这种情况下,它被取消引用,结果对象用于获取foo() 函数。所以它递归地调用自己,直到返回一个内置指针并且该指针必须指向一个具有该提取成员的对象。

  • 我不明白:为什么取消引用运算符的工作方式不同?那么为什么解引用c不调用b*操作符等等只要返回一个定义了解引用操作符的对象呢?

  • 请不要争论 A 中的内存泄漏,目的是为了简洁。

【问题讨论】:

    标签: c++ operator-overloading member-access


    【解决方案1】:

    原因是解引用操作符本质上是一元的(返回一个引用),所以它可以像任何其他操作符一样被重载。而且它可以递归使用,如果需要,你只需要再次应用它。

    OTOH, -> 更像是一个二元运算符……但它右边的东西不是一个值,而是一个 name。这个名字必须在某个地方查到。所以编译器肯定需要一个对象。因此运算符被定义为一元的。但它不用作一元,因此如果需要,您可以再次应用它。所以它的定义是相反的:你可以依赖递归应用程序,或者通过返回原始指针来“退出”它。

    免责声明:这就是我的看法。

    【讨论】:

      【解决方案2】:

      -&gt;(成员访问)和*(间接)就是defined

      正如您所指出的,-&gt; 将递归调用-&gt;,无论它返回什么,直到它解析为指针。此时,您可以使用指针做您想做的事情。

      * 运算符根本没有定义为以这种方式工作。无论返回什么,都不会递归调用*

      在您的情况下,您可以使用间接访问foo,但您必须手动执行此操作,如下所示:

      (**c).foo();
      

      还要注意,您的特定示例无法编译,因为*c 返回对B 类型对象的引用,该对象没有为它定义operator&lt;&lt;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-09-04
        • 1970-01-01
        • 2012-04-19
        • 2019-07-20
        • 2013-02-15
        • 1970-01-01
        • 2021-11-01
        • 1970-01-01
        相关资源
        最近更新 更多