473,407 Members | 2,676 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,407 software developers and data experts.

overload "operator->"

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
14 2774
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
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
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
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
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
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
"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
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
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
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
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
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
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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

34
by: Pmb | last post by:
I've been working on creating a Complex class for my own learning purpose (learn through doing etc.). I'm once again puzzled about something. I can't figure out how to overload the assignment...
6
by: Guagua | last post by:
I have lots of expression like "a <?= b" in my original code. However I switch to another compiler from gcc that doesn't support operator "<?=". How could I define the operator so that the...
1
by: Jongmin Lee | last post by:
Hi everybody, I overloaded "operattor== " for comparing two objects. However, I can't compare one instance to null valued object instance. How to solve this problem? public class Custom {...
5
by: Robin.Liu | last post by:
Hello all! I create a class A, and I want to insert an integer into the object of class A directly. Like this A a = new A(); a = 1; The compiler doesn't allow me to overload the operaotr...
9
by: Emanuele Aina | last post by:
I have some code which does a lot of "in" on lists containing objects with no __eq__ defined. It all goes fast until I add the __lt__() method: then I have a slowdown comparable to the one I get...
2
by: John Goche | last post by:
Hello, Could anyone please provide with some information on the C++ overloaded cast operator and in which circumstances this might be useful? I have consulted several references but found no...
1
by: Sunny | last post by:
The way to overload operator << is : ostream& operator << (ostream& os, const Obj& obj); and this is a member function. My question is why do we need to provide a const reference of Obj as...
5
by: Gianni Mariani | last post by:
I'm hoping someone can tell me why using member address of works and why using the dot operator does not in the code below. The code below uses the template function resolution mechanism to...
2
by: babakandme | last post by:
Hi everybody:D I've a string that contains the name of a class. Some members told that I can use """Stringizing Operator (#)""", but the problem is here, that I have the string, & I want...
3
by: tvnaidu | last post by:
I compiled tinyxml files (.cpp files) and when I am linking to create final exe in Linux, I am getting lot of errors saying "undefiend reference" to "operator new" and "delete", any idea?. ...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.