I have created a function that should edit the attributes of a class stored in a database. However, the vector insert function doesn't work as I expected. Could someone please suggest how I should implement the insert vector function to fill the hole I have made?
Whenever I implement it, this pops up:
Process finished with exit code -1073741819 (0xC0000005)
Code:
using namespace std;
int Natobase::counter = 0;
Natobase::Natobase(string n, string ci, string co, int ri, int tan, int pla, int lan)
: name(n), city(ci), country(co), rifles(ri), tanks(tan), planes(pla), launcher(lan) {};
Natobase::Natobase(string init) : Natobase("20thDiv", "Kuldiga", "Latvia", 100, 50, 75, 32) {};
std::ostream &printnames(std::ostream &pr, Natobase &pro) {
pr << "\nID:" << pro.ID << "\nName:" << pro.name;
return pr;
}
std::istream &operator>>(std::istream &re, Natobase &product) {
std::cout << "Enter the name of the base: \n";
re >> product.name;
std::cout << "Enter the city where it is located: \n";
re >> product.city;
std::cout << "Enter the country where it is located: \n";
re >> product.country;
std::cout << "Enter the number of guns held: \n";
re >> product.rifles;
std::cout << "Enter the number of tanks stationing: \n";
re >> product.tanks;
std::cout << "Enter the number of planes stationing: \n";
re >> product.planes;
std::cout << "Enter the number of launchers stationing: \n";
re >> product.launcher;
product.get_counter();
product.ID = product.counter;
return re;
}
**void Database::EditDB() {
Natobase nato;
int editt;
cout << "Enter the number of the base that you want to change:\n";
std::cout << "The bases are:\n";
printids();
cin >> editt;
auto iter = std::find_if(std::begin(DbMain), std::end(DbMain), [&](Natobase& nb)
{ return nb.get_ID() == editt; });
if (iter != DbMain.end())
{
DbMain.erase(iter);
cout << "\nPlease enter the input of the base one more time" << endl;
cin >> nato;
DbMain.insert(DbMain.begin() + iter->get_ID(), nato);
cout << "\nSuccess";
}
}**
Header file included:
//
// Created by Stasd on 28/04/2022.
//
//Stanislaw Dutkiewicz 263509
#ifndef OOPLABPROJECT_NATOBASE_H
#define OOPLABPROJECT_NATOBASE_H
#include <string>
#include <vector>
#include "Natobase.h"
class Natobase {
friend std::ostream &tosave(std::ostream &, const Natobase &);
friend std::istream &toim(std::istream &, Natobase &);
friend std::ostream &printnames(std::ostream &, Natobase &);
friend std::istream &operator>>(std::istream &, Natobase &);
public:
Natobase() = default;
Natobase(std::string n, std::string ci, std::string co, int ri, int tan, int pla, int lan); //read-only
Natobase(std::string init); //initialisation
const std::string &get_name() const { return this->name; }
const std::string &get_city() const { return this->city; }
const std::string &get_country() const { return this->country; }
const int &get_rifle() const { return this->rifles; }
const int &get_tanks() const { return this->tanks; }
const int &get_planes() const { return this->planes; }
const int &get_launch() const { return this->launcher; }
const int &get_ID() const { return this->ID; }
friend class Database;
private:
std::string name;
std::string city;
std::string country;
int rifles;
int tanks;
int planes;
int launcher;
static int counter;
int ID;
static int get_counter()
{
counter++;
return counter;
};
};
std::ostream &tosave(std::ostream &, const Natobase &); //save data into txt file
std::istream &toim(std::istream &, Natobase &);// to read the data from txt file
std::ostream &printnames(std::ostream &, Natobase &); //used for edit and remove function in Database class
std::ostream &operator<<(std::ostream &, const Natobase &); //input attributes
std::istream &operator>>(std::istream &, Natobase &); //output attributes
/////////////////////////
////////////////////////
class Database {
public:
Database() = default;
void print_data();
void read_data();
void saveDB();
void openDB();
void EditDB();
void RemoveDB();
void printids();
void compare();
private:
std::vector<Natobase> DbMain;
};
#endif //OOPLABPROJECT_NATOBASE_H
From this erase reference:
Invalidates iterators and references at or after the point of the erase, including the end() iterator.
After you called erase the iterator iter is no longer valid, it can't be used anymore.
If you need to use data from it you need to copy it first before you call erase.
You also need to use the iterator that erasereturns if you want to continue your loop.
Related
I have some data in the file that I would like to be able to read into a vector of a class-type/object. This object also has within itself a vector that takes in another class type, and the data that needs to populate that inner vector is also contained within the text file. How can I read the data from the file into the vectors accordingly without using getLine()?
The data is formatted as so in the document.
143 Jones
1234 2 C
-1
123 Smith
4321 4 A
132 3 B
-1
Where the first line is the ID of the student followed by their name, and below it is a series of classes that student has taken followed by the number of credits each course is worth and the grade the student got for the course.
Below is the course class header code
#pragma once
#include <iostream>
class Course {
public:
Course(int, int, std::string);
int getCourseCode() const {return courseCode;}
int getCredits() const {return courseCredits;}
std::string getGrade() const {return grade;}
void print(std::ostream &os) const;
private:
int courseCode;
int courseCredits;
std::string grade;
};
inline std::ostream &operator <<(std::ostream &os, const Course &course) {
course.print(os);
return os;
}
inline Course::Course(int courseCode, int courseCredits, std::string grade) {
this->courseCode = courseCode;
this->courseCredits = courseCredits;
this->grade = grade;
}
Below is the student class header code
#pragma once
#include <vector>
#include "course.h"
class Student {
public:
Student(int, std::string, std::vector<Course> courses);
int getID() const;
double getGPA() const;
std::string getName() const;
void print(std::ostream &os) const;
std::vector<Course> courses;
private:
int id;
std::string name;
};
inline std::ostream &operator << (std::ostream &os, const Student &student) {
student.print(os);
return os;
}
Below is the student.cpp code
#include "student.h"
#include <string>
using namespace std;
Student::Student(int id, std::string name, vector<Course> courses) {
this->id = id;
this->name = name;
this->courses = courses;
}
int Student::getID() const {
return id;
}
string Student::getName() const {
return name;
}
double Student::getGPA() const {
double total;
double creds;
double cgrade;
double gpa;
for(int i = 0; i < courses.size(); i++) {
if(courses[i].getGrade() == "A") cgrade = 4.0;
else if(courses[i].getGrade() == "B") cgrade = 3.0;
else if(courses[i].getGrade() == "C") cgrade = 2.0;
else if(courses[i].getGrade() == "D")cgrade = 1.0;
total += cgrade * courses[i].getCredits();
creds += courses[i].getCredits();
}
gpa = total / creds;
return gpa;
}
void Student::print(std::ostream &os) const {
os << id << " " << name << ": " << this->getGPA() << endl;
for(int i = 0; i < courses.size(); i++) {
os << courses[i];
}
}
This is what I've tried so far in terms of trying to load the vectors
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "student.h"
using namespace std;
void loadStudents(string fileName, vector<Student> &students);
bool compareCourses(const Course &c1, const Course &c2);
bool compareStudents(const Student &s1, const Student &s2);
void printResults(string fileName, vector<Student> &students);
int main() {
try {
vector<Student> students;
loadStudents("students.data", students);
cout << students.size() << " records processed" << endl;
return 0;
}
catch(string message) {
cout << "Error: " << message << endl;
exit(1);
}
};
void loadStudents(string fileName, vector<Student> &students) {
ifstream studentsFile(fileName.c_str());
if(!studentsFile.good()) {
throw string("Input file: " + fileName + ", not found!");
}
int id;
string name;
vector<Course> cs;
while(studentsFile >> id >> name >> cs) {
students.place_back(student);
}
studentsFile.close();
}
bool compareCourses(const Course &c1, const Course &c2) {
return c1.getGrade() < c2.getGrade();
}
bool compareStudents(const Student &s1, const Student &s2) {
return s1.getGPA() < s2.getGPA();
}
void printResults(string fileName, vector<Student> &students) {
ofstream outputFile(fileName.c_str());
if(!outputFile.good()) {
throw string("Output file: " + fileName + ", not found!");
}
for(auto student : students) {
outputFile << student.print(outputFile) << endl;
}
outputFile.close();
}
I'm getting an error stating that "no operator ">>" matches these operands" in the while loop inside the loadStudents function, which I think pertains to the istream for the vector.
The desired output is something like this printed to an output file.
143 Smith: 3.57143
4321 (4 credits): A
132 (3 credits): B
143 Jones: 2
1234 (2 credits): C
2 records processed
Where the student ID and name are printed along with their calculated GPA and the courses they took below them followed by a message stating the number of students that were processed.
My main issue pertains to the loading of the students vector with the subsequent data of the course information being appropriately loaded into the courses vector for each student. Is this possible without using the getLine() method and istream >>?
The code runs, but I cannot get cout to work. Please help me, I am a beginner, and really struggling with getting the contents of my array to output.
cout << myArray[0].getSquareName(); is the line that never cout's.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class cSquare {
public:
string SquareName;
string getSquareName() const;
void setSquareName(string);
friend std::istream & operator >> (std::istream & is, cSquare & s);
};
// set method
void cSquare::setSquareName(string squareName)
{
squareName = SquareName;
}
//square name get method
string cSquare::getSquareName() const
{
return SquareName;
}
ostream & operator << (ostream & os, const cSquare & s)
{
os << s.getSquareName() << ' ';
return os;
}
istream & operator >> (istream & is, cSquare & s)
{
is >> s.SquareName;
return is;
}
int main()
{
string discard;
int i = 0;
const int MAX_SIZE = 26;
ifstream monopoly("monopoly.txt", ios::in);
if (monopoly.is_open())
{
cSquare myArray[MAX_SIZE];
getline(monopoly, discard);
string sname; //string to store what I read in from my file
while (i < MAX_SIZE && monopoly >> sname)
{
myArray[i].setSquareName(sname);//stores the string read in into the array
cout << myArray[0].getSquareName(); //it never cout's this
i++;
}
}
}
Your setSquareName() method is assigning the object's SquareName member to the input parameter, which is wrong. You need to do the opposite instead, eg:
void cSquare::setSquareName(string sname)
{
//sname = SquareName;
SquareName = sname;
}
Also, this line:
cout << myArray[0].getSquareName();
Should be this instead:
cout << myArray[i];
With those 2 changes, the code works.
Demo
I am trying to swap strings. For one of my functions of my class, I am passing in two strings and I also created a temp variable. I have been trying to compile my code, but it says "no suitable function for conversion from std::string to const char* exists.
void CdLib::swap(string *s1, string *s2)
{
string temp;
strcpy(temp, *s1);
strcpy(*s1, *s2);
strcpy(*s1, temp);
}
class CdLib
{
public:
int n;
char Cd[N_MAX];
string artist;
string title;
int year;
string genre;
string fan;
string imageURL;
CdLib();
void setFromFile(string fileName);
void print(string label);
void sortByYear();
void sortByArtist();
void sortByTitle(string genres[]);
private:
void swap(int *a, int *b);
void swapStrings(string *s1, string *s2);
};
I'm confused why it is trying to convert between string and char when they should all be string. Thank you.
strcpy() takes char* pointers, not string* pointers. It you are not allocating any memory for strcpy() to copy into.
Rather than using strcpy() at all, a better solution is to use std::string::operator= instead:
void CdLib::swap(string *s1, string *s2)
{
string temp = *s1;
*s1 = *s2;
*s1 = temp;
}
Or better, std::swap():
void CdLib::swap(string *s1, string *s2)
{
std::swap(*s1, *s2);
}
I am trying to swap strings
Why would you need to? Sorting can be accomplished via std::sort and you don't have to worry about how the strings get swapped - that's the beauty of C++, such basic operations are all implemented in the standard library.
std::swap supports pretty much everything, so use that.
Don't pass strings as arguments by value. Pass them by const reference. Return them by value. If a function is intended to modify a string in place, then it should take it by non-const reference (i.e. "just" a reference).
Don't write using namespace std - it's bad practice.
I guess that the CdLib class is some sort of a CD library, but you haven't told us what else your program should do.
If I were to write a sketch of this, I'd start with a structure representing the CD information, comparison functions for the CD that can be used in sorting, a function to print out the CD information, and a way to stream the CD information to/from an ostream/istream:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
struct CDInfo
{
std::string artist;
std::string title;
std::string genre;
std::string fan;
std::string imageUrl;
int year;
friend void swap(CDInfo& a, CDInfo& b)
{
// see https://stackoverflow.com/a/2684544/1329652 for rationale
using std::swap; // bring in swap for built-in types
swap(a.artist, b.artist);
swap(a.title, b.title);
swap(a.genre, b.genre);
swap(a.fan, b.fan);
swap(a.imageUrl, b.imageUrl);
swap(a.year, b.year);
}
};
bool lessByYear(const CDInfo &l, const CDInfo &r) {
return l.year < r.year;
}
bool lessByArtist(const CDInfo &l, const CDInfo &r) {
return l.artist < r.artist;
}
void print(std::ostream &os, const CDInfo &cd) {
os << "Artist: " << cd.artist
<< "\n Title: " << cd.title
<< "\n Genre: " << cd.genre
<< "\n Fan: " << cd.fan
<< "\n Image: " << cd.imageUrl
<< "\n Year: " << cd.year << "\n";
}
std::istream &operator>>(std::istream &is, CDInfo &cd)
{
std::string year;
std::getline(is, cd.artist);
std::getline(is, cd.title);
std::getline(is, cd.genre);
std::getline(is, cd.fan);
std::getline(is, cd.imageUrl);
if (std::getline(is, year)) cd.year = std::stoi(year);
return is;
}
std::ostream &operator<<(std::ostream &os, const CDInfo &cd)
{
os << cd.artist << '\n' << cd.title << '\n'
<< cd.genre << '\n' << cd.fan << '\n'
<< cd.imageUrl << '\n' << cd.year << '\n';
return os;
}
Then I'd write a class representing the CD library, with methods to access the individual CDs, iterators to access the entire collection, methods using the std::sort algorithm and the comparison functions to sort the library, and methods to load/save it from/to file, and to print the entire library (by default to stdout):
class CDLibrary
{
std::vector<CDInfo> m_CDs;
public:
CDLibrary() = default;
int count() const { return m_CDs.size(); }
void resize(int newCount) { m_CDs.resize(newCount); }
CDInfo &getCD(int index) { return m_CDs[index]; }
const CDInfo &getCD(int index) const { return m_CDs[index]; }
auto begin() { return m_CDs.begin(); }
auto end() { return m_CDs.end(); }
auto begin() const { return m_CDs.begin(); }
auto end() const { return m_CDs.end(); }
auto cbegin() const { return m_CDs.begin(); }
auto cend() const { return m_CDs.end(); }
void sortByYear() {
std::sort(begin(), end(), lessByYear);
}
void sortByArtist() {
std::sort(begin(), end(), lessByArtist);
}
void addCD(const CDInfo &cd) {
m_CDs.push_back(cd);
}
void removeCD(int index) {
m_CDs.erase(m_CDs.begin() + index);
}
bool load(const std::string &filename);
bool save(const std::string &filename) const;
void printAll(std::ostream &os = std::cout) const {
int n = 1;
for (auto &cd : *this) {
os << "--- CD #" << n << '\n';
print(os, cd);
}
}
};
Of course I'd also implement the streaming operators for the entire library, just as we did for the individual CDInfo:
std::istream &operator>>(std::istream &is, CDLibrary &lib) {
std::string count;
if (std::getline(is, count)) {
lib.resize(std::stoi(count));
for (auto &cd : lib)
if (!(is >> cd)) break;
}
return is;
}
std::ostream &operator<<(std::ostream &os, const CDLibrary &lib) {
if (!(os << lib.count() << '\n')) return os;
for (auto &cd : lib)
if (!(os << cd)) break;
return os;
}
Then, the load and save convenience methods can be expressed n terms of those streaming operators:
bool CDLibrary::load(const std::string &filename) {
std::ifstream ifs(filename);
try {
return ifs.good() && ifs >> *this;
} catch (...) {}
return false;
}
bool CDLibrary::save(const std::string &filename) const {
std::ofstream ofs(filename);
return ofs.good() && ofs << *this;
}
Hopefully this gives you some idea how such code might look. I'm not quite sure what you expected to achieve with void sortByTitle(string genres[]), so I didn't implement it. Feel free to comment under this answer to explain, as well as edit the question to make it clear what is the functionality you need.
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int main() {
string str1 = "Hello";
string str2 = "World";
swap(str1,str2);
cout<<str1<<" ";
cout<<str2;
}
o/p:
Success #stdin #stdout 0s 4492KB
World Hello
A class BookLibrary constructs a vector of objects of class BookInfo. The task is to add some 'books' (objects of class BookInfo) into the vector and print them out. For some reason, a conventional for(unsigned int i = 0; i < vector.size(); i++) cout << vector[i] << endl; loop is not working. This is a homework project from Savitch textbook "Problem Solving with C++".
Here's the code:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class BookInfo
{
public:
BookInfo(string newAuthor, string newTitle);
BookInfo(string newTitle);
string getName();
string getAuthor();
string getTitle();
private:
string author;
string title;
};
class BookLibrary
{
public:
BookLibrary();
BookLibrary(vector<BookInfo> newLibrary);
void add(BookInfo newBook);
void size();
void printInfo();
private:
vector<BookInfo> library;
};
int main()
{
BookLibrary library1;
BookInfo book1("Michael Krichton", "Jurassic Park");
BookInfo book2("War and Peace"), book3("Valter Savitch", "Programming in C++");
library1.add(book1);
library1.add(book2);
library1.add(book3);
library1.size();
library1.printInfo();
return 0;
}
BookInfo::BookInfo(string newAuthor, string newTitle)
{
author = newAuthor;
title = newTitle;
}
BookInfo::BookInfo(string newTitle) :
title(newTitle), author("unknown")
{}
string BookInfo::getName()
{
return (author + " " + title);
}
string BookInfo::getAuthor()
{
return author;
}
string BookInfo::getTitle()
{
return title;
}
BookLibrary::BookLibrary()
{}
BookLibrary::BookLibrary(vector<BookInfo> newLibrary)
{
library = newLibrary;
}
void BookLibrary::add(BookInfo newBook)
{
library.push_back(newBook);
}
void BookLibrary::size()
{
cout << library.size();
}
void BookLibrary::printInfo()
{
for (unsigned int i = 0; i < library.size(); i++)
cout << library[i] << endl;
}
It underlines the cout << in the last line.
Your loop is not able to print out a BookInfo object, because you have not defined an operator<< for BookInfo. As such, a statement like cout << library[i] does not know what to do with the BookInfo that library[i] returns.
You need to add that operator, eg:
class BookInfo
{
public:
...
friend ostream& operator<<(ostream &os, const BookInfo &book)
{
os << "\"" << book.title << "\" by " << book.author;
return os;
}
...
};
If you want to use your getName() method instead, you would need to declare it as const (which you should do anyway for all of your getters), eg:
class BookInfo
{
public:
...
string getName() const;
...
friend ostream& operator<<(ostream &os, const BookInfo &book)
{
os << book.getName();
return os;
}
...
};
string BookInfo::getName() const
{
return ...;
}
I'm making a small program that contains a user defined class that contains obects object of struct type date and time. The struct date contains a string type. How can i serialize the containing object entry so as to be able to store the entry object in a file as well as to read from it in c++?
Here is my minimal code:
#include<iostream>
#include<fstream>
#include<string>
#define s ' ' //defining space character
using namespace std;
struct date{
int day;
string month;
int year;
};
struct time{
int hr;
int min;
};
class entry{
private:
date d;
time t;
int sno=0;
public:
void incrementsno(){++sno;}
void getdate(){ //This function gets date
cout<<"\nEnter the date : ";
cout<<"\nDay : ";
cin>>d.day;
cout<<"Month : ";
cin>>d.month;
cout<<"Year :";
cin>>d.year;
}
void gettime(){ //This function gets time
cout<<"\n\nEnter time : ";
cout<<"\nHours :";
cin>>t.hr;
cout<<"Minutes :";
cin>>t.min;
}
};
int main(){
//declaring variables
char c;
string filename;
entry e;
ifstream filer;
ofstream filew;
//getting file name begins
cout<<"Enter the name of file you want to create : ";
cin>>filename;
cout<<"\nThe file name is : "<<filename<<endl;
//getting file name over
//creating and opening file
filew.open(filename.c_str(),ios::binary|ios::out|ios::app);
//file association operation successful
cout<<"\nDo you want to write to file? : ";
cin>>c;
if(c=='y')//Entering date and time
{
do{
e.getdate();
e.gettime();
filew.write((char*)&e,sizeof(e));
cout<<"\nFile write operation successful.\n";
e.incrementsno();
cout<<"\nDo you wish to continue? :";
cin>>c;
}
while(c=='y');
}
else
cout<<"\nReading file...\n";
filew.close();
filer.open(filename.c_str(),ios::binary|ios::in); //opening file for reading
while(filer.read((char*)&e,sizeof(e)))
{
e.showdate();
e.showtime();
}
cout<<"\n\nFile IO successful...";
filer.close();
return 0;
}
This is a non-working, halfmeasure streaming framework based on the comments. It does NOT work - it's something to work with.
#include <iostream>
#include <string>
#include <vector>
//-----------------------------------------------------------------------------
struct Date {
int day;
std::string month;
int year;
};
// Date serializing support:
// stream out a Date to a generic stream (like a file)
std::ostream& operator<<(std::ostream& os, const Date& d) {
return os << d.day << '\n' << d.month << '\n' << d.year << '\n';
}
// read a Date from a generic stream (like a file)
std::istream& operator>>(std::istream& is, Date& d) {
return is >> d.day >> d.month >> d.year;
}
// Date adapters for human interaction - only holds references to "real" objects
struct DateUIout {
explicit DateUIout(const Date& d) : date(d) {}
// DateUIout(const Date&) = delete; // not copyable - but made it explicitly
// clear
// holds a reference to the Date struct we'd like to work with
// and an output stream for asking the user questions if needed
const Date& date;
};
std::ostream& operator<<(std::ostream& os, const DateUIout& dui) {
const Date& d = dui.date; // alias to the Date we'd like to work with
return os << "Day: " << d.day << " Month: " << d.month << " Year: " << d.year
<< '\n';
}
struct DateUIin {
explicit DateUIin(Date& d, std::ostream& qs = std::cout) :
date(d), questions(qs) {}
DateUIin(const Date&) = delete; // not copyable - but made it explicitly clear
Date& date;
std::ostream& questions; // used for printing questions to humans
};
std::istream& operator>>(std::istream& is, DateUIin& dui) {
Date& d = dui.date; // alias to the Date we'd like to work with
dui.questions << "Enter the date:\n"
<< " Day: ";
is >> d.day;
dui.questions << " Month: ";
is >> d.month;
dui.questions << " Year: ";
return is >> d.year;
}
//-----------------------------------------------------------------------------
struct Time {
int hr;
int min;
};
// Time serializing support: (much like everything in Date)
// stream out a Time
std::ostream& operator<<(std::ostream& os, const Time& t) {
return os << t.hr << '\n' << t.min << '\n';
}
// read a Time from a stream
std::istream& operator>>(std::istream& is, Time& t) {
return is >> t.hr >> t.min;
}
// Time adapter for human interaction - only holds references to "real" objects
struct TimeUI {
explicit TimeUI(Time& t, std::ostream& qs = std::cout) : tim(t), questions(qs) {}
Time& tim;
std::ostream& questions;
};
std::ostream& operator<<(std::ostream& os, const TimeUI& tui) {
Time& t = tui.tim;
return os << "Hour: " << t.hr << ' ' << t.min << '\n';
}
std::istream& operator>>(std::istream& is, TimeUI& tui) {
Time& t = tui.tim;
tui.questions << "Enter the time:\n Hour: ";
is >> t.hr;
tui.questions << " Minute: ";
return is >> t.min;
}
//-----------------------------------------------------------------------------
struct Timestamp {
Date date{};
Time time{};
};
// Timestamp serializing support:
// stream out a Timestamp
std::ostream& operator<<(std::ostream& os, const Timestamp& ts) {
return os << ts.date << ts.time;
}
// read a Timestamp from a stream
std::istream& operator>>(std::istream& is, Timestamp& ts) {
return is >> ts.date >> ts.time;
}
// Timestamp adapter for human interaction - only holds references to "real" objects
struct TimestampUIout {
TimestampUIout(const Timestamp& Ts) : ts(Ts) {}
// TimestampUIout(const TimestampUI&) = delete;
Timestamp& ts;
};
std::ostream& operator<<(std::ostream& os, const TimestampUIout& tsui) {
return os << DateUIout(tsui.ts.date) << TimeUI(tsui.ts.time, os);
}
struct TimestampUIin {
TimestampUI(Timestamp& Ts, std::ostream& qs = std::cout) :
ts(Ts), questions(qs) {}
TimestampUI(const TimestampUI&) = delete;
Timestamp& ts;
std::ostream& questions;
};
std::istream& operator>>(std::istream& is, TimestampUIin& tsui) {
DateUIin dui(tsui.ts.date, tsui.questions);
TimeUI tui(tsui.ts.time, tsui.questions);
return is >> dui >> tui;
}
//-----------------------------------------------------------------------------
int main() {
Timestamp tmp;
TimestampUI tsui(tmp, std::cout); // bind UI adapter to the Timestamp
std::vector<Timestamp> timestamps;
while(std::cin >> tsui) { // use UI adapter
timestamps.push_back(tmp); // store a raw Timestamp
}
// print collected timestamps - using adapter
for(const Timestamp& ts : timestamps) {
std::cout << TimestampUIout(ts);
}
// print collected timestamps - as they would be streamed to a file
for(const Timestamp& ts : timestamps) {
std::cout << ts;
}
}