Input of User-Defined Types

Input of User-Defined Types

Input may be defined in a similar way:

class Person
{
public:
	// …
	friend
	istream &operator>>(istream &os, Person &p);
private:
	// …
};

But it’s a little trickier on input, because you have to get the formatting exactly right (just as scanf() is trickier to use than printf() in C).

Example

Let’s assume that we wish to read back the exact same stuff we output before from the cout << p, including labels:

//
//  Person.h
//  iostreams - User-defined types
//
//  Created by Bryan Higgs on 9/4/24.
//

#ifndef Person_h
#define Person_h

#include <iostream>

class Person
{
public:
  // Constructor
  Person(const std::string &nm,
         const std::string &street = "", 
         const std::string &town = "",
         const std::string &state = "",
         int a = -1);
  
  // Access member functions
  const std::string &getName() const { return m_name; }
  const std::string &getStreet() const { return m_street; }
  const std::string &getTown() const { return m_town; }
  const std::string &getState() const { return m_state; }
  const int getAge() const { return m_age; }
  
  // Mutator member functions
  void setStreet(const std::string &street) { m_street = street; }
  void setTown(const std::string &town) { m_town = town; }
  void setState(const std::string &state) { m_state = state; }
  void setAge(int age) { m_age = age; }
  
  friend
  std::ostream &operator<<(std::ostream &os, const Person &p);
  
  friend
  std::istream &operator>>(std::istream &is, Person &p);

private:
  std::string m_name;
  std::string m_street;
  std::string m_town;
  std::string m_state;
  int  m_age;
};

#endif /* Person_h */

Note how more complex the code is for input compared with output.
I don’t claim this is particularly efficient, and it clearly doesn’t scale as a solution (if we had lots more fields. etc.)

//
//  Person.cpp
//  iostreams - User-defined types
//
//  Created by Bryan Higgs on 9/4/24.
//

#include "Person.h"
#include <iostream>

// Constructor
Person::Person(const std::string &name,
       const std::string &street,
       const std::string &town,
       const std::string &state,
       int age)
  : m_name(name), m_street(street), m_town(town),
    m_state(state), m_age(age)
{ }

static const char NAME[]  = "Name:   ";
static const char STREET[]  = "Street: ";
static const char TOWN[]  = "Town:   ";
static const char STATE[]  = "State:  ";
static const char AGE[]  = "Age:    ";


// Overloaded operator <<
std::ostream &operator<<(std::ostream &os, const Person &p)
{
  return os << NAME << p.m_name << std::endl
            << STREET << p.m_street << std::endl
            << TOWN << p.m_town << std::endl
            << STATE << p.m_state << std::endl
            << AGE << p.m_age << std::endl;
}

// Overloaded operator >>
std::istream &operator>>(std::istream &is, Person &p)
{
  static char buffer[81];
  static char value[81];

  is.get(buffer, sizeof(NAME)); // Read the label
  is.get(value, sizeof(value)); // Read the value
  p.m_name = value;
  is.getline(buffer, sizeof(buffer)); // Discard the newline
  
  is.get(buffer, sizeof(STREET));
  is.get(value, sizeof(value));
  p.m_street = value;
  is.getline(buffer, sizeof(buffer));
  
  is.get(buffer, sizeof(TOWN));
  is.get(value, sizeof(value));
  p.m_town = value;
  is.getline(buffer, sizeof(buffer));

  is.get(buffer, sizeof(STATE));
  is.get(value, sizeof(value));
  p.m_state = value;
  is.getline(buffer, sizeof(buffer));

  is.get(buffer, sizeof(AGE));
  is >> p.m_age;
  is.getline(buffer, sizeof(buffer));

  return is;
}

… and here’s a main program to test it:

//
//  main.cpp
//  iostreams - User-defined types
//
//  Created by Bryan Higgs on 9/4/24.
//

#include <iostream>
#include "Person.h"

int main(int argc, const char * argv[]) 
{
  Person p1(""), p2("");

  std::cout << "Enter data for Person 1:" << std::endl;
  std::cin >> p1;
  std::cout << "Enter data for Person 2:" << std::endl;
  std::cin >> p2;

  std::cout << "\n+++Person 1++++" << std::endl << p1;
  std::cout << "\n+++Person 2++++" << std::endl << p2;

  return 0;
}

It outputs:

Enter data for Person 1:
Name:   Fred Bloggs
Street: 15 Highland Terrace
Town:   Cleveland
State:  OH
Age:    34

Enter data for Person 2:
Name:   Mary Smith
Street: 27 Doubleday Ave.
Town:   Monterey
State:  CA
Age:    28


+++Person 1++++
Name:   Fred Bloggs
Street: 15 Highland Terrace
Town:   Cleveland
State:  OH
Age:    34

+++Person 2++++
Name:   Mary Smith
Street: 27 Doubleday Ave.
Town:   Monterey
State:  CA
Age:    28
Program ended with exit code: 0

The italicized text was input to the program.
Note that I simply copied the output from the earlier program, and pasted it in for input. (You don’t want to do this manually, as it is very picky to get right!)

Index