By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,983 Members | 1,597 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,983 IT Pros & Developers. It's quick & easy.

overload "operator->"

P: n/a
Hi,

I read about operator overloading and have a question regarding
"operator->()". If I have two classes like this:

struct A{
void f();
};

struct B{
A* p;
A* operator->(){return p;}
};

Then we can do:

B b;
b->f();

and A's f() is called.

However, the overloading of -seems to say it's a unary operator, and
is prefixed (because of the ()). Therefore, to me, it looks like we
should use this operator like:
B::operator->b,

which will give use a the pointer member in B. Then to access "f", I
think we need to do:

(B::operator->b)->f(),

which is very different to b->f(). Can someone please tell me why
using b->f() gives me the f() of A?

Thanks,
Jess

May 4 '07 #1
Share this Question
Share on Google+
14 Replies


P: n/a
Jess wrote:
Hi,

I read about operator overloading and have a question regarding
"operator->()". If I have two classes like this:

struct A{
void f();
};

struct B{
A* p;
A* operator->(){return p;}
};

Then we can do:

B b;
b->f();

and A's f() is called.

However, the overloading of -seems to say it's a unary operator, and
is prefixed (because of the ()). Therefore, to me, it looks like we
should use this operator like:
B::operator->b,
No, it's shorthand for b.operator->().
which will give use a the pointer member in B. Then to access "f", I
think we need to do:

(B::operator->b)->f(),
b.operator->()->f()
--
Ian Collins.
May 4 '07 #2

P: n/a
On May 4, 1:37 pm, Ian Collins <ian-n...@hotmail.comwrote:
No, it's shorthand for b.operator->().
b.operator->()->f()
But the declaration A* operator->() shows "->" should be used as a
prefix of "b", isn't it? Using it as a prefix should give us "->b"...

Moreover, your expansion above seems to say we can expand "b" to
"b.operator->()", I really can't see where it's from....

Jess

May 4 '07 #3

P: n/a
Jess wrote:
On May 4, 1:37 pm, Ian Collins <ian-n...@hotmail.comwrote:
>No, it's shorthand for b.operator->().
b.operator->()->f()

But the declaration A* operator->() shows "->" should be used as a
prefix of "b", isn't it? Using it as a prefix should give us "->b"...
How so? Operator -is a unary *postfix* operator.

See section 11.10 of Stroustrup.

--
Ian Collins.
May 4 '07 #4

P: n/a
On May 4, 3:04 pm, Ian Collins <ian-n...@hotmail.comwrote:
How so? Operator -is a unary *postfix* operator.
I see, so we can't change its postfix property when overloading it.
My other two questions are:

a. if we use it as postfix, then why don't we overload it as:

A* operator->(void)

to show it has no right argument? Why do we have () in "A* operator-
>()"? What does the "()" mean?
b. why is b->f() the shorthand of
(b.operator->()) -f()

now there are two "->". I think in b->f(), "b->" should be expanded
to "b.operator->". Then b->f() is the shorthand of

(b.operator->)f()

(which obviously isn't a valid syntax...)

Thanks,
Jess
May 4 '07 #5

P: n/a
Jess wrote:
On May 4, 3:04 pm, Ian Collins <ian-n...@hotmail.comwrote:
>How so? Operator -is a unary *postfix* operator.

I see, so we can't change its postfix property when overloading it.
My other two questions are:

a. if we use it as postfix, then why don't we overload it as:

A* operator->(void)
Why should we? Are you thinking of the prefix and postfix ++ and --
operators? Th use of (int) with this is required to disambiguate the
operator.
to show it has no right argument? Why do we have () in "A* operator-
>()"? What does the "()" mean?

b. why is b->f() the shorthand of
(b.operator->()) -f()

now there are two "->". I think in b->f(), "b->" should be expanded
to "b.operator->". Then b->f() is the shorthand of
What? b.operator->() returns a pointer:

A* p = b.operator->();
a->f();

--
Ian Collins.
May 4 '07 #6

P: n/a
On May 4, 8:16 am, Jess <w...@hotmail.comwrote:
On May 4, 3:04 pm, Ian Collins <ian-n...@hotmail.comwrote:
How so? Operator -is a unary *postfix* operator.
I see, so we can't change its postfix property when overloading it.
You can't change the syntax of C++ with operator overloading.
You can only extend it to support additional types.
My other two questions are:
a. if we use it as postfix, then why don't we overload it as:
A* operator->(void)
to show it has no right argument?
That's how we do overload it. Except that the void isn't
necessary. But it has nothing to do with whether the argument
is right or left. In general, when overloading operators, the
first operand of the function is the first operand of the
operator, and so on. If the overloaded operator is a member
(required for operator->), its first operand is this, so it has
one less formal parameter.
Why do we have () in "A* operator-
()"? What does the "()" mean?
That you are declaring/defining a function. An overloaded
operator is always a function.
b. why is b->f() the shorthand of
(b.operator->()) -f()
Because that's what the standard says.
now there are two "->". I think in b->f(), "b->" should be expanded
to "b.operator->".
The name of the function? That doesn't make any sense.
Then b->f() is the shorthand of
(b.operator->)f()
(which obviously isn't a valid syntax...)
No, because a user defined overload is always implemented as a
function, and when the operator is used, that function is
called.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

May 4 '07 #7

P: n/a
"Jess" <wd***@hotmail.comwrote in message
news:11**********************@u30g2000hsc.googlegr oups.com...
On May 4, 3:04 pm, Ian Collins <ian-n...@hotmail.comwrote:
>How so? Operator -is a unary *postfix* operator.

I see, so we can't change its postfix property when overloading it.
My other two questions are:

a. if we use it as postfix, then why don't we overload it as:

A* operator->(void)

to show it has no right argument? Why do we have () in "A* operator-
>>()"? What does the "()" mean?
You seem to assume that how operator overloading is expressed in any way
reflects the orientation (prefix/postfix/infix) of the operator itself.
Assumptions are the mother of all fuck-ups :). Your assumption is incorrect,
it only reflects the arity of the operator. An operator with 1 parameter is
an unary operator (whether they are prefix or postfix), and an operator with
2 parameters is a binary operator. Keep in mind the 'this' pointer is an
implicit first parameter. The only two exceptions to this are the postfix ++
and -- operators. Since both the postfix and prefix variants are unary,
their function definitions would be the same and therefore ambiguous. That's
why an extra int parameter is used for the postfix ++ and -- operators to
distinguish them from the prefix ones.

The operator syntax is just like ordinary functions, where the function name
is followed by parameters contained in parantheses. The function-style name
for the -operator is "operator ->". Just as you would do b.func(), you can
also do b.operator->(). Likewise, ++b is the same as b.operator++().

- Sylvester Hesp
May 4 '07 #8

P: n/a
On May 4, 4:44 pm, Ian Collins <ian-n...@hotmail.comwrote:
What? b.operator->() returns a pointer:

A* p = b.operator->();
a->f();
Yes, from here, it shows "(b.operator->()) -f()" is what we want,
and I couldn't understand why it's equivalent to "b->f()". But if it
is the standard (as James said), then I'll take it as a fact. :)

Thanks,
Jess

May 6 '07 #9

P: n/a
On May 4, 7:32 pm, James Kanze <james.ka...@gmail.comwrote:
You can't change the syntax of C++ with operator overloading.
You can only extend it to support additional types.
By "extending", I guess I can't change a postfix to a prefix, or its
precedence? Can I change a member function to a non-member and vice
versa? Can I change a unary operator to a binary or a binary to a
unary? Also, when ">>" and "<<" are used by iostream, are then member
operators of iostream or non-member functions?
b. why is b->f() the shorthand of
(b.operator->()) -f()

Because that's what the standard says.
I see, it's the standard, though it doesn't look very obvious why
standard says it. :) When "->" is used with a pointer "p->b()" is
equivalent to (*p).b(). which doesn't show how we can use "->" with
user-defined class types.

Thanks,
Jess

May 6 '07 #10

P: n/a
On May 4, 7:53 pm, "Sylvester Hesp" <s.h...@oisyn.nlwrote:
The operator syntax is just like ordinary functions, where the function name
is followed by parameters contained in parantheses. The function-style name
for the -operator is "operator ->". Just as you would do b.func(), you can
also do b.operator->(). Likewise, ++b is the same as b.operator++().
Thanks a lot for the explanations!
Jess

May 6 '07 #11

P: n/a
On 2007-05-06 13:22, Jess wrote:
On May 4, 7:32 pm, James Kanze <james.ka...@gmail.comwrote:
>You can't change the syntax of C++ with operator overloading.
You can only extend it to support additional types.

By "extending", I guess I can't change a postfix to a prefix, or its
precedence?
Correct.
Can I change a member function to a non-member and vice
versa?
No, but for most(?) operators there's both a member and a non-member
version.
Can I change a unary operator to a binary or a binary to a
unary?
No.
Also, when ">>" and "<<" are used by iostream, are then member
operators of iostream or non-member functions?
Non-member, and that is how you should make the if you ever want to add
an operator<< to your class so that you can easily print it.

As far as I know the only operator that you have some freedom with is
the ()-operator, with which you can decide how many argument it takes,
all the others are quite fixed, in arity, precedence, postfix/prefix, etc.
b. why is b->f() the shorthand of
(b.operator->()) -f()

Because that's what the standard says.

I see, it's the standard, though it doesn't look very obvious why
standard says it. :) When "->" is used with a pointer "p->b()" is
equivalent to (*p).b(). which doesn't show how we can use "->" with
user-defined class types.
The idea is that you should be able to make a class that acts just like
a pointer, and that requires that it works like that, take a look at
this code and compare my Pointer-class with a real pointer:

#include <string>
#include <iostream>

template<class T>
class Pointer
{
T* ptr_;
public:
Pointer(T* p) : ptr_(p) {}
T* operator->() { return ptr_; }
T& operator*() { return *ptr_; }
};
int main()
{
std::cout << "Using Pointer:\n";
Pointer<std::stringP(new std::string());
*P = "Hello";
P->append(" World\n");
std::cout << *P;

std::cout << "Using a std::string pointer:\n";
std::string* p = new std::string();
*p = "Hello";
p->append(" World\n");
std::cout << *p;
}

--
Erik Wikström
May 6 '07 #12

P: n/a
Thanks a lot for the example!

Jess

On May 6, 9:59 pm, Erik Wikström <Erik-wikst...@telia.comwrote:
On 2007-05-06 13:22, Jess wrote:
On May 4, 7:32 pm, James Kanze <james.ka...@gmail.comwrote:
You can't change the syntax of C++ with operator overloading.
You can only extend it to support additional types.
By "extending", I guess I can't change a postfix to a prefix, or its
precedence?

Correct.
Can I change a member function to a non-member and vice
versa?

No, but for most(?) operators there's both a member and a non-member
version.
Can I change a unary operator to a binary or a binary to a
unary?

No.
Also, when ">>" and "<<" are used by iostream, are then member
operators of iostream or non-member functions?

Non-member, and that is how you should make the if you ever want to add
an operator<< to your class so that you can easily print it.

As far as I know the only operator that you have some freedom with is
the ()-operator, with which you can decide how many argument it takes,
all the others are quite fixed, in arity, precedence, postfix/prefix, etc.
b. why is b->f() the shorthand of
(b.operator->()) -f()
Because that's what the standard says.
I see, it's the standard, though it doesn't look very obvious why
standard says it. :) When "->" is used with a pointer "p->b()" is
equivalent to (*p).b(). which doesn't show how we can use "->" with
user-defined class types.

The idea is that you should be able to make a class that acts just like
a pointer, and that requires that it works like that, take a look at
this code and compare my Pointer-class with a real pointer:

#include <string>
#include <iostream>

template<class T>
class Pointer
{
T* ptr_;
public:
Pointer(T* p) : ptr_(p) {}
T* operator->() { return ptr_; }
T& operator*() { return *ptr_; }

};

int main()
{
std::cout << "Using Pointer:\n";
Pointer<std::stringP(new std::string());
*P = "Hello";
P->append(" World\n");
std::cout << *P;

std::cout << "Using a std::string pointer:\n";
std::string* p = new std::string();
*p = "Hello";
p->append(" World\n");
std::cout << *p;

}

--
Erik Wikström

May 6 '07 #13

P: n/a
On May 6, 1:22 pm, Jess <w...@hotmail.comwrote:
On May 4, 7:32 pm, James Kanze <james.ka...@gmail.comwrote:
You can't change the syntax of C++ with operator overloading.
You can only extend it to support additional types.
By "extending", I guess I can't change a postfix to a prefix, or its
precedence?
Right. And you cannot introduce new operators, either. (Say a
@ operator.) Basically, the compiler builds (or at least,
should be able to build) an expression tree without looking at
the types of the data. Only once it has the expression tree
does it look at the types, and map the operators onto either a
built-in operator or a user defined operator.
Can I change a member function to a non-member and vice
versa?
In general, no. Most operators, however, can be defined as
either one or the other.
Can I change a unary operator to a binary or a binary to a
unary?
No. On the other hand, C++ has a number of operator tokens
which can represent two different operators, one binary and one
unary. The choice of which is made *before* the compiler
evaluates whether to use a user defined operator or a built-in,
however.
Also, when ">>" and "<<" are used by iostream, are then member
operators of iostream or non-member functions?
Either (or in this case, both). >and << are binary operators;
there are two ways of overloading a binary operator (with a few
exceptions): as a member function taking a single argument (with
the object the member function is called on as the first
argument to the operator, and the function argument as the
second), or as a free function taking two arguments.

The important thing to keep in mind here is that when the
compiler sees << or >>, it doesn't immediately consider
overloading of any sort. It just notes that it has a binary
operator of such and such precedance and binding, and continues
building the expression tree. Only when it has finished, and is
actually generating code, will it look at the possible
overloads, and do overload resolution over the set of built-in
operators, member function redefines, and free function
redefines.
b. why is b->f() the shorthand of
(b.operator->()) -f()
Because that's what the standard says.

I see, it's the standard, though it doesn't look very obvious why
standard says it. :)
True, but not for the reasons you seem to be saying. A priori,
looking at it, one would expect -to be a binary operator.
It's not treaded as such, however, but as a unary operator. And
as a unary operator, if it is defined as a member function, the
operand is the object it is called on.

There aren't many examples of postfix unary operators to draw
on. (++ and -- are very special, as they can be either prefix
or postfix.) But this behavior is consistent with the idea that
a member function is called on an object, and that if the member
function is a user defined operator overload, the object the
function is called on is the first operand of the operator,
regardless of where the operand occurs relative to the operator.
When "->" is used with a pointer "p->b()" is
equivalent to (*p).b(). which doesn't show how we can use "->" with
user-defined class types.
This is true in general. For built in operators, a += b is the
equivalent of a = a + b, but there is no relationship if the
operators are defined by the user (unless the user decides to
create one---which is highly recommended).

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

May 6 '07 #14

P: n/a
On May 6, 1:59 pm, Erik Wikström <Erik-wikst...@telia.comwrote:
On 2007-05-06 13:22, Jess wrote:
On May 4, 7:32 pm, James Kanze <james.ka...@gmail.comwrote:
You can't change the syntax of C++ with operator overloading.
You can only extend it to support additional types.
By "extending", I guess I can't change a postfix to a prefix, or its
precedence?
Correct.
Can I change a member function to a non-member and vice
versa?
No, but for most(?) operators there's both a member and a non-member
version.
Most. The -operator is an exception, as are =, [], () and
unary &.
Can I change a unary operator to a binary or a binary to a
unary?
No.
Also, when ">>" and "<<" are used by iostream, are then member
operators of iostream or non-member functions?
Non-member, and that is how you should make the if you ever want to add
an operator<< to your class so that you can easily print it.
Both, or either, depending on your point of view. An operator<<
which takes an std::ostream as its first operand can be either a
non-member, or a member of std::ostream. The operator<< for
most of the built in types are members of std::ostream. For a
user defined type, of course, you're not allowed to add
functions to std::ostream, so you must define it as a non-member
function.
As far as I know the only operator that you have some freedom with is
the ()-operator, with which you can decide how many argument it takes,
all the others are quite fixed, in arity, precedence, postfix/prefix, etc.
Of course, the built-in () operator also accepts a variable
number of arguments, so this freedom isn't "extending" the
language in any way.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

May 6 '07 #15

This discussion thread is closed

Replies have been disabled for this discussion.