Click to See Complete Forum and Search --> : overloading operator >>
jimbucc
May 17th, 2002, 07:29 AM
I am having trouble overloading operator >>. I can overload operator << with no problem but the reverse is giving me difficulty - perhaps I am missing something.
Here's some sample code.
class c2
{
public:
short i;
double d;
.... other members - different from class c1
c2();
~c2();
}
class c1
{
int i;
double d
... // other members
public:
c1& operator<<(const c2& p) { return *this;} // this compiles
c2& operator>>(const c1& p) {..} // this won't compile
In operator << I want to populate a c1 object with members from c2.
In operator >> I want to populate a c2 object with members from c1.
Any ideas - please help. I can't find a good example in any texts.
Thanks.
JB
curious
May 17th, 2002, 07:53 AM
what error are you getting ? post that.
Also you don't have a ; to end class c2 .. is this a typo ?
jimbucc
May 17th, 2002, 08:43 AM
Thanks for the reply. I had the syntax wrong.
operator>> should be:
c2& operator>>(const c2& p)
{
return p;
}
Stitch
May 20th, 2002, 11:03 AM
I think there's another error in your code, logical rather than syntatic
--In operator << I want to populate a c1 object with members from c2.
--In operator >> I want to populate a c2 object with members from c1.
The implication of the code in your post is
c1 x;
c1 y;
c2 z;
x << z; // You get what you want
z = x >> y; // I don't think you want this
To get the behaviour you seem to want, you would need to put the
>> operator into the c2 class. It has to be this way in order for
c2 to be on the LHS. the other option is to do it outside of either
class.e.g
c2 &operator>>(c2 &x, c1 &y){...}
c1 &operator<<(c1 &x, c2 &y){...}
Graham
May 21st, 2002, 03:57 AM
In an earlier thread on this subject, I suggested that using operators >> and << was probably not a good idea. I think the fact that there is so much confusion about what needs to be declared, and how to declare it tends to back up my point. the problem arises because there is no secure mental mapping of those operators to the task assigned to them, so you're constantly having to remind yourself of what is supposed to be happening. Replace them with named member functions like "SupplyTransferData" and "ReceiveTransferData" and at least you now know what each function is supposed to do. Than, if you absolutely insist on implementing the operators, you can at least implement them as free functions using those member functions:
class A
{
public:
struct AData
{
// Data to be transferred
};
AData SupplyTransferData();
};
class B
{
public:
void ReceiveTransferData(const A::AData&);
};
B& operator<<(B& b, const A& a)
{
b.ReceiveTransferData(a.SupplyTransferData());
return b;
}
The "AData" struct is only an illustration, but you get the idea.
Mind you, if you do carry on with using << and >> in this way, I just hope that I'm never the one to have to pick up and maintain your code.
jimbucc
May 21st, 2002, 04:08 AM
Thanks for all of the input. The extent to which I am using these operators is minimal - one call. My classes have a lot of members and using functions is a good idea - which I've done. I like the flexibility if the operator. Plus, the operators are self-explanatory *a >> *b - load a to b
*a << *b - load b to a.
If this isn't easy to follow, then I hope this code never crosses the pond.
;)
Thanks again for your help. If I do get a lot of complaints about this, from my compadres, I will implement functions.
JB
Graham
May 21st, 2002, 04:55 AM
I'm not trying to be offensive about this, honestly. I just think that using an operator to do a job that is done more clearly by a function call tends to obscure code, and we should always strive for clarity. I have to say that I disagree that "a >> b" is self-explanatory. Seeing that in isolation, my first guesses would be that either a and b are integral and it's shifting bits, or that a is derived from istream and it's reading the value of b. Also, you have potentially two ways of doing the same thing: "a >> b" and "b << a". Is it obvious that these two are identical? Why should they be?
Another factor is that, by doing it this way, you're introducing a strong coupling between the two classes, and another good guideline is "low coupling, high coherence" - that is, always take the design that reduces coupling. If we modify my previous suggestion and encapsulate the transferred data into a separate class (or struct), then we can eliminate the coupling entirely:
// CommonData.h
struct CommonData
{
// whatever
};
// A.h
#include "CommonData.h"
class A
{
public:
CommonData SupplyData() const;
void ReceiveData(const CommonData&);
// etc.
};
// B.h
#include "CommonData.h"
class B
{
public:
CommonData SupplyData() const;
void ReceiveData(const CommonData&);
// etc.
};
With this structure, classes A and B have no dependency on each other, you're not stuck with forward declarations or the need to artificially introduce pointers (to avoid the need for a complete class declaration). You can also easily introduce class C (also transferring CommonData) into the scheme. Serialisation is also simple because, by providing the member functions, you have a ready-made way to consistently serialise the common data. And consider also that, if you do decide you want to serialise these classes, you're going to have another set of operator << and >> to deal with doing a different job to the original.
Just because it's only used once now, doesn't mean that there won't be a great demand for it in the future. Also, why expend all this effort on something that's only used once?
I went down this road of defining operators to do (inappropriate)things "because I could" many years ago. I wouldn't do it again, because I have been in the situation of picking up code like that - I hated it and resolved that I wouldn't do it again and potentially put someone else through it.
Why not implement operator=() ?
//B.h (others as before)
#include "CommonData.h"
class B
{
public:
CommonData SupplyData() const;
void ReceiveData(const CommonData&);
B& operator=(const CommonData& cd)
{
ReceiveData(cd);
return *this;
}
// etc.
};
// main.c
#include "A.h"
#include "B.h"
int main()
{
A a;
B b;
// do stuff...
b = a.SupplyData();
}
I don't think that's as clear as "b.ReceiveData(a.SupplyData());", but I do think it's a bit clearer than "b << a" or "a >> b".
As a final alternative, you could replace the "Supply" and "Receive" functions with simple accessors:
struct CommonData
{
// whatever
CommonData& operator=(const CommonData&);
};
class A
{
public:
const CommonData& CommonStuff() const;
CommonData& CommonStuff();
};
// Ditto for class B.
int main()
{
A a;
B b;
// do stuff
b.Commonstuff() = a.CommonStuff();
};
Now that's expressive (and extendable).
Like I say, I'm not trying to be insulting or anything, I'm just trying to pass on the lessons of personal experience.
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.