Solved

overloading operator<< and it's design

Posted on 1998-09-23
14
219 Views
Last Modified: 2013-12-03
Using C++'s iostream class, one can set the precision and width of built in types, such as FLOAT.
I have created my own class. Let's call it MYCARCLASS. When I overload the OPERATOR<< I first check MYCARCLASS.m_outputtype. This variable instructs the overloaded OPERATOR<< on how to format the output of my data.
EX.
if m_outputtype = DETAILED
cout << mycar << endl;
produces
2.2l 4cly 3vpc single cam ...
whereas
if m_outputtype = BRIEF
cout << mycar << endl;
produces
4cly Sedan ...
1. Is it possible to set up the following?
cout << showcardetail;
cout << mycar; (DETAILED INFO)
2. Am I correct that the following code is not possible?
cout.setcardetail(DETAILED);
cout << mycar; (DETAILED INFO)
3. Is there any rational against setting m_outputtype = NNNNN to decide the output?
mycar.setype(DETAILED); (DATA MEMBER IS PRIVATE)
cout << mycar << endl;

Notes:
1. I will be using ostream and ofstream.
2. In my real problem I have several output formats, hence input formats.
3. Implementation code for question number two, if possible, would be needed.
4. Include in your answer implications for complementary operator>>.
 
-Thanks
-Paullkha
0
Comment
Question by:Paullkha
  • 8
  • 6
14 Comments
 
LVL 2

Author Comment

by:Paullkha
ID: 1173527
Edited text of question
0
 
LVL 2

Author Comment

by:Paullkha
ID: 1173528
Edited text of question
0
 
LVL 2

Author Comment

by:Paullkha
ID: 1173529
Edited text of question
0
 
LVL 22

Accepted Solution

by:
nietod earned 50 total points
ID: 1173530
answers coming.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1173531
I think the best thing for you to do is to use IO manipulators.  There are like the "endl" you use to start a new line in a stream.  There really are functions, but they don't look like it.

details follow.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1173532
the stream classes overload << to accept a pointer to a function that takes a reference to a stream in the parameters and returns a reference to a stream (presumably the same stream).  When the overloaded << function is called, it it calls the function using the pointer and passes a copy of the stream.  In other words if you specify a function name on the right side of <<, it will call the function for you.  (assuming the funciton has the right parameters and return values).  

To use this, write two functions, like

ostream & showcardetail(ostream &O)
{
   // do something here.
   return O;
}

ostream & showcarbrief(ostream &O)
{
   // do something here.
   return O;
}

then you can manipulate the stream like

cout << showcardetail;
cout << mycar;
cout << showcarbrief  << myothercar;
0
 
LVL 22

Expert Comment

by:nietod
ID: 1173533
>> 2. Am I correct that the following code is not possible?
>>   cout.setcardetail(DETAILED);
>>   cout << mycar; (DETAILED INFO)
That is right.  That is not possible.  You cannot add a new function to an existing stream class.  You can derive your own stream class and add the function to it. BUT that is not ussually a good idea.  This is because that approach doesn't help you work with and streams that were declared from classes that you didn't declare, like cout with is an ostream, not a stream class that you created.

>>   3. Is there any rational against setting m_outputtype = NNNNN to decide the output?
>>   mycar.setype(DETAILED); (DATA MEMBER IS PRIVATE)
>>   cout << mycar << endl;
It depends on the circumstances, but ussually that is not a good idea.  First of all, it means that each car object needs to "carry around" settings about its display options.  That can waste space.  Second of all, it can lead to confussion.  Code in one place might set the settings and assume they will remain, but code elsewhere might set them differently.  The solution to prevent this problem is to always set the settings immediately before you print.  But in that case, there is no need to store the settings with the object, since you are always setting these settings immediately before they are used.  

However, if an object's display properties is really tightly associated with an object, and not with the code that tries to print the object, then it makes sense.   (But that sentince probably doesn't).   What I mean is, if in some places in the code you will want objects to be printed in detail and other places in the code you want it to be brief then the setting is associated with the code, not the object printed.   On the other hand, if some objects should ussualy be printed brief regardless of where they are printed, and others should be detailed, regardless of where they are printed, then it makes sense to store the setting in the object.

>> Include in your answer implications for complementary operator>>.
Ussually you would not want this sort of approach for input.  That is, you don't want a setting for inputing a brief or a detailed object.  (But sometimes you have to go that way)   If possible, you want the input functions to examine the input and determine if it is getting detailed or brief information.   To do so, it means the format of the brief and detailed information must be distinct enough that it can tell the difference.  you have
2.2l 4cly 3vpc single cam ...
4cly Sedan ...

so you can use the the engine size to tell the difference.  If the first number has units of "l", then you are reading a detailed format, otherwise if the units are cly, the format is brief.

I hope this helps, ask if you have questions.
     
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 2

Author Comment

by:Paullkha
ID: 1173534
So the function ostream & showcarbrief(ostream &O) could look as follows:
ostream & showcardetail(ostream &O)
{
   m_myoutput_type = DETAILED;
   return O;
}
I would still have only one friend input operator>>, correct? It would have to figure what format the data is in(mini-parser)?
I would need a function for ofstream as well, correct?
Am I correct that the following code,cout.setcardetail(DETAILED), is impossible or is it impractical or both?


0
 
LVL 2

Author Comment

by:Paullkha
ID: 1173535
OK I'll ask :)

cout << showcardetail;-This statment must set a static variable in MYCARCLASS
cout << mycar;-This object must look at the static variable to decide how to print itself.
I am confused by your statement ,"there is no need to store the settings with the object". It is not store with the object instation, it is stored with the class. (Because I can not see any other way.)
Everything else makes sense.
Side note, so if I have 14 formats, I will need
cout<<showtypeBrief<<showtypeDetailed<<...<showtype14;
Could I have to resort to?
cout<<showtype(MYCARCLASS::Brief);
 

0
 
LVL 22

Expert Comment

by:nietod
ID: 1173536
>>So the function ostream & showcarbrief(ostream &O) could look as follows:
>>      ostream & showcardetail(ostream &O)
>>     {
>>         m_myoutput_type = DETAILED;
>>         return O;
>>      }
Yes, but I question the m_myoutput_type part.  What is that doing?  Is that some sort of global variable it is setting.  It would probably have to be.  That would work if the code is single threaded, it could be very dangerious if the code is multi-threaded.  

Now that I think about it, user defined manipulates aren't much good in this case, they really are  for changing the existing settings in the stream, like altering the precision and fill character etc.  They aren't very good at changing a custom setting as you are trying to do.

There is another approach to the custom setting that I will post at the end.

>> I would still have only one friend input operator>>, correct? It would
>> have to figure what format the data is in(mini-parser)?
Yes, based on what you read in the beginning you figure out what remains to be read.  This tends to be the safest code and the easiest for the programmer (that uses the code, not that writes the >> function.)


>> I would need a function for ofstream as well, correct?
No.  All these functions deal with ostream, the base class of ofstream.  So they work with ofstream and iostream and iofstream and lots of others.

>>Am I correct that the following code,cout.setcardetail(DETAILED),
>> is impossible or is it impractical or both?
yes it is impossible.  You cannot add a function to a  class defined in the run-time library.  You can define manipulators that take parameters however, like

cout << SetCarFormat(DETAILED) << car1 << SetCarFormat(BRIEF);

I can show you how to do that, but it is somewhat discouraged (by the library designer himself)..  It is a little messy, so if you can get by with a limited number of no-parameter manipulators, use that instead of a sigle manipulator that takes parameters.

0
 
LVL 22

Expert Comment

by:nietod
ID: 1173537
Now what you can do instead of using the manipulator and setting a global variable like myoutput_type, is write a new class, that "binds" the formatting option to the class data you want to print.

The new class would have members that store the formatting settings and a member that stores a pointer to or reference to the object you want to print.  For example,

enum CarFmtTyp
{
 DETAILED,
 BRIEF
};

class CarFormat
{
   CarFmtTyp FmtTyp;
   const Car * CarPtr;
public:
    CarFormat (CarFmtTyp T,const Car &Car) :
    CarFmtTyp(T),
    CarPtr(&Car)  {}:
    ostream & operator << (ostream &O);
    {
         if (CarFmtTyp == DETAILED)
            O << Car.size << Car.Cylinder;
         else
            O << Car.Cylinder;
      return O;
    }

Notice this class takes formatting options and a car when it is constructed and saves them.  When it is ouputted it uses the formatting options to format the car (it would probably be a friend of car.)

To use this, you don't have (or don't have to have) << operators in the car class.  The format class will do the work.  To ouput a car you would construct a temporary format object in the stream like

cout << CarFormat(DETAILED,Car1)  << CarFormat(BRIEF,Car2);

these temporary objects exist only until they are ouputed (which really ouputs the car) and then they are deleted.   This is a very good technique becuase it allows you lots of flexibility.  You can add lots of format options.  You can have the format object print some or all of the information using virtual functions so it works well for class heirarchies.  The format object can call functions in the car class and pass formatting options if needed.  Lots of room for features this way.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1173538
Note I didn't see your last comment when I responded to the one before it.  I sort of answered things in it, but not explicitly.

>> cout << showcardetail;-This statment must set a static variable in MYCARCLASS
>>      cout << mycar;-This object must look at the static variable to decide how to print itself.
yes, that is how you would have to do it.  It would work in a single threaded environment, but I would avoid that approach because it certainly won't work in a multi-threaded environment.

>> I am confused by your statement ,"there is no need to store the
>> settings with the object". It is not store with the object instation, it
>> is stored with the class.
That is correct.  If you store the setting with each object, the settings are part of the object and "stick" with the object.  You would not use the manipulators for this.  You would use member functions of the class.  This is used sometimes, but is not appropriate for all classes as I tried to explain.  If the settings are associated with the code that does the printing, rather than the particular object that is printed, then you would not store the settings in each object.  You could store the settings in static member of the class, but as I said above, that is not the best practice.

>> Side note, so if I have 14 formats, I will need
>>      cout<<showtypeBrief<<showtypeDetailed<<...<showtype14;
>>      Could I have to resort to?
>>      cout<<showtype(MYCARCLASS::Brief);
Yes, I can show you how, but as I said, the designers of the library themselves recommend you don't write manipulators that take parameters.   They would recommend that you write 14 different manipulators rather than 1 that takes 1 of 14 possible parameters (enums).  At least they would recommend you consider it.  However, I recommend that you consider the format object as an alternative.  That is from Bjarne Stroustrup, the inventor of C++ and I listed some of the benefits I see in it.
0
 
LVL 2

Author Comment

by:Paullkha
ID: 1173539
I actually was looking at Stroustrup's design with his floating-point format, and trying to avoid it. :(    -Oh, well. Guess father of C++ knows best.

-Thanks.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1173540
There are lots of benefits to that design.  I'd seriously consider it.  Unfortuantely, I don't think he explained it well and I don't think he discussed the advantages of it.  
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now