Using virtual functions with classes and constructors to print book info - c++

I'm at the very last step for this project, and I'm stuck on what to do. The project is to take an input file containing book info, like this:
A Book on C
Al Kelly and Ira Pohl
Addison-Wesley, Fifth Edition 1998.
0201183994
C How to Program
Paul Deitel and Harvey Deitel
Prentice Hall Sixth Edition 2010
0136123562
And then print it using several options. I'll put all the code here so you can compile and see what each option does. I'm having trouble with option 5, specifically. For option 5, I need to:
Input more information on each book. I'm required to have two subclasses, InfoBookRecord containing the price and author biography, and TypeBookRecord containing the book genre.
Print the new information using virtual functions. I thought it made sense to make the virtual function in the class ListRecords, but the grading key seems to imply I should be using them for the two subclasses InfoBookRecord and TypeBookRecord. I can't think of any way to do that.
header.h:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <fstream>
#include <algorithm>
using namespace std;
#define TABLE_SIZE 200
class BookRecord{
public:
BookRecord(string input_title, string input_author, string input_publisher, int input_isbn);
string getTitle();
string getAuthor();
string getPublisher();
int getISBN();
private:
string title;
string author;
string publisher;
int isbn;
};
class InfoBookRecord: public BookRecord {
public:
InfoBookRecord(string input_title, string input_author, string input_publisher, int input_isbn, double input_price, string input_authorBio) : BookRecord(input_title,input_author,input_publisher,input_isbn) {
price=input_price;
authorBio=input_authorBio;}
double getPrice();
string getAuthorBio();
private:
double price;
string authorBio;
};
class TypeBookRecord: public BookRecord {
public:
TypeBookRecord(string input_title, string input_author, string input_publisher, int input_isbn, string input_genre) : BookRecord(input_title,input_author,input_publisher,input_isbn){
input_genre.resize(15);
genre=input_genre;}
string getGenre();
private:
string genre;
};
class ListRecords{
public:
ListRecords(char filename[]);
void insertBookInfo(BookRecord record);
//virtual void printBookInfo(int bookISBN);
void printBookInfo(int bookISBN);
void printListByISBN();
void printListByTitle();
BookRecord ** books;
InfoBookRecord ** books2;
TypeBookRecord ** books3;
int line_num;
int k;
string garbage;
};
// problem here
/*
class extraListRecords: public ListRecords{
public:
extraListRecords();
void printBookInfo(int bookISBN){
cout << "testing 1 2 3 " << endl;
}
};*/
BookRecord.cpp:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <fstream>
#include <algorithm>
#include "header.h"
using namespace std;
#define TABLE_SIZE 200
BookRecord::BookRecord(string input_title, string input_author, string input_publisher, int input_isbn){
title=input_title;
author=input_author;
publisher=input_publisher;
isbn=input_isbn;
}
string BookRecord::getTitle() {return title;}
string BookRecord::getAuthor() {return author;}
string BookRecord::getPublisher() {return publisher;}
int BookRecord::getISBN() {return isbn;}
double InfoBookRecord::getPrice() {return price;}
string InfoBookRecord::getAuthorBio() {return authorBio;}
string TypeBookRecord::getGenre() {return genre;}
ListRecords.cpp:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <fstream>
#include <algorithm>
#include "header.h"
using namespace std;
#define TABLE_SIZE 200
ListRecords::ListRecords(char filename[]){
ifstream input(filename);
assert(("Error: File does not exist.", input != NULL));
string line;
line_num=0;
while (getline(input,line)){
line_num++;
}
//go back to beginning of file
input.clear();
input.seekg(0, ios::beg);
char lines[TABLE_SIZE][TABLE_SIZE];
int i=0;
// load lines of file into array
while (i < line_num) {
input.getline(lines[i],TABLE_SIZE);
i++;
}
input.close();
books = new BookRecord*[TABLE_SIZE];
books2 = new InfoBookRecord*[TABLE_SIZE];
books3 = new TypeBookRecord*[TABLE_SIZE];
k=0;
for(i=0;i<line_num;i+=5){
// check for duplicate entries
int test=0;
for(int j=0;j<i/5;j++){
if(books[j]->getISBN() == atoi(lines[i+3])){
cout << "Found a duplicate ISBN... ignoring entry " << lines[i+3] << endl;
test=1;
}
}
// if not a duplicate entry, add to array
if(test==0){
int the_price;
cout << "Please enter price of " << lines[i] << ": " << endl;
cin >> the_price;
getline(cin,garbage);
string the_authorBio;
cout << "Please enter author bio of " << lines[i] << ": ";
cin >> the_authorBio;
getline(cin,garbage);
string the_genre;
cout << "Please enter the book genre of " << lines[i] << ": ";
cin >> the_genre;
getline(cin,garbage);
*(books2+k) = new InfoBookRecord(lines[i],lines[i+1],lines[i+2],atoi(lines[i+3]),the_price,the_authorBio);
*(books3+k) = new TypeBookRecord(lines[i],lines[i+1],lines[i+2],atoi(lines[i+3]),the_genre);
*(books+k) = new BookRecord(lines[i],lines[i+1],lines[i+2],atoi(lines[i+3]));
k++;
}
else
i+=5;
}
}
void ListRecords::insertBookInfo(BookRecord record){
line_num+=5;
*(books+k) = new BookRecord(record.getTitle(),record.getAuthor(),record.getPublisher(),record.getISBN());
k++;
}
void ListRecords::printBookInfo(int bookISBN){
int found=0;
for(int i=0;i<k;i++){
if(books[i]->getISBN() == bookISBN){
if(to_string(books[i]->getISBN()).length()==9)
cout << endl << books[i]->getTitle() << endl << books[i]->getAuthor() << endl << books[i]->getPublisher() << endl << "0" << books[i]->getISBN() << endl;
if(to_string(books[i]->getISBN()).length()==10)
cout << endl << books[i]->getTitle() << endl << books[i]->getAuthor() << endl << books[i]->getPublisher() << endl << books[i]->getISBN() << endl;
found=1;
break;
}
}
if(found==0)
cout << "The record you requested was not found in the list." << endl;
}
bool compare_by_isbn(BookRecord* x,BookRecord* y) { return (x->getISBN() < y->getISBN()); }
bool compare_by_title(BookRecord* x,BookRecord* y) { return (x->getTitle() < y-> getTitle()); }
void ListRecords::printListByISBN(){
sort(books, books + k, compare_by_isbn);
printf(" %-22s %-22s %-17s %s\n", "Title", "Author", "Publisher", "ISBN");
cout << string(22, '-') << " " << string(22, '-') << " " << string(22, '-') << " " << string(10, '-') << endl;
for(int i=0;i<k;i++){
if(to_string(books[i]->getISBN()).length()==9)
printf("%-22.22s %-22.22s %-22.22s 0%d\n", books[i]->getTitle().c_str(), books[i]->getAuthor().c_str(), books[i]->getPublisher().c_str(), books[i]->getISBN());
if(to_string(books[i]->getISBN()).length()==10)
printf("%-22.22s %-22.22s %-22.22s %d\n", books[i]->getTitle().c_str(), books[i]->getAuthor().c_str(), books[i]->getPublisher().c_str(), books[i]->getISBN());
}
}
void ListRecords::printListByTitle(){
sort(books, books + k, compare_by_title);
printf(" %-22s %-22s %-17s %s\n", "Title", "Author", "Publisher", "ISBN");
cout << string(22, '-') << " " << string(22, '-') << " " << string(22, '-') << " " << string(10, '-') << endl;
for(int i=0;i<k;i++){
if(to_string(books[i]->getISBN()).length()==9)
printf("%-22.22s %-22.22s %-22.22s 0%d\n", books[i]->getTitle().c_str(), books[i]->getAuthor().c_str(), books[i]->getPublisher().c_str(), books[i]->getISBN());
if(to_string(books[i]->getISBN()).length()==10)
printf("%-22.22s %-22.22s %-22.22s %d\n", books[i]->getTitle().c_str(), books[i]->getAuthor().c_str(), books[i]->getPublisher().c_str(), books[i]->getISBN());
}
}
main.cpp:
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <fstream>
#include <algorithm>
#include "header.h"
using namespace std;
#define TABLE_SIZE 200
int main(int argc, char* argv[]){
char filename[50];
cout << "Enter the name of a file to load:" << endl;
cin >> filename;
ListRecords listrecords(filename);
while(true){ // looping for the selection menu
int selection, n;
cout << "Please select a menu option:\n1) Insert a book record into the list\n2) Print information of a book with a given ISBN number\n3) Print the list of books sorted by ISBN\n4) Print the list of books sorted alphabetically by title\n5) Print the books also with info on price, author biography, and genre.\n6) Quit the program" << endl;
cin >> selection;
if(cin.fail()){ // make sure input is a digit
cout << "Invalid selection. Quitting program..." << endl;
break;
}
if(selection==1){
string in_title;
string in_author;
string in_publisher;
int in_isbn;
string junk;
getline(cin, junk);
cout << endl << "Please enter a title: ";
getline(cin, in_title);
cout << "Please enter an author: ";
getline(cin, in_author);
cout << "Please enter a publisher: ";
getline(cin, in_publisher);
cout << "Please enter an ISBN: ";
cin >> in_isbn;
BookRecord new_record(in_title, in_author, in_publisher, in_isbn);
listrecords.insertBookInfo(new_record);
cout << endl << "The record has been added to the list." << endl;
cout << endl << endl;
}
if(selection==2){
int in_isbn;
cout << endl << "Please enter ISBN number: " << endl;
cin >> in_isbn;
listrecords.printBookInfo(in_isbn);
cout << endl << endl;
}
if(selection==3){
cout << endl;
listrecords.printListByISBN();
cout << endl << endl;
}
if(selection==4){
cout << endl;
listrecords.printListByTitle();
cout << endl << endl;
}
if(selection==5){
int in_isbn;
cout << endl << "Please enter ISBN number: " << endl;
cin >> in_isbn;
cout << endl << "List of books also with info on price and author biography: " << endl;
cout << endl << endl;
// problem here
// extraListRecords extras;
//ListRecords *bookextras= &extras;
// bookextras->printBookInfo(in_isbn);
cout << endl << "List of books also with info on genre: " << endl;
}
if(selection==6){
cout << endl << "Program terminating normally..." << endl;
break;
}
} // end of while(true) loop
return 0;
};
Makefile:
LFLAGS = -Wno-write-strings -std=c++11
CFLAGS = -Wno-write-strings -std=c++11 -c
myprogam: main.o BookRecord.o ListRecords.o
g++ $(LFLAGS) -o myprogram main.o BookRecord.o ListRecords.o header.h
main.o: main.cpp header.h
g++ $(CFLAGS) main.cpp
BookRecord.o: BookRecord.cpp header.h
g++ $(CFLAGS) BookRecord.cpp
ListRecords.o: ListRecords.cpp header.h
g++ $(CFLAGS) ListRecords.cpp
clean:
rm *.o
rm myprogram
I commented out the two parts giving me trouble. One is at the end of header.h, and the other is near the end of main.cpp.
When I try to make this, I get the error
main.cpp:(.text+0x4c7): undefined reference to `extraListRecords::extraListRecords()'
collect2: error: ld returned 1 exit status
make: *** [myprogam] Error 1
I've tried a few other attempts at that subclass with the virtual function, such as adding the initialization of book2 and book3 to the body of its constructor, so writing its constructor as extraListRecords(char filename[]) :ListRecords(filename){ / the chunk of code in ListRecords.cpp above around line 55 / }
Thanks a bunch for the help!

You need to provide the constructor definition for extraListRecords
class extraListRecords: public ListRecords {
public:
extraListRecords() = default;
// ^^^^^^^^^^
};

I figured it out. The problem was pretty silly. I just forgot to flush the buffer between cin on an integer and getline.
cin and getline skipping input
The virtual function was completely fine as extraListRecords(char filename[]): ListRecords(filename){;} as the constructor in the header.

Related

C++ Inheritance vector problem (infinite looping+ question of using vector in other class)

I'm making a surface to let the user to input information and print it out.
And this is what it looks like.
main <- menu <- Reservation
<- BookingManager <- BookingRecord
And I create a vector vector<string> CompanyName in Reservation,
This is outputdataInfo() that add CompanyName,
void Reservation::outputdataInfo()
{
string CompName;
cout << "Company Name <-" << endl;
cin >> CompName;
Reservation::setCompanyName(string (CompName) );
cout << CompanyName.at(0) << endl;
// Use for test and it works
cout << CompanyName.size() << endl;
// Use for test and it works
cout << "End of Reservation, thank you." << endl;
}
The setter of CompanyName:(worked)
void Reservation::setCompanyName(const string& cn)
{this->CompanyName.push_back(cn);}
But now BookingRecord::outputdataInfo() wants to print Booking Record.
void BookingRecord::outputdataInfo()
{
cout << " ----- Booking Record -----" << endl;
Reservation::printBookingRecord();
}
And I wrote like this(unconfirm this is correct or not):
void Reservation::printBookingRecord() {
for (int i = 0; i < CompanyName.size(); i++) {
cout << " ---- Company ---- " << endl;
cout << "Name: " << CompanyName.at(i) << endl;
}
}
But CompanyName suddenly looks like it forget anything, or like reset the size.
The result is BookingRecord::outputdataInfo() is printing infinitly non-stop, but nothing happen to the Reservation::printBookingRecord(). This is weird beacuse there suppose no for-loop in BookingRecord::outputdataInfo().
And I wanna know how to print data with (Reservation::printBookingRecord() is called by BookingRecord::outputdataInfo(), but the vector is at "Reservation")
(or vector can be use in other classes)
Big thanks :)
Source Code (kinda bit long sry)
//
// main.cpp
//
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include "Menu.h"
#include "Reservation.h"
#include "BookingManager.h"
using namespace std;
int main(int argc, const char* argv[]) {
Menu m;
Reservation R;
BookingManager BM;
char choice;
do {
choice = m.menu();
switch (choice)
{
case 'R': case 'r':
R.outputdataInfo();
break;
case 'B': case 'b':
BM.outputdataInfo();
break;
default:
cout << "Invalid Alphabet. Please try again." << endl;
break;
}
} while (choice == 'R' || choice == 'r' || choice == 'B' || choice == 'b');
return 0;
}
//.....................
// Menu.h
//
#include <iostream>
#ifndef Menu_h
#define Menu_h
class Menu {
public: //Accessibility as public
char option;
char menu();
};
#endif
//.....................
// Menu.cpp
//
#include <iostream>
#include "Menu.h"
using namespace std;
char Menu::menu() {
cout << "" << endl;
cout << " BNC Exhibition Tour in European Cities" << endl;
cout << " Exhibition Recruitment " << endl;
cout << " " << endl;
cout << "Please type:" << endl;
cout << "R -> for Reservation Page" << endl;
cout << "B -> for Booking Manager Page" << endl;
cout << "And Press ENTER." << endl;
cin >> option;
cout << "" << endl;
return option;
}
//.............................
// Reservation.h
//
#include <iostream>
#include <vector>
using namespace std;
#ifndef Reservation_h
#define Reservation_h
class Reservation {
private:
vector<string> CompanyName;
public: //Accessibility as public
void outputdataInfo();
void setCompanyName(const string& cn);
Reservation();
~Reservation();
void printBookingRecord();
};
#endif
//.....................................
// Reservation.cpp
//
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <vector>
using namespace std;
#include "Reservation.h"
void Reservation::outputdataInfo()
{
cout << "Please input detail information first :" << endl;
string CompName;
cout << "Company Name <-" << endl;
cin >> CompName;
Reservation::setCompanyName(string (CompName) );
cout << CompanyName.at(0) << endl; //it works
cout << CompanyName.size() << endl; //it works
cout << "End of Reservation, thank you." << endl;
}
//////////////////////// S E T T E R ////////////////////
void Reservation::setCompanyName(const string& cn)
{
this->CompanyName.push_back(cn);
}
//////////////////////// S E T T E R ////////////////////
Reservation::Reservation() {}
Reservation::~Reservation() {}
/////////////////////// P R I N T ///////////////////////
void Reservation::printBookingRecord() {
for (int i = 0; i < CompanyName.size(); i++) {
cout << " ---- Company ---- " << endl;
cout << "Name: " << CompanyName.at(i) << endl;
}
}
//.............................
// BookingManager.h
//
#include <iostream>
#include <vector>
#ifndef BookingManager_h
#define BookingManager_h
class BookingManager {
public: //Accessibility as public
char option;
void outputdataInfo();
};
//..........................................
// BookingManager.cpp
//
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <vector>
#include "BookingManager.h"
#include "BookingRecord.h"
using namespace std;
void BookingManager::outputdataInfo() {
BookingRecord BR;
cout << "" << endl;
cout << " ----- Booking Manager -----" << endl;
cout << "" << endl;
cout << "Please type:" << endl;
cout << "B -> for Booking Record" << endl;
cout << "And Press ENTER." << endl;
cin >> option;
cout << "" << endl;
do {
switch (option)
{
case 'B': case 'b':
BR.outputdataInfo();
break;
default:
cout << "Invalid Alphabet. Please try again." << endl;
break;
}
} while (option == 'B' || option == 'b');
}
#endif
//...........................................
// BookingRecord.h
//
#include <iostream>
#include <vector>
#include "Reservation.h"
#ifndef BookingRecord_h
#define BookingRecord_h
class BookingRecord : public Reservation {
public: //Accessibility as public
void outputdataInfo();
};
#endif
//..........................................
// BookingRecord.cpp
//
#include <iostream>
#include <string>
#include <vector>
#include "Reservation.h"
#include "BookingRecord.h"
void BookingRecord::outputdataInfo()
{
cout << "" << endl;
cout << " ----- Booking Record -----" << endl;
cout << "" << endl;
cout << " Print all the information..." << endl;
Reservation::printBookingRecord();
}
// END
So you have two CompanyNames in your code.
One is here, part of the R variable.
int main(int argc, const char* argv[]) {
Menu m;
Reservation R;
And the other is here
void BookingManager::outputdataInfo() {
BookingRecord BR;
BookingRecord derives from Reservation, so it also contains a CompanyName.
I think it's pretty clear that you are adding a name to the CompanyName in R in main but printing out the CompanyName in BR in BookingManager::outputdataInfo.
The class design looks wrong to me.For instance there's a lack of parameters to your methods. Surely BookingManager::outputdataInfo should take a BookingRecord as a parameter to allow the caller to specify which BookingRecord they want to output. Just declaring a BookingRecord as a local variable in BookingManager::outputdataInfo doesn't make any sense.
Before you rush to write a lot of code, try and think about the design of your classes. How the different classes should relate to each other, what member variables they need, what methods they need, what parameters and return types those methods need. Think about this in terms of how your classes model the real world, not in terms of how you are going to implement functionality. That comes later, get the design right first.

Function return nothing with multiple files?

When I run one file, it works perfectly. Then I separate 3 file: header, main, function from that file. It aslo works but return nothing. Here the code:
File Header: printStudent.h
//Header.h
#ifndef PRINTSTUDENT_H_INCLUDED
#define PRINTSTUDENT_H_INCLUDED
void read ();
#endif
File Function: readFileCSV.cpp . It read and print from my .csv file
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string.h>
#include <algorithm>
#define student 1000
using namespace std;
void read (){
ifstream readFileCSV;
readFileCSV.open("studentEn.csv");
if(!readFileCSV.is_open()) {cout << "ERROR: File can't be opened or it doesn't exist" << endl;};
string aMSSV[student];
string aname[student];
string abirthDay[student];
string aaddress[student];
string MSSV;
string name;
string birthDay;
string address;
int countStudent = 0;
while(readFileCSV.good()) {
getline(readFileCSV, MSSV, ',');
getline(readFileCSV, name, ',');
getline(readFileCSV, birthDay, ',');
getline(readFileCSV, address, '\n');
int lengthAddress = address.length();
char charAddress[lengthAddress];
strcpy(charAddress, address.c_str());
char newCharAddress[lengthAddress-2];
for(int i = 0 ; i < lengthAddress-2 ; i++){
newCharAddress[i] = charAddress[i+1];};
string address(newCharAddress, lengthAddress - 2);
aMSSV[countStudent] = MSSV;
aname[countStudent] = name;
abirthDay[countStudent] = birthDay;
aaddress[countStudent] = address;
countStudent ++;
};
countStudent = countStudent - 1;
cout << "..................................................STUDENT..........................................................." << endl;
cout << setw(5) << left << "STT";
cout << setw(25) << left << "MSSV";
cout << setw(25) << left << "Name";
cout << setw(25) << left << "Date of Birth";
cout << left << "Address";
cout << endl;
cout << "...................................................................................................................." << endl;
for(int i = 0 ; i < countStudent ; i++){
cout << setw(5) << left << i + 1;
cout << setw(25) << left << aMSSV[i];
cout << setw(25) << left << aname[i];
cout << setw(25) << left << abirthDay[i];
cout << left << aaddress[i];
cout << endl;
}
readFileCSV.close();
}
File main:
#include <iostream>
#include "printStudent.h"
using namespace std;
int main(){
void read ();
return 0;
}
Help me why it's return nothing and give me a solution how can i make it works? Thanks!
int main(){
void read ();
return 0;
}
It is a function declaration in main a.k.a. forward declaration. Any expression that starts with a type or void is a declaration. It is a local declaration, thus it doesn't conflict with the globally declared function read.
To call the function do it so
int main(){
read ();
return 0;
}

C++: Multiple definition of object error

I recently started with file structuring in C++ with little success. The project was split into following files
-groups.h
-groups.cpp
-people.h
-people.cpp
-main.cpp
There are 2 base classes, groups and players and every other class in inherited by either of them.
Here's the files
groups.h
people.h
groups.cpp
people.cpp
main.cpp
groups.h
#ifndef GROUPS_H
#define GROUPS_H
//Groups of people one of the base classes
class groups {
int num_of_people;
float avg_age;
friend class SoccerTeams;
public:
//virtual string getclass() { return char2str(typeid(*(this)).name()); }
groups(int numb = 0): num_of_people(numb) {};
~groups(){};
};
//SoccerTeam group class
class SoccerTeams : public groups {
std::string teamName;
std::vector<SoccerTeams> teams;
int teamId;
public:
Players player;
void addManager();
std::string nameTeam(int);
void deletePlayer(int);
void showTeam();
void addPlayer();
void showPlayers();
void showManagers();
void exportToFile(const char *);
SoccerTeams() {};
SoccerTeams(std::string, int);
~SoccerTeams() {};
};
//FanClub group class
class FanClubs : public groups{
std::string clubName;
int clubId;
std::vector<FanClubs> fanclubs;
public:
Fans fan;
void addFans();
void showFans();
FanClubs() {};
FanClubs(std::string, int);
~FanClubs() {};
};
#endif
groups.cpp
#include <algorithm>
#include <iostream>
#include <vector>
#include <typeinfo>
#include <boost/units/detail/utility.hpp>
#include <cstdlib>
#include <fstream>
#include <list>
#include "groups.h"
using namespace std;
//Fan Club member functions
FanClubs::FanClubs(string name, int id) {
clubName = name;
clubId = id;
fanclubs.push_back(*this);
};
void FanClubs::showFans() {
cout << "Players in " << fanclubs.begin() -> clubName << endl;
fan.showFanas();
}
void FanClubs::addFans() {
int choice = 0;
cout << "1. Add a bunch of fans\n2. Add custom fans\nChoice: ";
cin >> choice;
switch(choice) {
case 1: {
int requirement;
cout << "How many fans do you need: ";
cin >> requirement;
static const string names[] = {
"Margarita", "Amalia", "Sam", "Mertie", "Jamila", "Vilma",
"Mazie", "Margart", "Lindsay", "Kerstin", "Lula", "Corinna", "Jina",
"Jimmy", "Melynda", "Demetrius", "Beverly", "Olevia", "Jessika",
"Karina", "Abdallah", "Max", "Prateek", "Aghaid"
};
for (int i = 0; i < requirement; ++i) {
fan.name = names[rand() % 24];
fan.age = (rand() % 80 + 1);
fan.sex = ((rand() % 2) ? 'M' : 'F');
fan.under_auth = false;
fan.auth_level = 0;
fans.push_back(fan);
}
break;
}
case 2: {
int requirement;
cout << "How many fans you want to add?\nnumber: ";
cin >> requirement;
for (int i = 0; i < requirement; ++i) {
cout << "======Fan " << i + 1 << "=======\n";
cout << "Enter name: ";
cin >> fan.name;
cout << "Enter age: ";
cin >> fan.age;
cout << "Enter sex: ";
cin >> fan.sex;
fan.under_auth = false;
fan.auth_level = 0;
fans.push_back(fan);
}
break;
}
default:
cout << "Incorrect choice\n";
break;
}
}
//Soccer Teams member functions
string SoccerTeams::nameTeam(int id) {
return teams.begin() -> teamName;
}
void SoccerTeams::showPlayers() {
cout << "Players in " << teams.begin() -> teamName << endl;
player.showPlayas();
}
void SoccerTeams::showManagers() {
int counter = 1;
list<ManagingDirectors>::iterator i;
for (i = directors.begin(); i != directors.end(); i++) {
cout << "Director " << counter << endl;
cout << "Works for team " << nameTeam(i -> directorId) << endl;
cout << "Name: " << i -> name << endl;
cout << "Sex: " << i -> sex << endl;
counter++;
}
}
void SoccerTeams::addPlayer() {
int newId;
int number;
cout << "Number of players to be added: ";
cin >> number;
for (int i = 0; i < number; ++i) {
cout << "\nEnter player name: ";
cin >> player.name;
cout << "Enter sex(M/F): ";
cin >> player.sex;
cout << "Enter age: ";
cin >> player.age;
cout << "Enter player id(0 for random id): ";
cin >> newId;
newId == 0 ? player.playerId = (rand() % 100 + 1) : player.playerId = newId;
player.under_auth = true;
player.auth_level = 0;
players.push_back(player);
teams.begin()->num_of_people++;
}
}
void SoccerTeams::deletePlayer(int id) {
std::vector<Players>::iterator i;
for (i = players.begin(); i != players.end(); ) {
if(i->playerId == id) {
i = players.erase(i);
teams.begin()->num_of_people--;
}
else
i++;
}
}
void SoccerTeams::showTeam() {
vector<SoccerTeams>::iterator i;
for (i = teams.begin(); i != teams.end(); ++i) {
cout << "\nTeam name: " << i -> teamName << endl;
cout << "Team id: " << i -> teamId << endl;
cout << "Number of players: " << i -> num_of_people << endl;
cout << "Average age: " << i -> player.ageCalc()/teams.begin() -> num_of_people << endl;
}
}
SoccerTeams::SoccerTeams(string tn, int id) {
teamName = tn;
teamId = id;
teams.push_back(*this);
};
void SoccerTeams::addManager() {
ManagingDirectors mandir;
int number;
cout << "How many managers you want to add: ";
cin >> number;
for (int i = 0; i < number; i++) {
cout << "Manager " << i + 1 << endl;
cout << "Enter name of the director: ";
cin >> mandir.name;
cout << "Enter the age: ";
cin >> mandir.age;
cout << "Enter the sex(M/F): ";
cin >> mandir.sex;
mandir.directorId = teams.begin() -> teamId;
mandir.auth_level = 3;
mandir.under_auth = false;
directors.push_front(mandir);
}
}
void SoccerTeams::exportToFile(const char *filename) {
ofstream outfile;
outfile.open(filename, ios::out);
vector<Players>::iterator i;
int counter = 1;
outfile << "Team Data" << endl;
outfile << "Team name : " << teamName << "\nPlayers : " << teams.begin() -> num_of_people << endl;
outfile << "Average age: " << teams.begin() -> player.ageCalc()/teams.begin() -> num_of_people << endl;
for (i = players.begin(); i != players.end(); ++i) {
outfile << "\nPlayer " << counter << endl;
outfile << "Name: " << i -> name << endl;
outfile << "Sex : " << i -> sex << endl;
outfile << "Age : " << i -> age << endl;
outfile << "Pid : " << i -> playerId << endl;
counter++;
}
outfile.close();
}
people.h
#ifndef PEOPLE_H
#define PEOPLE_H
//People base class
class people {
string name;
char sex;
int age;
bool under_auth;
int auth_level;
friend class SoccerTeams;
friend class Players;
friend class Fans;
friend class FanClubs;
public:
//virtual string getclass() { return char2str(typeid(*(this)).name()); }
people(){};
~people(){};
//virtual int get_age(){ return this->age; };
};
//players class people
class Players : public people {
int playerId;
int avgAge;
friend class SoccerTeams;
public:
void showPlayas();
float ageCalc();
Players(){};
~Players(){};
};
std::vector<Players> players;
//Class Managing Directors people
class ManagingDirectors : public people {
int directorId;
friend class SoccerTeams;
public:
ManagingDirectors(int);
ManagingDirectors() {};
~ManagingDirectors(){};
};
std::list<ManagingDirectors> directors;
//Fans people class
class Fans : public people {
public:
void showFanas();
Fans(){};
~Fans(){};
};
std::vector<Fans> fans;
#endif
people.cpp
#include <algorithm>
#include <iostream>
#include <vector>
#include <typeinfo>
#include <boost/units/detail/utility.hpp>
#include <cstdlib>
#include <fstream>
#include <list>
#include "people.h"
using namespace std;
const int vector_resizer = 50;
string char2str(const char* str) { return boost::units::detail::demangle(str); }
//Fan class member functions
void Fans::showFanas() {
int counter = 1;
vector<Fans>::iterator i;
for (i = fans.begin(); i != fans.end(); ++i) {
cout << "\nFan " << counter << endl;
cout << "Name: " << i -> name << endl;
cout << "Sex: " << i -> sex << endl;
cout << "Age: " << i -> age << endl;
counter++;
}
}
//Players class member functions
float Players::ageCalc() {
int totalAge = 0;
vector<Players>::iterator i;
for (i = players.begin(); i != players.end(); ++i) {
totalAge += i->age;
}
return totalAge;
}
void Players::showPlayas() {
int counter = 1;
vector<Players>::iterator i;
for (i = players.begin(); i != players.end(); ++i) {
cout << "\nPlayer " << counter << endl;
cout << "Name: " << i -> name << endl;
cout << "Sex: " << i -> sex << endl;
cout << "Age: " << i -> age << endl;
cout << "Player id: " << i -> playerId << endl;
counter++;
}
}
//Member functions of Managing DIrectos
ManagingDirectors::ManagingDirectors(int number) {
directorId = number;
};
In addition to these files, I also have a makefile.
//makefile
footballmaker: main.o groups.o people.o
gcc -o main main.o groups.o people.o
rm groups.o people.o
Also here's all the code in one file, the way it works right now.
I'm getting the following error when I try to make the program,
gcc -o main main.o groups.o people.o
groups.o:(.bss+0x0): multiple definition of `players'
main.o:(.bss+0x0): first defined here
groups.o:(.bss+0x20): multiple definition of `directors[abi:cxx11]'
main.o:(.bss+0x20): first defined here
groups.o:(.bss+0x40): multiple definition of `fans'
main.o:(.bss+0x40): first defined here
people.o:(.bss+0x0): multiple definition of `players'
main.o:(.bss+0x0): first defined here
people.o:(.bss+0x20): multiple definition of `directors[abi:cxx11]'
main.o:(.bss+0x20): first defined here
people.o:(.bss+0x40): multiple definition of `fans'
main.o:(.bss+0x40): first defined here
...
collect2: error: ld returned 1 exit status
makefile:3: recipe for target 'footballmaker' failed
make: *** [footballmaker] Error 1
The entire error was over 400 lines long, it is attached here.
I'm not sure how I can include files, so that I don't duplicate them, since the files are needed to make the program work, would there be a better way to split my code into files?
You define (not just declare!) variables at file scope in header file people.h. Such a variable definition will be visible to all other translation units at time of linkage. If different translation units, e.g. people.cpp and main.cpp, now include people.h, then this is as if these variable definitions had been written directly into both people.cpp and main.cpp, each time defining a separate variable with the same name at a global scope.
To overcome this, declare the variables in the header file, but define it in only one translation unit, e.g. people.cpp. Just declaring a variable means putting keyword extern in front of it (telling the compiler that variable definition will be provided by a different translation unit at the time of linking):
// people.h
extern std::vector<Players> players;
extern std::list<ManagingDirectors> directors;
extern std::vector<Fans> fans;
// people.cpp
std::vector<Players> players;
std::list<ManagingDirectors> directors;
std::vector<Fans> fans;

Floating Point Exception while reading from file

the program should read from 2 files (author.dat and citation.dat) and save them into a map and set;
first it reads the citationlist without problem, then it seems to properly read the authors and after it went through the whole list (author.dat) a floating point exception arises .. can't quite figure out why
seems to happen in author.cpp inside the constructor for authorlist
author.cpp:
#include <fstream>
#include <iostream>
#include "authors.h"
using namespace std;
AuthorList::AuthorList(char *fileName) {
ifstream s (fileName);
int idTemp;
int nrTemp;
string nameTemp;
try {
while (true){
s >> idTemp >> nrTemp >> nameTemp;
cout << idTemp << " " << nrTemp << " " << nameTemp << " test_string";
authors.insert(std::make_pair(idTemp,Author(idTemp,nrTemp,nameTemp)));
if (!s){
cout << "IF-CLAUSE";
throw EOFException();
}
cout << "WHILE-LOOP_END" << endl;
}
} catch (EOFException){}
}
author.h:
#ifndef CPP_AUTHORS_H
#define CPP_AUTHORS_H
#include <iostream>
#include <map>
#include <string>
#include "citations.h"
class Author {
public:
Author (int id, int nr, std::string name) :
articleID(id),
authorNR(nr),
authorName(name){}
int getArticleID() const {
return articleID;
}
std::string getAuthorName() const {
return authorName;
}
private:
int articleID;
int authorNR;
std::string authorName;
};
class AuthorList {
public:
AuthorList(char *fileName);
std::pair<std::multimap<int,Author>::const_iterator, std::multimap<int,Author>::const_iterator> findAuthors(int articleID) {
return authors.equal_range(articleID);
}
private:
std::multimap<int,Author> authors;
};
#endif //CPP_AUTHORS_H
programm.cpp:
#include <iostream>
#include <cstdlib>
#include "citations.h"
#include "authors.h"
#include "authorCitation.h"
using namespace std;
int main(int argc, char *argv[]){
CitationList *cl;
AuthorList *al;
//check if argv array has its supposed length
if (argc != 4){
cerr << "usage: programm article.dat citation.dat author.dat";
return EXIT_FAILURE;
}
//inserting citation.dat and author.dat in corresponding lists (article.dat not used)
cl = new CitationList(argv[2]);
al = new AuthorList(argv[3]);
try {
AuthorCitationList *acl;
acl->createAuthorCitationList(al,cl);
acl->printAuthorCitationList2File("authorcitation.dat");
} catch (EOFException){
cerr << "something went wrong while writing to file";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
All files:
https://drive.google.com/file/d/0B734gx5Q_mVAV0xWRG1KX0JuYW8/view?usp=sharing
I am willing to bet that the problem is caused by the following lines of code:
AuthorCitationList *acl;
acl->createAuthorCitationList(al,cl);
You are calling a member function using an uninitialized pointer. I suggest changing the first line to:
AuthorCitationList *acl = new AuthorCitationList;
Add any necessary arguments to the constructor.
While you are at it, change the loop for reading the data also. You have:
while (true){
s >> idTemp >> nrTemp >> nameTemp;
cout << idTemp << " " << nrTemp << " " << nameTemp << " test_string";
authors.insert(std::make_pair(idTemp,Author(idTemp,nrTemp,nameTemp)));
if (!s){
cout << "IF-CLAUSE";
throw EOFException();
}
cout << "WHILE-LOOP_END" << endl;
}
When you do that, you end up adding data once after the end of line has been reached. Also, you seem to have the last line in the wrong place. It seems to me that it should be outside the while loop.
You can use:
while (true){
s >> idTemp >> nrTemp >> nameTemp;
// Break out of the loop when reading the
// data is not successful.
if (!s){
cout << "IF-CLAUSE";
throw EOFException();
}
cout << idTemp << " " << nrTemp << " " << nameTemp << " test_string";
authors.insert(std::make_pair(idTemp,Author(idTemp,nrTemp,nameTemp)));
}
cout << "WHILE-LOOP_END" << endl;
You can simplify it further by using:
while (s >> idTemp >> nrTemp >> nameTemp){
cout << idTemp << " " << nrTemp << " " << nameTemp << " test_string";
authors.insert(std::make_pair(idTemp,Author(idTemp,nrTemp,nameTemp)));
}
cout << "WHILE-LOOP_END" << endl;

Function not recognized within scope

I've almost finished writing a program that will detect palindromes from a file and output a new file highlighting the palindromes but I'm stuck on a really dumb error. I'm trying to write a test for one of my methods (TDD) and, for some reason, it's not recognizing the function as within the scope.
I'm calling the isPalindrome(string s) method (declared in PalindromeDetector.h) in my isPalindromeTest() method (declared in PalindromeDetectorTest.h) but, for some reason, it's not recognizing it as within the scoope.
I feel like everything should be working but it just isn't. Any help you can provide would be greatly appreciated. Below is my code:
PalindromeDetector.h
#ifndef PALINDROMEDETECTOR_H_
#define PALINDROMEDETECTOR_H_
#include <iostream>
using namespace std;
class PalindromeDetector {
public:
void detectPalindromes();
bool isPalindrome(string s);
};
#endif /* PALINDROMEDETECTOR_H_ */
PalindromeDetector.cpp
#include "PalindromeDetector.h"
#include "Stack.h"
#include "ArrayQueue.h"
#include <iostream>
#include <fstream>
#include <cassert>
#include <cctype>
#include <string>
using namespace std;
void PalindromeDetector::detectPalindromes() {
cout << "Enter the name of the file whose palindromes you would like to detect:" << flush;
string fileName;
cin >> fileName;
cout << "Enter the name of the file you would like to write the results to: " << flush;
string outFileName;
cin >> outFileName;
fstream in;
in.open(fileName.c_str());
assert(in.is_open());
ofstream out;
out.open(outFileName.c_str());
assert(out.is_open());
string line;
while(in.good()){
getline(in, line);
line = line.erase(line.length()-1);
if(line.find_first_not_of(" \t\v\r\n")){
string blankLine = line + "\n";
out << blankLine;
} else if(isPalindrome(line)){
string palindromeYes = line + " ***\n";
out << palindromeYes;
} else {
string palindromeNo = line + "\n";
out << palindromeNo;
}
if(in.eof()){
break;
}
}
in.close();
out.close();
}
bool PalindromeDetector::isPalindrome(string s){
unsigned i = 0;
Stack<char> s1(1);
ArrayQueue<char> q1(1);
while(s[i]){
char c = tolower(s[i]);
if(isalnum(c)){
try{
s1.push(c);
q1.append(c);
} catch(StackException& se) {
unsigned capS = s1.getCapacity();
unsigned capQ = q1.getCapacity();
s1.setCapacity(2*capS);
q1.setCapacity(2*capQ);
s1.push(c);
q1.append(c);
}
}
i++;
}
while(s1.getSize() != 0){
char ch1 = s1.pop();
char ch2 = q1.remove();
if(ch1 != ch2){
return false;
}
}
return true;
}
PalindromeDetectorTest.h
#ifndef PALINDROMEDETECTORTEST_H_
#define PALINDROMEDETECTORTEST_H_
#include "PalindromeDetector.h"
class PalindromeDetectorTest {
public:
void runTests();
void detectPalindromesTest();
void isPalindromeTest();
};
#endif /* PALINDROMEDETECTORTEST_H_ */
PalindromeDetectorTest.cpp
#include "PalindromeDetectorTest.h"
#include <cassert>
#include <iostream>
#include <fstream>
#include <cctype>
#include <string>
using namespace std;
void PalindromeDetectorTest::runTests(){
cout << "Testing palindrome methods... " << endl;
detectPalindromesTest();
isPalindromeTest();
cout << "All tests passed!\n" << endl;
}
void PalindromeDetectorTest::detectPalindromesTest(){
cout << "- testing detectPalindromes()... " << flush;
fstream in;
string fileName = "testFile.txt";
in.open(fileName.c_str());
assert(in.is_open());
cout << " 1 " << flush;
ofstream out;
string fileOutName = "testFileOut.txt";
out.open(fileOutName.c_str());
assert(out.is_open());
cout << " 2 " << flush;
cout << " Passed!" << endl;
}
void PalindromeDetectorTest::isPalindromeTest(){
cout << "- testing isPalindrome()... " << flush;
// test with one word palindrome
string s1 = "racecar";
assert(isPalindrome(s1) == true); // these are not recognized within the scope
cout << " 1 " << flush;
// test with one word non-palindrome
string s2 = "hello";
assert(isPalindrome(s2) == false); // these are not recognized within the scope
cout << " 2 " << flush;
// test with sentence palindrome
string s3 = "O gnats, tango!";
assert(isPalindrome(s3) == true); // these are not recognized within the scope
cout << " 3 " << flush;
// test with sentence non-palindrome
string s4 = "This is not a palindrome.";
assert(isPalindrome(s4) == false); // these are not recognized within the scope
cout << " 4 " << flush;
cout << " Passed!" << endl;
}
isPalindrome is a member function of PalindromeDetector, but you are trying to call it from within a PalindromeDetectorTest method. If the test class derived from PalindromeDetector this would work, but there isn't (and almost certainly shouldn't be) any such relationship between them.
You need a PalindromeDetector object to call the method on. Probably just as simple as this:
void PalindromeDetectorTest::isPalindromeTest(){
cout << "- testing isPalindrome()... " << flush;
PalindromeDetector sut; // "subject under test"
// test with one word palindrome
string s1 = "racecar";
assert(sut.isPalindrome(s1) == true);
// etc.
}
You could also make the PalindromeDetector methods static since the object doesn't appear to have any state. Then you could simply call PalindromeDetector::isPalindrome(s1); without the need to create an instance.