[comp.lang.c++] possible to overload << and pass an object ptr?

todd@Quotron.COM (Todd Booth) (03/24/91)

Consider the following struct:

struct S {
	void operator<<(char p1) { cout << p1; }
};

S *o2 = new S;
o2 << 'a'; // error <--- How can I resolve this?
*o2 << 'a'; // no problem, but ugly

S o1;
o1 << 'a'; // no problem

thanks, 

--todd

--
todd (booth) 

todd@quotron.com 213 302-4368

gyro@kestrel.edu (Scott Layson) (03/24/91)

In article <todd.669759003@premises1.Quotron.COM> todd@Quotron.COM (Todd Booth) writes:
>Consider the following struct:
>
>struct S {
>	void operator<<(char p1) { cout << p1; }
>};
>
>S *o2 = new S;
>o2 << 'a'; // error <--- How can I resolve this?
>*o2 << 'a'; // no problem, but ugly
>
>S o1;
>o1 << 'a'; // no problem

I have used a two-level class structure in cases like this:

struct S {
     struct S_impl {
          // ... whatever
     } *impl;
  public:
     void operator<<(char p1) { cout << p1; }
     // constructors etc.
};

This is a pretty good solution, but it starts to break down when you
want to have parallel hierarchies of inner and outer classes, because
`impl' (the sole data member of S which will be inherited by all of
its derived classes) is always of type `S_impl*', while you will want
it to be a pointer to the appropriate derived class of `S_impl'.
Casting `impl' to be the right type is a bit messy but works, until
you start using multiple inheritance with virtual base classes, at
which point you're totally up a tree.

For these reasons I have toyed with the idea of proposing to the
committee a system for declaring "member functions" on the type `C*'
where C is some class, so that your first example could be made to
work without the two-level class structure.  Unfortunately, I have
never managed to come up with a proposal I find adequately elegant.

-- Scott Layson Burson
   Gyro@Reasoning.COM

Ari.Huttunen@hut.fi (Ari Juhani Huttunen) (03/25/91)

In article <1991Mar24.074308.28666@kestrel.edu> gyro@kestrel.edu (Scott Layson) writes:

>For these reasons I have toyed with the idea of proposing to the
>committee a system for declaring "member functions" on the type `C*'
>where C is some class, so that your first example could be made to
>work without the two-level class structure.  Unfortunately, I have
>never managed to come up with a proposal I find adequately elegant.

How about this one?

struct S {
friend  void operator<<(S *s, char p1) { *s << p1; }
	void operator<<(char p1) { cout << p1; }
};
--
Ari Huttunen, email: Ari.Huttunen@hut.fi, phone: 90-7285944

gyro@kestrel.edu (Scott Layson) (03/26/91)

In article <ARI.HUTTUNEN.91Mar24212428@punisher.hut.fi> Ari.Huttunen@hut.fi (Ari Juhani Huttunen) writes:
>In article <1991Mar24.074308.28666@kestrel.edu> gyro@kestrel.edu (Scott Layson) writes:
>
>>For these reasons I have toyed with the idea of proposing to the
>>committee a system for declaring "member functions" on the type `C*'
>>where C is some class, so that your first example could be made to
>>work without the two-level class structure.  Unfortunately, I have
>>never managed to come up with a proposal I find adequately elegant.
>
>How about this one?
>
>struct S {
>friend  void operator<<(S *s, char p1) { *s << p1; }
>	void operator<<(char p1) { cout << p1; }
>};

Ah.  Indeed that works for the specific example under consideration.
I was thinking of the example I had encountered in the past, where I
basically wanted to hide from the outside world the fact that a class
was implemented as a pointer.  So, I wanted to say `obj.mfunc()'
rather than `obj->mfunc()'.

Granted, overloadable `.' would accomplish this.  I seem to recall,
however, that that still isn't all I wanted.  Let me think about this.

-- Scott Layson Burson
Gyro@Reasoning.COM

gyro@kestrel.edu (Scott Layson Burson) (03/26/91)

In article <1991Mar25.192002.6392@kestrel.edu> I wrote:
>In article <ARI.HUTTUNEN.91Mar24212428@punisher.hut.fi> Ari.Huttunen@hut.fi (Ari Juhani Huttunen) writes:
>>How about this one?
>>
>>struct S {
>>friend  void operator<<(S *s, char p1) { *s << p1; }
>>	void operator<<(char p1) { cout << p1; }
>>};
>
>Ah.  Indeed that works for the specific example under consideration.
>I was thinking of the example I had encountered in the past, where I
>basically wanted to hide from the outside world the fact that a class
>was implemented as a pointer.  So, I wanted to say `obj.mfunc()'
>rather than `obj->mfunc()'.
>
>Granted, overloadable `.' would accomplish this.  I seem to recall,
>however, that that still isn't all I wanted.  Let me think about this.

I must correct myself.  Overloadable `.' would do nothing of the kind,
insofar as I understand the current proposal, because a pointer type
cannot have member functions and therefore cannot, in particular,
overload `operator.'.

I think the bottom line here is that C++ provides very well for the
"value model" of objects, but not very well for the "pointer model"
(see the commentary that starts on p.191 of E&S).  There are good
reasons for providing the value model, which I don't disagree with,
but I think the pointer model got unnecessarily left out in the cold.

-- Scott Layson Burson
Gyro@Reasoning.COM

Ari.Huttunen@hut.fi (Ari Juhani Huttunen) (03/26/91)

In article <1991Mar25.192002.6392@kestrel.edu> gyro@kestrel.edu (Scott Layson) writes:

Ari>How about this one?
Ari>
Ari>struct S {
Ari>friend  void operator<<(S *s, char p1) { *s << p1; }
Ari>	void operator<<(char p1) { cout << p1; }
Ari>};

Scott>Ah.  Indeed that works for the specific example under consideration.

No, this does not work. Or at least it does not work with g++ 1.37.1. The
error is:
	operator has no user-defined argument type
(meaning the friend operator.) Though I think this _should_ work.
--
Ari Huttunen, email: Ari.Huttunen@hut.fi, phone: 90-7285944

steve@taumet.com (Stephen Clamage) (03/28/91)

Ari.Huttunen@hut.fi (Ari Juhani Huttunen) writes:

|Ari>struct S {
|Ari>friend  void operator<<(S *s, char p1) { *s << p1; }
|Ari>	void operator<<(char p1) { cout << p1; }
|Ari>};

|No, this does not work. Or at least it does not work with g++ 1.37.1. The
|error is:
|	operator has no user-defined argument type
|(meaning the friend operator.) Though I think this _should_ work.

It should _not_ work.  It has always been a requirement that an overloaded
operator function must have at least one parameter of class type.
A pointer to a class type is not a class type.  We can argue about
whether the restriction should be relaxed (I don't believe it should be),
but the language definition make the code illegal.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

jss@gold.kpc.com (Jerry Schwarz) (03/29/91)

In article <todd.669759003@premises1.Quotron.COM> todd@Quotron.COM (Todd Booth) writes:

   *o2 << 'a'; // no problem, but ugly


Beauty is in the eye of the beholder.  Having worked a lot with
ostream* variables I have written stuff like the above a lot and no
longer find it ugly.  I certainly wouldn't contort my class
definitions in order to avoid it.

Jerry Schwarz