Operator overload and pointers

R

Rg

Hello, everyone.

I'm curious. Why can't I overload an operator only with pointers to
class objects?

For instance:

class SomeClass {
friend SomeClass *operator<<(SomeClass *, int);
};

This code will give me the following error message in G++:

error: 'SomeClass* operator>>(SomeClass*, int)' must have an
argument of class or enumerated type

However, if I use references instead of pointers, the code will compile
fine. I'd like to know the reason behind that restriction.

Thanks!
Rg
 
S

Salt_Peter

Rg said:
Hello, everyone.

I'm curious. Why can't I overload an operator only with pointers to
class objects?

Why would you ever want to? A pointer is not an object but a reference
is.
Thats a critical distinction here because a reference will not accept
an invalid object but a pointer will.
You can think of a reference as a runtime check.
Incidentally, if i understand your request, you already have a
SomeClass pointer: this.
Why not use that?
For instance:

class SomeClass {
friend SomeClass *operator<<(SomeClass *, int);
};

This code will give me the following error message in G++:

error: 'SomeClass* operator>>(SomeClass*, int)' must have an
argument of class or enumerated type

Exactly, a pointer is not an object.
However, if I use references instead of pointers, the code will compile
fine. I'd like to know the reason behind that restriction.

The reason is as explained above. Its not a restriction, its a feature.

Isn't the goal here to inject an integer via a stream?
If so, why not declare and define a member operator<< that takes an
integer?

#include <iostream>
#include <ostream>

class SomeClass
{
int n;
public:
SomeClass() : n(0) { }
void operator<<(const int& r_n) // by value is ok too
{
n = r_n;
}
friend std::eek:stream& operator<<(std::eek:stream& os, SomeClass& r_sc)
{
return os << r_sc.n;
}
};

int main()
{
SomeClass instance;
instance << 5;
std::cout << instance << std::endl;
}
/*
5
*/

Or did i miss something?
 
R

Rg

(SNIP)

Isn't the goal here to inject an integer via a stream?
If so, why not declare and define a member operator<< that takes an
integer?

(SNIP)

Or did i miss something?

No, you didn't. I was very brief in the explanation of the "issue" I
was running into. But, as it seems, there was no need for me to be more
specific. The problem is that I wasn't understanding a basic fact of
operator overloading: that pointers are primitive types and hence
cannot be overloaded.

I wanted to use pointers for syntax sugar. I'm very used to C and very
little used to C++, and hence I feel more comfortable working with
pointers rather than working with references. But that's another story.

Anyway, your examples were very clear, so thanks for the assistance!
 
S

Salt_Peter

Alf said:
* Salt_Peter:

You got that exactly backwards.

What? What did you have for breakfast today?
look at the context.

A pointer may, or may not, point to an instance.
A reference is an object.
 
A

Alf P. Steinbach

* Salt_Peter:
What? What did you have for breakfast today?
look at the context.

A pointer may, or may not, point to an instance.
Right.


A reference is an object.

Wrong.
 
S

Salt_Peter

Alf said:
* Salt_Peter:

Wrong.

Sorry, i'm too stupid to understand that.
Can you please expand on your statement considering:

double n(5);
// double& r; // illegal
double& r_n(n);

&n = 0x7fff507b6e18
&r_n = 0x7fff507b6e18
sizeof(n) = 8
sizeof(r_n) = 8
typeid(n).name() = d
typeid(r_n).name() = d

Or are we building compilers?
 
A

Alf P. Steinbach

* Salt_Peter:
Sorry, i'm too stupid to understand that.

A reference is not an object. An object is by definition a region of
storage. A reference does not necessarily occupy a region of storage,
and is by definition not an object.

Can you please expand on your statement considering:

double n(5);
// double& r; // illegal
double& r_n(n);

&n = 0x7fff507b6e18
&r_n = 0x7fff507b6e18
sizeof(n) = 8
sizeof(r_n) = 8
typeid(n).name() = d
typeid(r_n).name() = d

For example, you can't take the address of a reference, only of what it
refers to, which the above illustrates.

On the other hand, a pointer variable is an object.

You can take the address of a pointer variable.
 
F

Frank Puck

Salt_Peter said:
Thats a critical distinction here because a reference will not accept
an invalid object but a pointer will.
You can think of a reference as a runtime check.

Object &getObject(void)
{ Object *p = 0;
return *p;
}

this compiles and runs fine. You can initialize another reference with it as
long as you don't try to access the object.
So there is no runtime check for references.
 
F

Frank Puck

Alf P. Steinbach said:
A reference is not an object. An object is by definition a region of
storage. A reference does not necessarily occupy a region of storage, and
is by definition not an object.


so you can store a reference in no memory?


class A
{
};
typedef A &RefA;
typedef A *PointerA;

an instance or RefA occupies the same amount of memory like PointerA.
 
A

Alf P. Steinbach

* Frank Puck:
so you can store a reference in no memory?

Right, a reference does not necessarily take up any memory space.

class A
{
};
typedef A &RefA;
typedef A *PointerA;

an instance or RefA occupies the same amount of memory like PointerA.

Chapter and verse[1], please.


Notes:
[1] When newbies start spewing forth disinformation, we generally ask
them to provide a relevant quote from the standard; the phrase "chapter
and verse" is a request for such a quote, with the connotation that
whatever the phrase applies to is rubbish, fantasy, meaningless, etc.
 
S

Salt_Peter

Alf said:
* Salt_Peter:

A reference is not an object. An object is by definition a region of
storage. A reference does not necessarily occupy a region of storage,
and is by definition not an object.

A reference is not allowed, under any circumstance, to return a size of
0.
And it definitely occupies storage since its address is the same as the
object its pointing to.
Can i say that A a below is not an object because it doesn't occupy
storage? no.

struct A{
};

int main()
{
A a;
A& r_a(a);
std::cout << sizeof(a) << std::endl;
std::cout << sizeof(r_a) << std::endl;
}

/*
1 // <- required by law
1 // <- required by law
*/

Additionally, a reference that is *not* (or no longer) referencing a
valid object is undefined behaviour.
The same is not true of a pointer.
For example, you can't take the address of a reference, only of what it
refers to, which the above illustrates.

On the other hand, a pointer variable is an object.

i disaggree, a pointer is an address, period. It may or may not point
to an object.
I'm not going to be convinced that a nullptr is an object, for example.
Its not.

if i delete a pointer, i'm deleting the object its pointing to. In
fact, i can argue that the pointer doesn't know nor care about what
just happened. Its dumb and knows only its type unless void*.
One can argue that the pointer has "state" when its actually pointing
to something. The same can't be said of a reference: a reference
without "state" is undefined behaviour.
You can take the address of a pointer variable.

That doesn't mean its a valid pointer. And much less that its an
object.

<Pulls out his boxing gloves, lol>
 
A

Alf P. Steinbach

* Salt_Peter:
A reference is not allowed, under any circumstance, to return a size of
0.
Meaningless.


And it definitely occupies storage
Incorrect.


since its address is the same as the
object its pointing to.
Incorrect.


Can i say that A a below is not an object because it doesn't occupy
storage? no.
Meaningless.


struct A{
};

int main()
{
A a;
A& r_a(a);
std::cout << sizeof(a) << std::endl;
std::cout << sizeof(r_a) << std::endl;
}

/*
1 // <- required by law
1 // <- required by law
*/

Additionally, a reference that is *not* (or no longer) referencing a
valid object is undefined behaviour.
Incorrect.


The same is not true of a pointer.
Right.



i disaggree, a pointer is an address, period. It may or may not point
to an object.

A variable is an object, by definition (and I mean the standard's
definition).

I'm not going to be convinced that a nullptr is an object, for example.
Right.


Its not.
Meaningless.


if i delete a pointer, i'm deleting the object its pointing to. In
fact, i can argue that the pointer doesn't know nor care about what
just happened. Its dumb and knows only its type unless void*.
One can argue that the pointer has "state" when its actually pointing
to something. The same can't be said of a reference: a reference
without "state" is undefined behaviour.


That doesn't mean its a valid pointer.
Right.


And much less that its an object.

Meaningless.
 
K

Kai-Uwe Bux

Salt_Peter said:
A reference is not allowed, under any circumstance, to return a size of
0.
And it definitely occupies storage since its address is the same as the
object its pointing to.

Nope: not the reference occupies memory but the object it refers to. If you
write an expression that appears to take the address of a reference, you
actually don't do that. This is why the following does not compile:

typedef int & i_ref;

int main ( void ) {
int i;
i_ref ir ( i );
i_ref* i_ref_ptr irp = &ir;
}

There are no pointers to references. If references where objects (as opposed
to the objects they refer to), we could have pointers to references.

Can i say that A a below is not an object because it doesn't occupy
storage?

It does occupy memory.
no.

struct A{
};

sizeof(A) > 0 is required by the standard. Instances of A will occupy
memory.
int main()
{
A a;
A& r_a(a);
std::cout << sizeof(a) << std::endl;
std::cout << sizeof(r_a) << std::endl;
}

/*
1 // <- required by law
1 // <- required by law
*/

Well, it is required that sizeof(a) > 0 and that sizeof(a) == sizeof( r_a ).

However, you are not taking the size of the reference you are taking the
size of the object a. The reference may or may not occupy memory.

Additionally, a reference that is *not* (or no longer) referencing a
valid object is undefined behaviour.
The same is not true of a pointer.

True but irrelevant for the question whether references (not the objects
they refer to) are objects.

i disaggree, a pointer is an address, period. It may or may not point
to an object.

One needs to distinguish the pointer variable (a region in memory), the
value of that variable (some bit pattern stored in that region), and the
pointee identified by the value. The first is an object. The second is a
value that may or may not point to yet another object. Most of the time, it
suffices to distinguish the first and the third and gloss over the
difference between the first and the second.

I'm not going to be convinced that a nullptr is an object, for example.

A pointer variable of type int* whose value is (int*)0 is definitely an
object (of type int*). It so happens that this int* does not point to an
object of type int.

Depends on what you mean by nullptr. A const expression such as (int*)0 does
not refer to an object but only to a possible value of an object of type
int*.
if i delete a pointer, i'm deleting the object its pointing to. In
fact, i can argue that the pointer doesn't know nor care about what
just happened. Its dumb and knows only its type unless void*.
One can argue that the pointer has "state" when its actually pointing
to something. The same can't be said of a reference: a reference
without "state" is undefined behaviour.


That doesn't mean its a valid pointer.
True.

And much less that its an object.

False: it means exactly that. You can take the address of objects and
functions; and (as far as I know) you cannot take the address of anything
else.
<Pulls out his boxing gloves, lol>

Have fun boxing Alf. You'll loose cause he is right.


Best

Kai-Uwe Bux
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,152
Latest member
LorettaGur
Top