In C++ we know that for a pointer of class we use (->
) arrow operator to access the members of that class like here:
#include
usi
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.
In other words, when indexing the array to fetch the n'th element, you're not fetching a pointer to the n'th element, you're fetching a reference to the actual object, and the members of that need to be accessed using .
syntax.
you should read about difference between pointers and reference that might help you understand your problem.
In short, the difference is:
when you declare myclass *p
it's a pointer and you can access it's members with ->
, because p
points to memory location.
But as soon as you call p=new myclass[10];
p
starts to point to array and when you call p[n]
you get a reference, which members must be accessed using .
.
But if you use p->member = smth
that would be the same as if you called p[0].member = smth
, because number in []
is an offset from p
to where search for the next array member, for example (p + 5)->member = smth
would be same as p[5].member = smth
Because by using [] like p[3] you are already dereferencing the pointer to array + index shift. After that you have to use ".", since p[3] is an object, not a pointer.
Note that for a pointer variable x
myclass *x;
*x
means "get the object that x points to"x->setdata(1, 2)
is the same as (*x).setdata(1, 2)
and finallyx[n]
means "get the n-th object in an array".So for example x->setdata(1, 2)
is the same as x[0].setdata(1, 2)
.
Perhaps its insightful to consider that, given
myclass obj;
auto p = &obj; // avoid `new` with plain pointers. That combination is
// safer replaced by unique_ptr or std::vector.
the following will all work and are equivalent:
p->setdata(5, 6);
(*p).setdata(5, 6);
p[0].setdata(5, 6);
0[p].setdata(5, 6);
Showing that []
is really a pointer-dereferencing operator, just with the extra functionality that you can add offsets into a plain C-array.
It's generally questionable to use C-arrays in C++ code; the obvious alternative to your example is std::vector
:
std::vector<myclass> array(10);
Here, array[n]
can be used much like previously p[n]
, but
array.at(n)
)for(auto& obj: array){...}
.After...
MyClass* p = new myclass[10];
...p is a pointer to an array of MyClass objects. The "pointer to an array" thing has to be delt with first. Whenever you have a pointer to an array, p[n]
effectively gives you a reference to the nth element in the array, so you effectively have a MyClass&
. That's why .
is then needed to access MyClass
members ala p[n].member
, and why the pointer-specific ->
notation is erroneous in this case....
Note that p->member
(for any member) is still valid and equivalent to p[0].member
, so you can only use it for accessing the first element in the array. I strongly recommend you don't use it at all whenever you're in a programmatic context where 'p' is known to be pointer to the array, as it hides the fact that p
is an array. Sometimes though you may create another pointer - say q
- with the purpose of refering to a single array element - may or may not be [0]
- and in those situation's it's fair to use q->member
. Variables like q
may be used for iteration over the array too. But, sometime you're going to need to delete[] p;
- so you won't tend to change p
beforehands... you don't want to lose track of the p[0]
address or delete[] p;
will be Undefined Behaviour (which is allowed to be implementation defined and happens to be on Windows if p
still points within the array, but won't be portable).