C++中的Arrow Member运算符

Era*_*mus 6 c++ pointers reference pass-by-reference

我很擅长使用C++.我以前处理过Java和ActionScript,但现在我想学习这种强大的语言.由于C++授予程序员显式使用指针的能力,因此我对使用箭头成员运算符感到困惑.这是我尝试编写的示例代码.

main.cpp中:

   #include <iostream>
   #include "Arrow.h"
   using namespace std;

   int main()
   {
        Arrow object;
        Arrow *pter = &object;

        object.printCrap(); //Using Dot Access
        pter->printCrap(); //Using Arrow Member Operator
        return 0;
   }
Run Code Online (Sandbox Code Playgroud)

Arrow.cpp

   #include <iostream>
   #include "Arrow.h"
   using namespace std;

   Arrow::Arrow()
   {

   }

   void Arrow::printCrap(){
       cout << "Steak!" << endl;
   }
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,它所做的只是使用两种方法(Dot和Arrow)打印牛排.

简而言之,在使用C++编写真正的实际应用程序时,何时使用箭头符号?由于我以前的编程经验,我习惯使用点符号,但箭头对我来说是全新的.

Jer*_*fin 5

在C中,a->b恰恰相当于(*a).b.引入"箭头"符号是为了方便; 通过指针访问结构的成员是相当常见的,箭头表示法更容易编写/输入,并且通常也被认为更易读.

C++也增加了另一个皱纹:operator->可以为struct/ 重载class.虽然相当不寻常,但这样做对于智能指针类来说很常见(几乎是必需的).

这本身并不罕见:C++允许绝大多数运算符过载(尽管有些运算符几乎永远不应该,例如operator&&,operator||operator,).

不寻常的是如何operator->解释过载.首先,虽然a->b看起来像是->一个二元运算符,但是当你在C++中重载它时,它被视为一元运算符,所以正确的签名是T::operator(),T::operator(U)或者不是那个顺序.

结果也有些异常.假设foo某个类型的对象超载operator->,foo->bar则被解释为含义(f.operator->())->bar.反过来,这限制了重载的返回类型operator->.具体来说,它必须返回另一个也重载的类的实例operator->(或对这样一个对象的引用),否则它必须返回一个指针.

在前一种情况下,简单的外观foo->bar实际上可能意味着"追逐"整个(任意长的)对象实例链,每个实例都会重载operator->,直到最终到达一个可以引用名为的成员bar.对于(公认的极端)示例,请考虑以下事项:

#include <iostream>

class int_proxy {
    int val;
public:
    int_proxy(): val(0) {}
    int_proxy &operator=(int n) { 
        std::cout<<"int_proxy::operator= called\n";
        val=n; 
        return *this; 
    }
};

struct fubar {
    int_proxy bar;
} instance;

struct h {
    fubar *operator->() {
        std::cout<<"used h::operator->\n";
        return &instance;
    }
};

struct g {
    h operator->() {
        std::cout<<"used g::operator->\n";
        return h();   
    }
};

struct f {
    g operator->() { 
        std::cout<<"Used f::operator->\n";
        return g();
    }
};

int main() {
    f foo;

    foo->bar=1;
}
Run Code Online (Sandbox Code Playgroud)

即使foo->bar=1;看起来像通过指针对成员的简单赋值,该程序实际上产生以下输出:

Used f::operator->
used g::operator->
used h::operator->
int_proxy::operator= called
Run Code Online (Sandbox Code Playgroud)

显然,在这种情况下foo->bar不是(甚至接近),相当于一个简单的(*foo).bar.从输出中可以明显看出,编译器生成"隐藏"代码,以遍历->各种类中的整个重载运算符系列,从而获得foo指向成员的东西(指针)bar(在这种情况下也是一种类型)重载operator=,所以我们也可以看到赋值的输出.


dea*_*mer 3

好问题,

点(.) 该运算符用于使用该类/结构的实例变量访问该类或结构的成员函数或有时访问该类或结构的数据成员。

object.function(); 
object.dataMember; //not a standard for class.
Run Code Online (Sandbox Code Playgroud)

箭头(->)该运算符用于访问类或结构的成员函数或有时访问数据成员,但使用该类/结构的指针。

ptr->function();
ptr->datamember; //not a standard for class.
Run Code Online (Sandbox Code Playgroud)

  • 另外值得注意的是:如果`p`是指向对象`o`的指针,那么`p-&gt;blah`就完全等价于`(*p).blah`,后者等价于`o.blah`。 (3认同)