lundi 25 avril 2016

Using virtual functions with classes and constructors to print book info

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:

  1. 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.
  2. 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!

Aucun commentaire:

Enregistrer un commentaire