成员访问差异

时间:2009-12-28 19:51:17

标签: c++ operators operator-precedence

有人可以告诉我(*ptr).fieldptr->field之间有什么不同吗? 我知道它以某种方式连接到静态和动态链接,但我不知道它是什么。 谁能告诉我不同​​的东西,并举个例子?

编辑:  如果我有这个代码:

Point p;       //point is a class that derive from class shape 
Shape *s=&p; 
               //there is a diffrence if i write:

(*s).print();  //print is virtual func
s->print();    // the answers will not be the same, why?

TNX!

8 个答案:

答案 0 :(得分:7)

这与静态或动态链接无关。

C++'s operator precedence.的优先级低于*,因此*ptr.fldptr->fld之间实际上存在很大差异。例如,以下代码演示了:

#include <iostream>

struct foo {
  int f;
};

int main() {
  struct foo *p = new struct foo;
  p->f = 42;
  std::cout << p->f << std::endl;
  std::cout << (*p).f << std::endl;
  // The following will not compile
  // std::cout << *p.f << std::endl;
}

正如John Knoeller所指出的,ptr->fld(*(ptr)).fld的语法糖,但与*ptr.fld不同,后者实际上会评估为*(ptr.fld),可能不是什么你想要的。

当您拥有指向结构的指针并想要访问其中包含的字段时,您将使用ptr->fld(*(ptr)).fld意味着同样的事情,但不是那么整洁。当你有一个结构而不是指向结构的指针时,你会使用*strct.fld,它包含一个字段(fld),它是你要取消引用的指针。 ptr->fld的情况如上所示。 *strct.fld的情况可以使用以下结构:

struct foo {
  int *fld;
}

struct foo f;
f.fld = new int;
*f.fld = 42;

答案 1 :(得分:4)

它与静态或动态链接无关 两个表达式都将返回ptr.field

的值

ptr-&gt;字段表单是直接从指针

访问成员的缩写语法

更新:我发现你原来的意图不是链接,而是绑定 如果这确实是你的目标那么静态绑定动态绑定 这与 - &gt;有一定的关系operator see here

答案 2 :(得分:2)

静态链接是链接器将程序中使用的所有库例程复制到可执行映像中的结果。这可能需要比动态链接更多的磁盘空间和内存,但速度更快,更便携,因为它不需要在运行它的系统上存在库。

通过将可共享库的名称放在可执行映像中来完成动态链接。在运行映像之前,当可执行文件和库都放在内存中时,才会发生与库例程的实际链接。动态链接的一个优点是多个程序可以共享库的单个副本。

但它与你提到的指针间接无关 - 实际上,这两个表达式是相同的。

答案 3 :(得分:2)

我认为*ptr.field代表(*ptr).field

只考虑内置运营商,两者之间没有区别。不,它与“静态”或“动态”链接无关,无论这些术语暗示什么。

两者之间唯一的潜在差异是ptr->field变体->是C ++中的可重载运算符,而在(*ptr).field变体中只有*是可重载的,而.不是。

此外,这两种成员访问方法之间存在一些差异,这些方法存在于非常陈旧的C语言版本(CRM C)中,但我怀疑今天有人关心这些。

答案 4 :(得分:1)

这与链接无关。

ptr->fld 

只是

的简写
(*ptr).fld

这是纯粹的语法糖;)

答案 5 :(得分:1)

只要ptr是一个指针,一旦正确括号,两者就是等价的(正如其他人所说)。如果ptr是一个对象而不是一个指针,它们可能会有所不同,具体取决于来自对象类或祖先的operator*operator->(如果有)的定义。

答案 6 :(得分:1)

表格 - &gt;只是取消重新指定指针和访问成员的简写。

(*ptr).field;
// Equiv to 
ptr->field;

使用的一个很好的理由 - &gt;就是当你跟随一条链时:

int x = (*(*(*(*ptr).field1).field2).field3).field4;
// Equiv to 
int y = ptr->field1->field2->field3->field4;

第二个变得更具可读性。

关于你问题的第二部分。
我发现举一个例子真的很容易。

#include <iostream>

class Shape
{
    public:   virtual ~Shape()        {}
              virtual void Print()    {std::cout << "Shape\n";}
};
class Point: public Shape
{
    public:   virtual void Print()    {std::cout << "Point\n";}
};

int main ()
{
    Point   p;
    Shape*  s = &p;

    s->Print();
    (*s).Print();
}

> vi x.cpp
> g++ x.cpp
> ./a.exe
Point
Point

正如您所看到的,两种情况下的结果都相同。

当您通过指针或引用调用方法时,将调用虚拟调用机制。星型运算符(AKA derefence运算符)返回对象的引用(它实际上不会取消引用该对象)。因此,当它用于调用方法时,将调用虚拟调用机制并调用方法的最派生版本。

答案 7 :(得分:0)

它们都是一样的。
*ptr.field取消引用变量ptr,然后返回成员field的值。

->运算符是上述的简写符号。