【问题标题】:Why bother to write -> rather than .? [duplicate]为什么要写 -> 而不是 .? [复制]
【发布时间】:2010-10-05 15:31:06
【问题描述】:

可能重复:
Why does C have a distinction between -> and . ?

程序员在访问对象成员时必须区分.-> 的真正原因是什么?

void foo( Point &p ) {
    p.x ;
    p->y; // syntax error
} 

void foo( Point *p ) {
    p.x ; // syntax error
    p->y;
} 

我的意思是,不管怎样,它们都指向一个对象,p

  • 为什么我每次都要检查 p 是什么?编译器不能理解吗?

  • 为什么他们不允许它同时接受. 语法?这对于堆栈对象也可以。

如果是因为 C 传统,

  • 为什么不允许.-> 访问器?

15 年来,我一直谦虚地认为编译器错误是我的错!

【问题讨论】:

  • stackoverflow.com/questions/1813865/… 的可能重复项。虽然这涉及 C,但许多答案都涉及 C++ 问题。
  • 就是这样。习惯它或使用不同的语言。除非 Kernighan 或 Ritchie 已经开始在 StackOverflow 上发帖,否则您不太可能得到好的答案。
  • 我明白你的意思,但我认为“编译器错误是我的错”的想法有点忽略了这一点。 错误本身是一件好事, 当您将错误与无提示编译失败进行比较时,这一点很明显。令人讨厌的不是错误消息,而是无法接受和编译此代码。对?小点,但我希望它澄清了这个问题:为什么编译器(相当于:C++ 语言规范)不允许这个表达式?这就是您在要点中所说的。

标签: c++ pointers syntax


【解决方案1】:

因为p->d 实际上意味着(*p).d。它进行解引用,然后进行成员访问。引用表现得像对象,因此它们不需要取消引用(它们也是 C++ 的特性,而指针是从 C 继承的);它一直保持这种方式是为了向后兼容。

C++ 充满了这样的矛盾,但通常没有更好的选择来添加新功能保持旧代码正常工作。重写旧代码不是一种选择。

【讨论】:

  • 现在 imageine d 是下一个链表。 (*(*(*(*p).next).next).next).nextp->next->next->next->next 相同
【解决方案2】:

因为你可能有一个智能指针。在这种情况下,您可以使用. 访问智能指针的成员,使用-> 访问真实对象的成员。

【讨论】:

  • 难道不是反过来——智能指针利用了这个特性,而不是这个特性存在,所以智能指针可以存在......
  • 可能两者兼有。在出现智能指针之类的东西之前,C 显然区分了.->。但是 C++ 可以 原则上选择按照 OP 的建议合并它们,允许您使用任何一种语法。但是这样就不可能实现智能指针
  • @user779 我想说你有道理:)
【解决方案3】:

它们不一样。

. 是当你有一个实际的对象时。
-> 是当你有一个指向对象的指针时。

. 运算符不能重载,而-> 运算符可以重载。

【讨论】:

  • OP 的问题不是什么时候用什么,而是为什么这两种不同的语法形式首先存在。
【解决方案4】:

智能指针:它们可能同时具有成员并指向其他一些值。例如:

boost::smart_ptr<someclass> x(new someclass())
x->some_method();
x.reset();

【讨论】:

    【解决方案5】:

    理论上,至少在 C 语言中,该语言本来可以设计成这样。 D(例如)完全符合您的要求。

    在 C++ 中,事情可能更丑陋——x-&gt;yx.y 完全有可能都有效,但意味着完全不同的东西(即重载的智能指针operator-&gt;):

    #include <iostream>
    
    class P { 
        class inner { 
        public:
            inner() : x(1) {}
            int x;
        } i;
    public:
        int x;
    
    
        P() :x(0) {}
    
        inner *operator->() { return &i; }
    };
    
    int main() { 
        P p;
        std::cout << p.x << "\t" << p->x << "\n";
        return 0;
    }
    

    【讨论】:

    • 在 C 中使用单独的分隔符是一个良好的设计特性,遗憾的是在 C# 中缺少这一点。在 C 中,在 foo = bar; foo-&gt;boz = 3; 中,第二条语句不会修改 foo,但会修改 bar-&gt;boz。相比之下,在foo = bar; foo.boz = 3; 中,第二条语句确实修改了foo,但没有修改bar.boz。我希望 C# 和 .NET 允许将非字段成员声明为使用一个或其他运算符,-&gt; 暗示 this 将按值传递,. 暗示按引用传递。类字段将使用-&gt;,结构字段将使用.
    【解决方案6】:

    因为指针和引用不一样,被区别对待?

    我很欣赏阅读代码时的视觉差异。

    【讨论】:

      【解决方案7】:

      考虑以下代码:

      x.myInt = 3;
      cout << (int)&x <<< endl;
      

      我们在这里打印什么?指针的地址还是对象的地址? 我欢迎 .-&gt; 之间的区别,因为它为您提供了更多关于代码的上下文。

      根据您建议的更改,如果不查找 x 是什么类型,我们不会知道其中的区别。

      【讨论】:

      • 是的,这是我在回答中提到的一个例子。
      【解决方案8】:

      这是一个方便的问题:p->foo 与 (*p).foo 相同

      当你可以用简单的 + 和 = 运算符表达相同的逻辑时,这就像问为什么要使用 ++ 或 += 运算符。

      【讨论】:

      • 现在 imageine foo 是下一个链表。 (*(*(*(*p).next).next).next).next 等同于 p->next->next->next->next
      【解决方案9】:

      我能想到一个原因:开发人员编写的内容与他们实际想要发生的事情之间的映射越复杂,当出现类型或语法错误时,就越难以弄清楚它们的真正含义。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-01-20
        • 1970-01-01
        • 1970-01-01
        • 2018-10-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多