Ok, I'm going post all of my code, and hopefully someone can tell me where my error is at. I'm guessing I need to do a cin.ignore() somewhere, but I'm not sure where. I've tried it in a couple of places, but nothing has fixed the problem completely.

#include <string>
#include <iostream>
using namespace std ;

class Person
{
public:
    Person ( ) ;
    Person ( string theName ) ;
    Person ( const Person & theObject ) ;

    string getName ( ) const ;
    Person operator =( const Person & rtSide ) ;
    friend istream & operator >>( istream & is , Person & p ) ;
    friend ostream & operator <<( ostream & os , const Person & p ) ;
private:
    string name ;
} ;



#include "person.h"

Person::Person ( ) : name ( "John Doe" )
{ }

Person::Person ( string theName ) : name ( theName )
{ }

Person::Person ( const Person & theObject )
{
    name = theObject.name ;
}

Person Person::operator =( const Person & rtSide )
{
    //useless here
    if ( name == rtSide.name )
        return *this ;

    name = rtSide.name ;
    return *this ;
}

istream & operator >>( istream & is , Person & p )
{
    cout << "Name:  " << flush ;
    getline ( is , p.name ) ;
    
    return is ;
}

ostream & operator <<( ostream & os , const Person & p )
{
    os << "Name:  " << p.name << endl ;

    return os ;
}

string Person::getName ( ) const
{
    return name ;
}



#include <string>
#include <iostream>
using namespace std ;

class Vehicle
{
public:
    Vehicle ( ) ;
    Vehicle ( string newManufacturer , int newCylinders , Person newOwner ) ;
    Vehicle ( const Vehicle & theObject ) ;

    Vehicle operator =( const Vehicle & rtSide ) ;
    friend istream & operator >>( istream & is , Vehicle & v ) ;
    friend ostream & operator <<( ostream & os , const Vehicle & v ) ;
protected:
    string manufacturer ;
    int cylinders ;
    Person owner ;
} ;

class Truck : public Vehicle
{
public:
    Truck ( ) ;
    Truck( string manf , int cyl , Person newO , double newLoad, int newTowCap, int maxPas, bool kingCab ) ;

    Truck operator =( const Truck & rtSide ) ;
    friend istream & operator >>( istream & is , Truck & t ) ;
    friend ostream & operator <<( ostream & os , const Truck & t ) ;

    void setOwner ( ) ;
private:
    double loadCap ;
    int towingCap ;
    int maxPassengers ;
    bool kingCab ;
} ;



#include "person.h"
#include "vehicle.h"

Vehicle::Vehicle ( ) : manufacturer ( "No manufacturer set" ) , cylinders ( 0 ) , owner ( Person ( ) )
{ }

Vehicle::Vehicle ( string newManufacturer , int newCylinders , Person newOwner ) : manufacturer ( newManufacturer ) , cylinders ( newCylinders ) , owner ( newOwner )
{ }

Vehicle::Vehicle ( const Vehicle & theObject )
{
    manufacturer = theObject.manufacturer ;
    cylinders = theObject.cylinders ;
    owner = theObject.owner ;
}

Vehicle Vehicle::operator =( const Vehicle & rtSide )
{
    //check for self assignment not necessary without the use of pointers or arrays.

    manufacturer = rtSide.manufacturer ;
    cylinders = rtSide.cylinders ;
    owner = rtSide.owner ;
    return *this ;
}

istream & operator >>( istream & is , Vehicle & v )
{
    cout << "Manufacturer:  " << flush ;
    is >> v.manufacturer ;
    cout << "Number of cylinders:  " << flush ;
    is >> v.cylinders ;
    cout << "Owner: " << flush ;
    is >> v.owner ;

    return is ;
}

ostream & operator <<( ostream & os , const Vehicle & v )
{
    os << "Manufacturer:  " << v.manufacturer << endl ;
    os << "Number of cylinders:  " << v.cylinders << endl ;
    os << "Owner:  " << v.owner << endl ;

    return os ;
}

Truck::Truck ( ) : Vehicle ( ) , loadCap ( 0.0 ) , towingCap ( 0 ) , maxPassengers ( 0 ) , kingCab ( false )
{ }

Truck::Truck( string manf , int cyl , Person newO , double newLoad, int newTowCap, int maxPas, bool kingCab ) : Vehicle ( manf , cyl , newO ) , loadCap ( newLoad ) , towingCap ( newTowCap ) , maxPassengers ( maxPas ) , kingCab ( kingCab )
{ }

Truck Truck::operator = ( const Truck & rtSide )
{
    //check for self assignment not necessary without the use of pointers or arrays.

    Vehicle::operator = ( rtSide ) ;
    loadCap = rtSide.loadCap ;
    towingCap = rtSide.towingCap ; 
    maxPassengers = rtSide.maxPassengers ;
    kingCab = rtSide.kingCab ;

    return *this ;
}

istream & operator >>( istream & is , Truck & t )
{
    if ( t.manufacturer == "No manufacturer set" )
    {
        cout << "Manufacturer:  " << flush ;
        is >> t.manufacturer ;
        is.ignore ( ) ;
        cout << "Number of cylinders:  " << flush ;
        cout << flush ;
        cout << "Owner: " << flush ;
        is >> t.owner ;
    }

    char xCab ;
    cout << "Load Capacity (tons):  " << flush ;
    is >> t.loadCap ;
    cout << "Towing Capacity (lbs):  " << flush ;
    is >> t.towingCap ;
    cout << "Maximum Passengers:  " << flush ;
    is >> t.maxPassengers ;
    cout << "King Cab? (y/n):  " << flush ;
    is >> xCab ;
    if ( xCab == 'y' || xCab == 'Y' )
        t.kingCab = true ;
    else
        t.kingCab = false ;

    return is ;
}

ostream & operator <<( ostream & os , const Truck & t )
{
    os << "Owner:  " << t.owner.getName ( ) << endl ;
    os << "Manufacturer:  " << t.manufacturer << endl ;
    os << "Number of cylinders:  " << t.cylinders << endl ;
    os << "Load Capacity (tons):  " << t.loadCap << endl ;
    os << "Towing Capacity (lbs):  " << t.towingCap << endl ;
    os << "Maximum Passengers:  " << t.maxPassengers << endl ;
    os << "King Cab:  " ;
    if ( t.kingCab == true )
        os << "Yes" << endl ;
    else
        os << "No" << endl ;

    return os ;
}

void Truck::setOwner ( )
{
    cout << "New Owner:  " << flush ;
    cin >> owner ;

    cout << "Owner changed to " << owner << ".\n" ;
}




#include "person.h"
#include "vehicle.h"

int main ( )
{
    Person caleb ;
    Person todd ( "Todd Jones" ) ;

    cin >> caleb ;

    Truck silverado ;
    Truck titan ( "Nissan" , 8 , caleb , 2.3 , 7200 , 6 , true ) ;

    cin >> silverado ;

    cout << endl ;
    cout << silverado ;
    cout << titan ;

    Truck prototype ( silverado ) ;
    prototype.setOwner ( ) ;
    cout << prototype ;

    return 0 ;
}

Sample output:

Name: Caleb
Manufacturer: Chevy
Number of cylinders: Owner: Name:


Another sample (without the cin.ignore() at line 179):

Name: Caleb
Manufacturer: Chevy
Number of cylinders: Owner: Name: Load Capacity (tons):


:(

Recommended Answers

All 11 Replies

Your errors are not invincible, but they are all due to a very bad mixture of I/O (sorry).

You'll need to trace your program (using a piece of paper and pencil) to see what is happening.

Firstly, don't use output methods (cout, etc.) inside an overloaded input operator (>>). That is just bad design no matter how you look at it. Yes, I know it can be done, but it breaks every model there is, and will lead to future failures. Use instead a named method like getTruckInfoFromUser() or somesuch if you plan to use both input and output methods together. Don't disguise them both under the pretense of only one.

The mixup with "Number of cylinders: Owner: Name:" has to do with your use of these overloads. (After number of cylinders you never use <<. You cout "Owner:" then send off to Person's overloaded >> which couts "Name:". And you use a mixture of getline() and >> and ignore(). While not necessarily a problem, pick one --preferably only the one matching your operator.)

I hope you don't feel I've been unnecessarily harsh... but this really is industrial strength advice, and if you fail to heed it it really will bite you, and hard, later. Change your operators to named functions; only then mix and match input and output as you please. If you use getline() to get strings you won't need to use ignore() and you will avoid user input errors that can mess-up your data stream.

P.S. If your professor has asked the class to do this weird I/O stuff with the input operators, you need to go to your headmaster and get your professor fired. I'm serious.

Good luck.

[EDIT]
Oh yeah, almost forgot...

Always test for self assignment. Don't test against internal fields (two different objects can have the same values in the same fields). Test against the object itself. if (theObject == *this) return *this; Whew. Get some sleep.

you should try flushing the buffer too... it should improve your program's processing...

like this:

cout<<"/*whatever you want*/"<<flush;

or with endl; :

cout<<"/*Whatever you want*/"<<endl;

which may substitute \n

Firstly, don't use output methods (cout, etc.) inside an overloaded input operator (>>). That is just bad design no matter how you look at it. Yes, I know it can be done, but it breaks every model there is, and will lead to future failures. Use instead a named method like getTruckInfoFromUser() or somesuch if you plan to use both input and output methods together. Don't disguise them both under the pretense of only one.

Not sure I understand. If I use getTruckInfo(), there will be no point for overloading the istream, correct? Or could I do something along the lines of

string Truck::getManf ( )
{
     string manf ;

     cout << "Manufacturer:  " << flush ;
     cin >> manf ;
     return manf ;
}

istream & operator >>( istream & is , Vehicle & v )
{
   is >> getManf ;
   return is ;
}

Not sure I understand. If I use getTruckInfo(), there will be no point for overloading the istream, correct?

Exactly. The >> operator is for doing input, nothing else. Google "C++ serialization" for more information.

When you overload any operator to do something different than its primary function (or, in this case, something directly opposite its primary function) you are asking for trouble. Its like overloading ++ to do some power series expansion or some such. Just don't do it. You are always better off creating a method with a name that explains what it does.

You may say, "well, I know what I am doing" or "I'm the only one using the class" or "It's just some dumb homework" or something like that... but computer models only work when followed. Even in this short example you made an error as a direct consequence of breaking the mold: "Owner: Name:". Had you not overloaded Person's >> to do something weird, your code would have worked as expected.

I am not too fond of school environments that let people get away with such stuff because it has the same corrosive influence on the student's programming ability as the spaghetti code that BASIC encouraged.

Hope that makes sense.

[EDIT]
Oh yeah, there is no need to write a method for every field in the object. Just do what you were trying to do in the >> operator: ask for each piece of information in turn and return once the entire object has been initialized.

Alright, that all makes sense. Thanks.
Question though: When do you overload the istream?

bump

commented: c'mon you know better than to bump a thread. -2
commented: oh c'mon... you know better than to bump a thread caleb!! shame on you. =] +15
commented: heh +3

You overload the istream whenever you want to do serial input. This requires your class to have a definite (and hopefully unique) way to store its data. You can format it any way you desire, so long as you can tell where it begins and ends.

So, for example, if you have a class named Employee:

class Person {
  string surname;
  string given_name;
  string job_title;
  time_t hire_date;
  float pay_rate;
  //etc
  };

You can pick all kinds of ways to save this information. One would be just to list each piece as a string in a text file:

Shunpike
Stan
Knight Bus Conductor
1993/4/12
$7.15

Bones
Amelia Susan
Head of the Department of Magical Law Enforcement
1972/5/19
$50.32

Given a file like this and an appropriately coded >> operator you could read in the data, knowing that there are five lines of data plus one blank line per record. No need to ask questions or do anything else.

It depends entirely on your storage requirements. In this example I chose a simple line-by-line data dump. It can be more carefully organized textual information (for instance, if your Employee data is mixed with other types of data), or purely binary. It is up to you.

However, you really should read up on serialization.

Hope this helps.

commented: great explanations. +15

edit] didn't mean to post. Sorry.

commented: He he he +13
commented: lalala... take some meaningfull rep just for that +3

Thanks a ton. Your explanations are really helping me to grasp the concepts.

Also, on the other two problems you were helping me with, they're fixed now. Thanks a bunch.

It helped a lot. As always. :)

always glad to help...

edit] didn't mean to post. Sorry.

Yeah, i got a shock when i saw that you had been posting outisde the geeks lounge / coffee house ! ;) :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.