Possible Duplicate:
Overloading operator ->
Hi,
I've seen that operator->()
is chained (re-applied) after it is evaluated, for example:
struct Bar
{
Bar() : m_str("Hello world!") {}
const string* operator->() const { return &m_str; }
string m_str;
};
struct Foo
{
const Bar& operator->() const { return m_bar; }
Bar m_bar;
};
int main()
{
Foo f;
cout << f->c_str() << endl;
return 0;
}
works pretty fine, which requires three operator->()
to be evaluated - Foo::operator->()
, Bar::operator->()
and regular pointer resolution.
But it wont work with pointers in the middle - if Foo::operator->()
returns pointer to Bar instead of reference, it wont compile. Same happens with auto_ptr<auto_ptr<string>>
for example.
Is it specific to non-overloaded operator->()
so it is only applied once and does not cause chaining?
Is it possible to make code below works without using (*ptr2)-> ...
?
int main()
{
string s = "Hello world";
auto_ptr<string> ptr1(&s);
auto_ptr<auto_ptr<string> > ptr2(&ptr1);
cout << ptr1->c_str() << endl; // fine
cout << ptr2->c_str() << endl; // breaks compilation
}
Thanks!
C++98 standard §13.5.6/1 "Class member access":
An expression
x->m
is interpreted as(x.operator->())->m
for a class objectx
of typeT
ifT::operator->
exists and if the operator is selected at the best match function by the overload resolution mechanism (13.3).
What this means in practice is that when x
is a pointer, you don’t get chaining; you then just get the built-in operator->
(i.e. x->m
with x
a pointer translates to (*x).m
).
But when x
is an object of class type T
, then you can get the chaining effect. Because then the interpretation as (x.operator->())->m
can be that (x.operator->())
itself is an object of some class, say class U
. Whence the second ->
can be resolved as U::operator->
, and so on, if the result of that again is a class type object…
Like, in your case, Foo::operator->
produces (a reference to) an object of class Bar
, which does define an operator->
.
But when operator->
returns a pointer, as e.g. std::auto_ptr<T>::operator->
does, then it's just the built-in operator->
that's used.
In passing, the chaining can be used to practically prevent someone from using delete
inappropriately. std::auto_ptr
does not do that. And I’ve never seen it done.
But there was once a long discussion thread over in [comp.lang.c++.moderated] about how to prevent inadvertent delete
of the raw pointer managed by a smart pointer, and this was one possibility that was discussed.
Cheers & hth.
The reason your first example works is because you returned a reference instead of a pointer. That operator would normally be invalid except in the case that it is overloaded. Therefore, the compiler must execute the overloaded functions down the chain. However, in the case of auto_ptr
you actually are returned a real pointer and the default operator ->
is invoked for regular pointers.
Please see the Overloading operator -> question for more details.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With