Difference between object->function() and object.function() in C++
Can anyone explain the different 开发者_运维知识库between doing something like:
a->height();
and
a.height();
Is there actually a difference?
In the first example a is a pointer to an object, in the second example it is the object itself (or a reference to the object). At the lowest level, there is no clear difference between the two.
This is a strange question, assuming that we are talking about the built-in ->
. It sounds a bit like "what's the difference between a hammer and an apple". Usually a question about the "difference" applies when the two variants are at least somewhat interchangeable, both applicable at the same time. So, people would ask about the "difference" to decide, which variant to use. This is not the case here.
You can't have both a->height()
and a.height()
valid at the same time. Only one of the two can be valid, depending on the type of a
. I.e. you don't have a choice of which version to use. The first one (with a ->
) is applicable if the left-hand side is a pointer to an object. The second one (with just a .
) is only applicable when you the left-hand side is the object value itself. So, that's all there's to it.
The ->
is just a shorthand for a combination of unary *
and .
, meaning that when a
is a pointer a->height()
is equivalent to (*a).height()
. So, a more reasonable question would be about the difference between a->height()
and (*a).height()
. And the answer is: there's no difference (again, as long as we are considering the built-in ->
)
It basically boils down to how you declared "a". If you do:
SomeClass a;
then "a" is itself an object, and you use "." to reference its members.
If you do:
SomeClass * a;
a = [some expression that produces a pointer to a SomeClass object];
then "a" is a POINTER TO an object, not itself an object. Then you use the "->" notation.
(There are some potential exceptions to the above rules, but they're not something most people ever encounter.)
It's also worth mentioning that some objects like smart pointers support both notations. In that case, the first would refer to the object pointed to by the pointer- the second would refer to the smart pointer itself.
The operator->
, followed by a function call, will result in the returned pointer being dereferences, and the function being called on the resulting object. In short, a->foo()
is shorthand for (*a).foo()
.
Apart from the correct answer that a->foo()
requires a
to be a pointer to a class defining foo
, a contrived example may tell something different:
struct xC {
struct Member {
void foo(){printf("xC::Member::foo\n");};
};
Member a;
Member* operator->() { return &a; }
// following function doesn't really make sense.
void foo() { printf("xC::foo\n");};
};
int main(){
xC x;
x.foo(); // prints "xC::foo".
x->foo();// prints "xC::Member::foo"
}
In the context of smartpointers and the stl iterators, you will often see these kinds of operator->
definition. In that context, the definition does follow Stroustrup's guideline to not abuse it for something counter-intuitive, like my example, but to make the defining class usable as if it were 'pointing' to some object.
Assuming that a
is a pointer to some object then:
This:
a->height();
Is just shorthand for:
(*a).height();
It allows you to call a method via a pointer rather than just a plain object (or reference).
You don't actually need to use the -> version but when you chain a couple of calls togther it becomes obvious why it is useful.
person->body()->arm(right)->hand()->finger(index)->ring()->activate();
If you write this long hand it is:
(*(*(*(*(*(*person).body()).arm(right)).hand()).finger(index)).ring()).activate();
Its hard to correlate the de-reference (the *
) to the pointer it is de-referencing. While the first version -> the thing on the left is a pointer the thing on the right the part of the object after the pointer has been de-referenced.
As others have said, if you are talking about the dereferencing of a pointer, then the difference would not be terribly significant. More importantly however, if a
is a instance or a reference and has defined an operator->
function then you could see very different behaviors. a.name()
would call a's name()
function while a->name()
could be calling some other type's name()
function along with any other work the class has decided to do (it is a function call returning a pointer so 'evil' class could do most anything it wants so long as it returns a valid pointer). This is primarily used for smart pointers, but there is no guarantee of that in the language.
It all boils down to how readable you want the code itself and how fast you want it to be. At lowest level in assembler it's comes down to push/pull on stack. In real life today with fast computers/MCU it doesn't matter. It's the style of programming you use. Both ways are fine but don't mix them. That can make it difficult to read for other programmers.
精彩评论