21

在 C++ 中,我们知道对于类的指针,我们使用 ( ->) 箭头运算符来访问该类的成员,如下所示:

#include <iostream>
using namespace std;

class myclass{
    private:
        int a,b;
    public:
        void setdata(int i,int j){
            a=i;
            b=j;
        }
};

int main() {
    myclass *p;
    p = new myclass;
    p->setdata(5,6);
    return 0;
}

然后我创建一个数组myclass

p=new myclass[10];

当我通过 ( ) 箭头运算符访问myclass成员时->,出现以下错误:

base operand of '->' has non-pointer type 'myclass'

但是当我通过 ( .) 运算符访问班级成员时,它可以工作。这些事情让我很困惑。为什么我必须对.类数组使用 () 运算符?

4

6 回答 6

29

您应该阅读指针和参考之间的区别,这可能有助于您理解您的问题。

简而言之,区别在于:
当您声明myclass *p它是一个指针并且您可以使用 , 访问它的成员时->,因为p指向内存位置。

但是,一旦您调用p=new myclass[10]; p开始指向数组,并且当您调用时,您将p[n]获得一个引用,必须使用..
但是,如果您使用p->member = smth它,则与调用 相同p[0].member = smth,因为 number in[]是从到搜索下一个数组成员的位置的偏移量p,例如(p + 5)->member = smthp[5].member = smth

于 2013-07-18T06:47:18.827 回答
10

请注意,对于指针变量 x

myclass *x;
  • *x意思是“获取 x 指向的对象”
  • x->setdata(1, 2)(*x).setdata(1, 2)和最后一样
  • x[n]表示“获取数组中的第 n 个对象”。

所以例如x->setdata(1, 2)是一样的x[0].setdata(1, 2)

于 2013-07-18T06:55:43.937 回答
5

因为通过使用像 p[3] 这样的 [] 您已经取消了指向数组 + 索引移位的指针。之后你必须使用“.”,因为 p[3] 是一个对象,而不是一个指针。

于 2013-07-18T06:45:41.040 回答
4

后...

MyClass* p = new myclass[10];

...p 是指向 MyClass 对象数组的指针。“指向数组的指针”必须首先处理。每当您有一个指向数组的指针时,p[n]都会有效地为您提供对数组中第 n 个元素的引用,因此您实际上拥有一个MyClass&. 这就是为什么.需要访问MyClass成员 ala p[n].member,以及为什么在这种情况下特定于指针的->符号是错误的......

请注意,p->member(对于任何成员) 仍然有效且等效于p[0].member,因此您只能使用它来访问数组中的第一个元素。我强烈建议你在编程上下文中根本不要使用它,因为它隐藏了p一个数组的事实。有时,尽管您可能会创建另一个指针 - 比如说q- 以引用单个数组元素的目的 - 可能是也可能不是[0]- 在这种情况下使用q->member. 类似的变量q也可以用于数组的迭代。但是,有时你会需要delete[] p;- 所以你不会p事先改变......你不想忘记p[0]地址或delete[] p;将是未定义的行为(如果仍然指向数组中的点,则允许实现定义并且恰好在 Windows 上p,但不可移植)。

于 2013-07-18T06:50:40.983 回答
3
myclass *ptr;

ptr = new myclass();     // ptr points to a single object
ptr->doSomething();      // calls doSomething on the object _pointed to_

ptr = new myclass[10];   // ptr points to multiple objects
ptr->doSomething();      // calls doSomething on the first object _pointed to_
(ptr+1)->doSomething();  // calls doSomething on the second object _pointed to_

auto val = ptr[2];       // fetches a reference to the second _object_ to val.
val.doSomething();       // calls doSomething on the _object reference_ val.

换句话说,当索引数组以获取第 n 个元素时,您不会获取指向第 n 个元素的指针,而是获取对实际对象的引用,并且需要访问该对象的成员使用.语法。

于 2013-07-18T06:47:19.390 回答
1

考虑到这一点,也许它很有见地,鉴于

myclass obj;
auto p = &obj;  // avoid `new` with plain pointers. That combination is
               //  safer replaced by unique_ptr or std::vector.

以下都将起作用并且是等效的:

p->setdata(5, 6);
(*p).setdata(5, 6);
p[0].setdata(5, 6);
0[p].setdata(5, 6);

显示这[]实际上是一个指针解引用运算符,只是具有可以将偏移量添加到普通 C 数组中的额外功能。

在 C++ 代码中使用 C 数组通常是有问题的;您的示例的明显替代方法是std::vector

std::vector<myclass> array(10);

在这里,array[n]可以像以前一样使用p[n],但是

  • 你不会得到任何愚蠢的指针想法,因为接口中没有指针
  • 您可以获得适当的自动内存管理,即当数组超出范围时,它会自动删除对象及其内存
  • 如果需要,您可以获得边界检查 ( array.at(n))
  • 您可以使用 (C++11) 轻松循环整个数组for(auto& obj: array){...}
于 2013-07-18T06:53:25.780 回答