Thread: Book Program - Help Needed

  1. #271
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    Last week I found a copy of std_lib_facilities.h somewhere on the Publisher or Author site.
    http://www.stroustrup.com/Programmin...b_facilities.h

    I found that using a newer MinGW GCC 5.1 and a few options that I can compile the OP code and make a build log.

    Of the build log I think this one is the one that would concern me the most.
    Code:
    C:\SourceCode\Test\books\main.cpp: In member function 'void Library::add_book(const Book&)':
    C:\SourceCode\Test\books\main.cpp:539:22: warning: unused variable 'x' [-Wunused-variable]
         for (const Book& x : books)
    But, I am still a C Programmer trying to learn C++, myself.

    Tim S.

    The build log I got; I only changed the single line that includes Author's header of "std_lib_facilities.h", now.
    Code:
    -------------- Build: Debug in books (compiler: gcc-5.1.x)---------------
    
    mingw32-g++.exe -Weffc++ -pedantic -std=c++11 -Wextra -Wall -fexceptions -g  -c C:\SourceCode\Test\books\main.cpp -o obj\Debug\main.o
    In file included from C:\SourceCode\Test\books\main.cpp:7:0:
    C:\SourceCode\Test\books\std_lib_facilities.h: In member function 'char& String::operator[](unsigned int)':
    C:\SourceCode\Test\books\std_lib_facilities.h:111:8: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
       if (i<0||size()<=i) throw Range_error(i);
            ^
    C:\SourceCode\Test\books\std_lib_facilities.h: In member function 'const char& String::operator[](unsigned int) const':
    C:\SourceCode\Test\books\std_lib_facilities.h:117:8: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
       if (i<0||size()<=i) throw Range_error(i);
            ^
    C:\SourceCode\Test\books\main.cpp: At global scope:
    C:\SourceCode\Test\books\main.cpp:35:27: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
         const int copyright() const { return copyright_date; }
                               ^
    C:\SourceCode\Test\books\main.cpp:36:33: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
         const Genre genre_of_book() const { return book_genre; }
                                     ^
    C:\SourceCode\Test\books\main.cpp:37:29: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
         const bool checked_in() const { return book_checked_in; }
                                 ^
    C:\SourceCode\Test\books\main.cpp:78:82: warning: unused parameter 'library_fee' [-Wunused-parameter]
         Patron(const string& user_name, const string& library_card_number, const int library_fee)
                                                                                      ^
    C:\SourceCode\Test\books\main.cpp:78:82: warning: unused parameter 'library_fee' [-Wunused-parameter]
    C:\SourceCode\Test\books\main.cpp: In member function 'void Library::relieve_patron_debt(const Patron&, int)':
    C:\SourceCode\Test\books\main.cpp:458:61: warning: parameter 'fee' set but not used [-Wunused-but-set-parameter]
     void Library::relieve_patron_debt(const Patron& patron, int fee)
                                                                 ^
    C:\SourceCode\Test\books\main.cpp: At global scope:
    C:\SourceCode\Test\books\main.cpp:458:49: warning: unused parameter 'patron' [-Wunused-parameter]
     void Library::relieve_patron_debt(const Patron& patron, int fee)
                                                     ^
    C:\SourceCode\Test\books\main.cpp: In member function 'void Library::add_book(const Book&)':
    C:\SourceCode\Test\books\main.cpp:539:22: warning: unused variable 'x' [-Wunused-variable]
         for (const Book& x : books)
                          ^
    mingw32-g++.exe  -o bin\Debug\books.exe obj\Debug\main.o   
    Output file is bin\Debug\books.exe with size 1.85 MB
    Process terminated with status 0 (0 minute(s), 50 second(s))
    0 error(s), 10 warning(s) (0 minute(s), 50 second(s))
    Last edited by stahta01; 08-02-2015 at 06:00 PM.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  2. #272
    Registered User
    Join Date
    Mar 2015
    Posts
    384
    @Adrian: So the problem is in these functions?
    Code:
    void Library::add_book(const Book& book)
    {
        for (const Book& x : books)
        {
            if (is_book_in_library(book))
            {
                error("error: Book is already in library.");
            }
        }
        books.push_back(book);
    }
    Code:
    bool Library::book_in_library(const Book& book) const
    {
        for (size_t i = 0; i < books.size(); i++)
        {
            if (book == books[i])
            {
                return true;
            }
        }
        return false;
    }
    Code:
    bool Library::is_book_in_library(const Book& book) const
    {
        if (!book_in_library(book))
        {
            error("error: book either out of copies or not in library to begin with");
            return false;
        }
        return true;
    }
    Is there a problem in the patron ones, too?

    If you're going to give me the answer, please don't make it too blatant, at least? Give me some example code first that just gives me an idea. If I still don't get it, then you could give me code that's blatantly for my program (as a last resort).
    Last edited by Osman Zakir; 08-02-2015 at 05:58 PM.

  3. #273
    Guest
    Guest
    Quote Originally Posted by Osman Zakir View Post
    If you're going to give me the answer, please don't make it too blatant, at least? Give me some example code first that just gives me an idea. If I still don't get it, then you could give me code that's blatantly for my program (as a last resort).
    Ok, I'll just comment on the code directly:
    Code:
    void Library::add_book(const Book& book)
    {
        for (const Book& x : books) // This loop iterates over vector 'books', putting each book into 'x'
        {
            /* The following condition is evaluated as many times as there are elements in 'books'.
                If there are 5 books, is_books_in_library() will be called 5 times, each time
                with the same book, namely the one you passed in as add_book's argument.
                There is no reason why this function should run more than once. */
            if (is_book_in_library(book))
            {
                error("error: Book is already in library.");
            }
        }
        books.push_back(book);
    }
    stahta01 is right in that your compiler should produce still more warnings!


    The following two functions are almost identical; it seems redundant. Note that you can overload the same function to take different arguments if necessary. In this case, I think it should only take Book objects, not std::string. (unless the assignment demands it)
    Code:
    bool Library::book_in_library(const Book& book) const
    {
        for (size_t i = 0; i < books.size(); i++) // if you're gonna use range-based for-loops in your other functions, then do so here
        {
            if (book == books[i])
            {
                return true;
            }
        }
        return false;
    }
    
    bool Library::is_book_in_library(const Book& book) const
    {
        if (!book_in_library(book))
        {
            error("error: book either out of copies or not in library to begin with"); // we aware that this function throws, the control flow will not proceed normally.
            return false;
        }
        return true;
    }
    Is there a problem in the patron ones, too?
    Looks ok to me. You should add the check function to add_patron as you did for add_book. But don't rush it, first fix any current errors, then carefully extend functionality.
    Last edited by Guest; 08-02-2015 at 06:44 PM.

  4. #274
    Registered User
    Join Date
    Mar 2015
    Posts
    384
    About add_book(), then, how do I make sure is_book_in_library() is only called once, but the loop is still look through the whole vector to see if the book is in there already or not? As for book_in_library() and is_book_in_library(), do you mean I should combine them? Then, would it be better to just take out book_in_library() and do everything in is_book_in_library()? I think I should add that those functions already take jus the Book object, with no string object.

    And yeah, I think I really should take out the call to error() from is_book_in_library().

    What flags should I turn on to see those other warnings, though? Could you show me a list of all of the flags you've got turned on?

    Edit: I've taken out the call to error() form is_book_in_library() now. So now I just need the answers to my other questions.

    Edit2: I've changed the ranged-for loops to normal for-loops now, and I've also taken out the redundant patron and book searchers. Look over it again now, please:
    Code:
    // Osman Zakir
    // 7/12/2015
    // Programming: Principles and Practice Using C++ 2nd Edition by Bjarne Stroustrup
    // Chapter 9 Exercises 5 - 9
    // Program implements a Book class, a Library class, a Patron class, a Genre class,
    // and a Transaction, and constructs objects for the class to print out data for the books and patrons in a library
    #include "../custom_std_lib_facilities.h"
    #include <algorithm>
    #include <vector>
    
    
    using namespace std;
    
    
    enum class Genre
    {
        fiction, nonfiction, periodical, biography, children
    };
    
    
    class Book
    {
    private:
        string isbn_number;
        string title;
        string author;
        int copyright_date;
        Genre book_genre;
        bool book_checked_in = true;
    public:
        Book(const string& isbn_number, const string& title, const string& author, const int copyright_date, const Genre book_genre);
        const string& isbn() const { return isbn_number; }
        const string& book_title() const { return title; }
        const string& author_name() const { return author; }
        const int copyright() const { return copyright_date; }
        const Genre genre_of_book() const { return book_genre; }
        const bool checked_in() const { return book_checked_in; }
        void set_check(bool check) { book_checked_in = check; }
    };
    
    
    enum class Month
    {
        jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
    };
    
    
    class Date
    {
    public:
        Date(const int y, const Month m, const int d);
        int year() const { return y; }
        Month month() const { return m; }
        int day() const { return d; }
        void add_day(int n);
        void add_month(int n);
        void set_day(int value);
        void set_month(Month value);
        void set_year(int value);
    private:
        int y;
        Month m;
        int d;
    };
    
    
    class Patron
    {
    private:
        string user_name;
        string library_card_number;
        int library_fee;
    public:
        const string& username() const { return user_name; }
        const string& card_number() const { return library_card_number; }
        int fee() const { return library_fee; }
        void set_fee(int value) { library_fee = value; }
        Patron(const string& user_name, const string& library_card_number, const int library_fee)
        : user_name{user_name}, library_card_number{library_card_number}, library_fee{0} {}
    };
    
    
    class Library
    {
    private:
        struct Transaction
        {
        string book_isbn;
        string patron_card_number;
        Date date;
        Transaction(const string& book_isbn, const string& patron_card_number, const Date& date)
        : book_isbn{book_isbn}, patron_card_number{patron_card_number}, date{date} {}
        };
    
    
        vector<Book> books{};
        vector<Patron> patrons{};
        vector<Transaction> transactions{};
        bool is_book_in_library(const Book& book_title) const;
        bool is_patron_in_library(const Patron& patron_name) const;
    public:
        void add_book(const Book& book);
        void add_patron(const Patron& patron);
        void check_book_in(Book& book, const Date due_date, Patron& patron);
        void check_book_out(Book& book, const Date transaction_date, const Patron& patron);
        void extend_due_date(Date due_date);
        void relieve_patron_debt(const Patron& patron, int fee);
        int number_of_books();
        int number_of_checked_out_books();
    };
    
    
    void printBookData(const Book& book);
    
    
    void printPatronData(const Patron& patron);
    
    
    bool operator==(const Book& book1, const Book& book2);
    
    
    bool operator!=(const Book& book1, const Book& book2);
    
    
    bool is_fee_owed(const Patron& patron);
    
    
    ostream& operator<<(ostream& os, const Date& dd);
    
    
    int main()
    {
        try
        {
            cout<<"Creating books, patrons and library...\n";
            Book book1{"0-15-204560-0", "Heir Apparent", "Vivian Vande Velde", 2002, Genre::fiction};
            Book book2{"0-375-82668-8", "Eragon", "Christopher Paolini", 2003, Genre::fiction};
            Book book3{"0-590-55356-9", "Sandry's Book", "Tamora Pierce", 1997, Genre::fiction};
    
    
            Patron patron1{"Mike", "3-2504-58140-9664", patron1.fee()};
            Patron patron2{"Osman", "4-2512-21408-5521", patron2.fee()};
            Patron patron3{"Draco", "2-1262-52741-6185", patron3.fee()};
    
    
            Library library;
            library.add_book(book1);
            library.add_book(book2);
            library.add_book(book3);
    
    
            book1.set_check(true);
            book2.set_check(true);
            book3.set_check(true);
    
    
            library.add_patron(patron1);
            library.add_patron(patron2);
            library.add_patron(patron3);
    
    
            Date date1{2015, Month::mar, 25};
            Date date2{2015, Month::mar, 26};
            Date date3{2015, Month::mar, 24};
    
    
            if (book1.checked_in() || !is_fee_owed(patron2))
            {
                library.check_book_out(book1, date1, patron2);
            }
            if (book2.checked_in() || !is_fee_owed(patron1))
            {
                library.check_book_out(book2, date2, patron1);
            }
            if (book3.checked_in() || !is_fee_owed(patron3))
            {
                library.check_book_out(book3, date3, patron3);
            }
            else if (!book1.checked_in())
            {
                error("error: book has already been checked out.");
            }
            else if (!book2.checked_in())
            {
                error("error: book has already been checked out.");
            }
            else if (!book3.checked_in())
            {
                error("error: book has already been checked out.");
            }
    
    
            cout<<"Checking in books...\n";
    
    
            Date due_date1{2015, Month::apr, 24};
            Date due_date2{2015, Month::apr, 25};
            Date due_date3{2015, Month::apr, 26};
    
    
            library.check_book_in(book1, due_date1, patron2);
            library.check_book_in(book2, due_date2, patron1);
            library.check_book_in(book3, due_date3, patron3);
    
    
            cout<<"\n\nprinting info...\n";
            cout << "The information for " << book1.book_title() << " is:\n";
            printBookData(book1);
            cout << "\n";
            cout << "The information for " << book2.book_title() << " is:\n";
            printBookData(book2);
            cout << "\n";
            cout << "The information for " << book3.book_title() << " is:\n";
            printBookData(book3);
            cout << "\nInformation on Library Patrons:\n";
            printPatronData(patron1);
            cout << "\n";
            printPatronData(patron2);
            cout << "\n";
            printPatronData(patron3);
            cout << "\n";
    
    
            keep_window_open();
        }
        catch(runtime_error& r)
        {
            cout << r.what() << "\n";
            keep_window_open();
            return 1;
        }
        catch(...)
        {
            cout << "Whoops! Unknown exception! Please try again later.\n";
            keep_window_open();
            return 2;
        }
    }
    
    
    Book::Book(const string& isbn_number, const string& title, const string& author, const int copyright_date, const Genre book_genre)
    :isbn_number{isbn_number}, title{title}, author{author}, copyright_date{copyright_date}, book_genre{book_genre}
    {
        constexpr int MaxDate = 2015;
        if (copyright_date <= 0 || copyright_date > MaxDate)
        {
            error("invalid copyright date");
        }
        stringstream ss(isbn_number);
        char valid = '-';
        char invalid = ' ';
        for (int i = 0; i < 3; i++)
        {
            int integer = -1;
            char character = invalid;
            ss >> integer >> character;
            if (integer < 0 || character != valid)
            {
                error("Invalid ISBN");
            }
        }
        string final;
        ss >> final;
        if (final.size() != 1)
        {
            error("Invalid ISBN");
        }
        else if(!isdigit(final[0]) && !isalpha(final[0]))
        {
            error("Invalid ISBN");
        }
    }
    
    
    Date::Date(const int y, const Month m, const int d)
    : y{y}, m{m}, d{d}
    {
        if (m == Month::feb && d > 28)
        {
            error("Error: Invalid date; unless this is/was a leap-year, February should only have 28 days. Try again later.");
        }
        if ((m == Month::jan || m == Month::mar || m == Month::may || m == Month::jul || m == Month::aug || m == Month::oct || m == Month::dec) && d > 31)
        {
            error("Error: Invalid date; this month only has 31 days. Try again later.");
        }
        if ((m == Month::apr || m == Month::jun || m == Month::sep || m == Month::nov) && d > 30)
        {
            error("Error: Invalid date; this month only has 30 days. Try again later.");
        }
        if (m < Month::jan || m > Month::dec || d <= 0)
        {
            error("Error: Invalid month and/or day! Try again later.");
        }
        if (y <= 0 || y > 2200)
        {
            error("Error: Invalid year! Please try again later.");
        }
    }
    
    
    void Date::add_day(int n)
    {
        d += n;
        if (m == Month::feb && d > 28)
        {
            error("Error: Invalid date; unless this is/was a leap-year, February should only have 28 days. Try again later.");
        }
        if ((m == Month::jan || m == Month::mar || m == Month::may || m == Month::jul || m == Month::aug || m == Month::oct || m == Month::dec) && d > 31)
        {
            error("Error: Invalid date; this month only has 31 days. Try again later.");
        }
        if ((m == Month::apr || m == Month::jun || m == Month::sep || m == Month::nov) && d > 30)
        {
            error("Error: Invalid date; this month only has 30 days. Try again later.");
        }
        if (d <= 0)
        {
            error("Error: Invalid day! Try again later.");
        }
    }
    
    
    void Date::add_month(int n)
    {
        m = static_cast<Month>(static_cast<int>(m) + n);
        if (m < Month::jan || m > Month::dec)
        {
            error("Error: Invalid month and/or day! Try again later.");
        }
    }
    
    
    void Date::set_day(int value)
    {
        d = value;
        if (m == Month::feb && d > 28)
        {
            error("Error: Invalid date; unless this is/was a leap-year, February should only have 28 days. Try again later.");
        }
        if ((m == Month::jan || m == Month::mar || m == Month::may || m == Month::jul || m == Month::aug || m == Month::oct || m == Month::dec) && d > 31)
        {
            error("Error: Invalid date; this month only has 31 days. Try again later.");
        }
        if ((m == Month::apr || m == Month::jun || m == Month::sep || m == Month::nov) && d > 30)
        {
            error("Error: Invalid date; this month only has 30 days. Try again later.");
        }
        if (d <= 0)
        {
            error("Error: Invalid day! Try again later.");
        }
    }
    
    
    void Date::set_month(Month value)
    {
        m = value;
        if (m < Month::jan || m > Month::dec)
        {
            error("Error: Invalid month and/or day! Try again later.");
        }
    }
    
    
    void Date::set_year(int value)
    {
        y = value;
        if (y <= 0 || y > 2200)
        {
            error("Error: Invalid year! Please try again later.");
        }
    }
    
    
    void Library::check_book_in(Book& book, const Date due_date, Patron& patron)
    {
        int fee = 10 * 100;
        bool finished_reading_book = true;
        if (finished_reading_book)
        {
            Date return_date{2015, Month::apr, 24};
            if (due_date.day() == 24 && due_date.month() == Month::apr)
            {
                return_date.set_month(Month::apr);
                return_date.set_day(24);
            }
            else if (due_date.day() == 25 && due_date.month() == Month::apr)
            {
                return_date.set_month(Month::apr);
                return_date.set_day(25);
            }
            else if (due_date.day() == 26 && due_date.month() == Month::apr)
            {
                return_date.set_month(Month::apr);
                return_date.set_day(26);
            }
            if (return_date.day() > due_date.day() || static_cast<int>(return_date.month()) > static_cast<int>(due_date.month()))
            {
                patron.set_fee(fee);
                error("error: book is overdue, please pay fee of $10.");
            }
            book.set_check(true);
        }
        else
        {
            extend_due_date(due_date);
        }
        relieve_patron_debt(patron, patron.fee());
    }
    
    
    void Library::check_book_out(Book& book, const Date transaction_date, const Patron& patron)
    {
        if (is_fee_owed(patron))
        {
            error("error: fee is owed; relieve fee first before borrowing another book.");
        }
        else
        {
            if (is_book_in_library(book) && is_patron_in_library(patron))
            {
                Date due_date{2015, Month::apr, 24};
                if (transaction_date.day() == 24)
                {
                    due_date.set_day(24);
                }
                else if (transaction_date.day() == 25)
                {
                    due_date.set_day(25);
                }
                else if (transaction_date.day() == 26)
                {
                    due_date.set_day(26);
                }
                Transaction transaction{book.isbn(), patron.card_number(), transaction_date};
                transactions.push_back(transaction);
                if (is_book_in_library(book))
                {
                    book.set_check(false);
                }
            }
            else
            {
                error("error: this book and patron aren't in the library");
            }
        }
    }
    
    
    void Library::extend_due_date(Date due_date)
    {
        int extension_value = 1;
        due_date.add_month(extension_value);
        if (due_date.month() > Month::dec || due_date.month() < Month::jan)
        {
            error("error: invalid month value.");
        }
    }
    
    
    void Library::relieve_patron_debt(const Patron& patron, int fee)
    {
        bool fee_paid = true;
        if (fee_paid)
        {
            fee = 0 * 100;
        }
    }
    
    
    int Library::number_of_checked_out_books()
    {
        vector<Book> number_of_books;
        for (size_t i = 0; i < books.size(); i++)
        {
            if (!books[i].checked_in())
            {
                number_of_books.push_back(books[i]);
            }
        }
        return number_of_books.size();
    }
    
    
    ostream& operator<<(ostream& os, const Date& dd)
    {
        return os << dd.year() << '-' << static_cast<int>(dd.month()) << '-' << dd.day();
    }
    
    
    void printBookData(const Book& book)
    {
        cout << "ISBN number: " << book.isbn() << "\n"
            << "Title: " << book.book_title() << "\n"
            << "Author: " << book.author_name() << "\n";
        switch(book.genre_of_book())
        {
        case Genre::biography:
            cout << "Genre: Biography\n";
            break;
        case Genre::children:
            cout << "Genre: Children\n";
            break;
        case Genre::fiction:
            cout << "Genre: Fiction\n";
            break;
        case Genre::nonfiction:
            cout << "Genre: Nonfiction\n";
            break;
        case Genre::periodical:
            cout << "Genre: Periodical\n";
            break;
        default:
            cout << "No Genre?\n";
            break;
        }
    }
    
    
    bool operator==(const Book& book1, const Book& book2)
    {
        return book1.isbn() == book2.isbn();
    }
    
    
    bool operator!=(const Book& book1, const Book& book2)
    {
        return !(book1.isbn() == book2.isbn());
    }
    
    
    void printPatronData(const Patron& patron)
    {
        cout << "Patron's name: " << patron.username() << "\n"
            << "Library card no: " << patron.card_number() << "\n"
            << "Fee owed: $" << patron.fee() << "\n";
    }
    
    
    void Library::add_book(const Book& book)
    {
        for (size_t i = 0; i < books.size(); i++)
        {
            if (is_book_in_library(book))
            {
                error("error: Book is already in library.");
            }
        }
        books.push_back(book);
    }
    
    
    void Library::add_patron(const Patron& patron)
    {
        patrons.push_back(patron);
    }
    
    
    int Library::number_of_books()
    {
        return books.size();
    }
    
    
    bool Library::is_book_in_library(const Book& book) const
    {
        for (size_t i = 0; i < books.size(); i++)
        {
            if (book == books[i])
            {
                return true;
            }
        }
        return false;
    }
    
    
    bool Library::is_patron_in_library(const Patron& patron) const
    {
        for (size_t i = 0; i < patrons.size(); i++)
        {
            if (patron.username() == patrons[i].username())
            {
                return true;
            }
        }
        return false;
    }
    
    
    bool is_fee_owed(const Patron& patron)
    {
        if (patron.fee() > 0)
        {
            error("error: a fee is owed");
            return true;
        }
        return false;
    }
    Last edited by Osman Zakir; 08-02-2015 at 07:23 PM.

  5. #275
    Guest
    Guest
    About add_book(), then, how do I make sure is_book_in_library() is only called once, but the loop is still look through the whole vector to see if the book is in there already or not?
    It's is_book_in_library's job to look through all books. So you call it once before adding a book.

    As for book_in_library() and is_book_in_library(), do you mean I should combine them? Then, would it be better to just take out book_in_library() and do everything in is_book_in_library()?
    Choose whichever name you prefer, just be consistent with naming conventions throughout your program. If one function returns true/false and the other function does something based on that, then replace "return true/false;" with whatever actions the other function took.

    I think I should add that those functions already take jus the Book object, with no string object.
    Yes, I got mixed up with your code postings.

    What flags should I turn on to see those other warnings, though? Could you show me a list of all of the flags you've got turned on?
    I always use -std=c++14 -pedantic -Wall for testing. For learners, some people suggest -Werror which turns all warnings into errors, so they aren't being "ignored".

    Look over it again now, please:
    I'll ignore the methods still under discussion right now.

    Line 29: Move the initalization into Book's constructor as I suggested.
    Line 30-37: Don't return values as const here, only references.
    Code:
    void Library::relieve_patron_debt(const Patron& patron, int fee) // what is the purpose of the separately passed fee?
    {
        bool fee_paid = true; // always true
        if (fee_paid) // hence always executed
        {
            fee = 0 * 100; // Is this some symbolic reminder or why the * 100? Fee is also a local copy, so this does nothing useful.
        }
    }
    Code:
    int Library::number_of_checked_out_books()
    {
        vector<Book> number_of_books; // don't push books into a vector just to count them, use and int!
        for (size_t i = 0; i < books.size(); i++)
        {
            if (!books[i].checked_in())
            {
                number_of_books.push_back(books[i]);
            }
        }
        return number_of_books.size();
    }
    Code:
    bool is_fee_owed(const Patron& patron)
    {
        if (patron.fee() > 0)
        {
            error("error: a fee is owed"); // I wouldn't throw here, it's excessive for what is not a program error
            return true;
        }
        return false;
    }
    /* Also, shouldn't this be a method of the Library class? I thought the library keeps track of Patrons and the fees owed. */
    This is by no means a thorough analysis. You'll have to ensure your program "works" by running and testing it.

  6. #276
    Registered User
    Join Date
    Mar 2015
    Posts
    184
    Edit2: So when I create a Patron object in main(), how should I put in the fee value? Do I make a const int variable for the fee and initialize it to the return value of the fee() function (getter function for library_fee)?
    No, just leave it out, like you were told. You don't need to mention all the members in a constructor. It makes sense to just call patron(name, UUID) in main. Under the hood you initialize the fee to zero in the initializer list.

    For the is_isbn_same() function, I need to pass in a vector since it's not going to be a Library class member, but the Book vector is private. So how I should I do this?
    That would be a problem if 1) you call the function from main. And 2) you want to pass it the books member.
    Only point 2 is true. So ask yourself where does the function get called from, if not from main? So passing a private member is no problem if the one doing the passing is a method of the class.

  7. #277
    Registered User
    Join Date
    Mar 2015
    Posts
    384
    @Jig: I can't leave it out. The compiler gives me a warning about the member being required in the initialization list in the constructor when I compile it without the fee member in the initialization list for the constructor.

    So this is what I did for that:
    Code:
    Patron(const string& user_name, const string& library_card_number, const int library_fee)
    Code:
        : user_name{user_name}, library_card_number{library_card_number}, library_fee{0} {}
    @Adrian: I tried to fix it, but I've got some more questions about what I have now. Like this function:
    Code:
    void Library::check_book_in(Book& book, const Date due_date, Patron& patron)
    {
        int fee = 10 * 100;
        bool finished_reading_book = true;
        if (finished_reading_book)
        {
            Date return_date{2015, Month::apr, 24};
            if (due_date.day() == 24 && due_date.month() == Month::apr)
            {
                return_date.set_month(Month::apr);
                return_date.set_day(24);
            }
            else if (due_date.day() == 25 && due_date.month() == Month::apr)
            {
                return_date.set_month(Month::apr);
                return_date.set_day(25);
            }
            else if (due_date.day() == 26 && due_date.month() == Month::apr)
            {
                return_date.set_month(Month::apr);
                return_date.set_day(26);
            }
            if (return_date.day() > due_date.day() || static_cast<int>(return_date.month()) > static_cast<int>(due_date.month()))
            {
                patron.set_fee(fee);
                error("error: book is overdue, please pay fee of $10.");
            }
            book.set_check(true);
        }
        else
        {
            extend_due_date(due_date);
        }
        relieve_patron_debt(patron);
    }
    The Boolean finished_reading_book is always true in this case, yes? So what should I do with this to make sure it works the way I want it to? Any suggestions?

    I also have this message currently:
    Code:
    C:\Users\Osman\programming\stroustrup_programming_using_c++\book\book.cpp||In member function 'void Library::relieve_patron_debt(Patron&)':|
    Code:
    C:\Users\Osman\programming\stroustrup_programming_using_c++\book\book.cpp|425|warning: variable 'fee_paid' set but not used [-Wunused-but-set-variable]|
    ||=== Build finished: 0 error(s), 1 warning(s) (0 minute(s), 1 second(s)) ===|


    Referring to this function:
    Code:
    void Library::relieve_patron_debt(Patron& patron)
    {
        bool fee_paid;
        if (patron.fee() > 0)
        {
            fee_paid = false;
        }
        else
        {
            fee_paid = true;
        }
    }


    Should I make this function return a Boolean value, and then change the way I use it in check_book_in() to reflect that, or should I leave it as is and ignore the warning (most likely a bad idea, huh?)?

    For reference, here is the full code (I have yet to fully test it out - I'll do that after I've got the current set of problems I'm looking at sorted out).
    Code:
    // Osman Zakir
    // 7/12/2015
    // Programming: Principles and Practice Using C++ 2nd Edition by Bjarne Stroustrup
    // Chapter 9 Exercises 5 - 9
    // Program implements a Book class, a Library class, a Patron class, a Genre class,
    // and a Transaction, and constructs objects for the class to print out data for the books and patrons in a library
    #include "../custom_std_lib_facilities.h"
    #include <algorithm>
    #include <vector>
    
    
    using namespace std;
    
    
    enum class Genre
    {
        fiction, nonfiction, periodical, biography, children
    };
    
    
    class Book
    {
    private:
        string isbn_number;
        string title;
        string author;
        int copyright_date;
        Genre book_genre;
        bool book_checked_in;
    public:
        Book(const string& isbn_number, const string& title, const string& author, const int copyright_date, const Genre book_genre, const bool book_checked_in);
        const string& isbn() const { return isbn_number; }
        const string& book_title() const { return title; }
        const string& author_name() const { return author; }
        const int copyright() const { return copyright_date; }
        const Genre genre_of_book() const { return book_genre; }
        const bool checked_in() const { return book_checked_in; }
        void set_check(bool check) { book_checked_in = check; }
    };
    
    
    enum class Month
    {
        jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
    };
    
    
    class Date
    {
    public:
        Date(const int y, const Month m, const int d);
        int year() const { return y; }
        Month month() const { return m; }
        int day() const { return d; }
        void add_day(int n);
        void add_month(int n);
        void set_day(int value);
        void set_month(Month value);
        void set_year(int value);
    private:
        int y;
        Month m;
        int d;
    };
    
    
    class Patron
    {
    private:
        string user_name;
        string library_card_number;
        int library_fee;
    public:
        const string& username() const { return user_name; }
        const string& card_number() const { return library_card_number; }
        int fee() const { return library_fee; }
        void set_fee(int value) { library_fee = value; }
        Patron(const string& user_name, const string& library_card_number, const int library_fee)
        : user_name{user_name}, library_card_number{library_card_number}, library_fee{0} {}
    };
    
    
    class Library
    {
    private:
        struct Transaction
        {
        string book_isbn;
        string patron_card_number;
        Date date;
        Transaction(const string& book_isbn, const string& patron_card_number, const Date& date)
        : book_isbn{book_isbn}, patron_card_number{patron_card_number}, date{date} {}
        };
    
    
        vector<Book> books{};
        vector<Patron> patrons{};
        vector<Transaction> transactions{};
        bool is_book_in_library(const Book& book_title) const;
        bool is_patron_in_library(const Patron& patron_name) const;
    public:
        void add_book(const Book& book);
        void add_patron(const Patron& patron);
        void check_book_in(Book& book, const Date due_date, Patron& patron);
        void check_book_out(Book& book, const Date transaction_date, const Patron& patron);
        void extend_due_date(Date due_date);
        void relieve_patron_debt(Patron& patron);
        bool is_fee_owed(const Patron& patron);
        int number_of_books();
        int number_of_checked_out_books();
    };
    
    
    void printBookData(const Book& book);
    
    
    void printPatronData(const Patron& patron);
    
    
    bool operator==(const Book& book1, const Book& book2);
    
    
    bool operator!=(const Book& book1, const Book& book2);
    
    
    ostream& operator<<(ostream& os, const Date& dd);
    
    
    int main()
    {
        try
        {
            cout<<"Creating books, patrons and library...\n";
            Book book1{"0-15-204560-0", "Heir Apparent", "Vivian Vande Velde", 2002, Genre::fiction, book1.checked_in()};
            Book book2{"0-375-82668-8", "Eragon", "Christopher Paolini", 2003, Genre::fiction, book2.checked_in()};
            Book book3{"0-590-55356-9", "Sandry's Book", "Tamora Pierce", 1997, Genre::fiction, book3.checked_in()};
    
    
            Patron patron1{"Mike", "3-2504-58140-9664", patron1.fee()};
            Patron patron2{"Osman", "4-2512-21408-5521", patron2.fee()};
            Patron patron3{"Draco", "2-1262-52741-6185", patron3.fee()};
    
    
            Library library;
            library.add_book(book1);
            library.add_book(book2);
            library.add_book(book3);
    
    
            book1.set_check(true);
            book2.set_check(true);
            book3.set_check(true);
    
    
            library.add_patron(patron1);
            library.add_patron(patron2);
            library.add_patron(patron3);
    
    
            Date date1{2015, Month::mar, 25};
            Date date2{2015, Month::mar, 26};
            Date date3{2015, Month::mar, 24};
    
    
            if (book1.checked_in() || !library.is_fee_owed(patron2))
            {
                library.check_book_out(book1, date1, patron2);
            }
            if (book2.checked_in() || !library.is_fee_owed(patron1))
            {
                library.check_book_out(book2, date2, patron1);
            }
            if (book3.checked_in() || !library.is_fee_owed(patron3))
            {
                library.check_book_out(book3, date3, patron3);
            }
            else if (!book1.checked_in())
            {
                error("error: book has already been checked out.");
            }
            else if (!book2.checked_in())
            {
                error("error: book has already been checked out.");
            }
            else if (!book3.checked_in())
            {
                error("error: book has already been checked out.");
            }
    
    
            cout<<"Checking in books...\n";
    
    
            Date due_date1{2015, Month::apr, 24};
            Date due_date2{2015, Month::apr, 25};
            Date due_date3{2015, Month::apr, 26};
    
    
            library.check_book_in(book1, due_date1, patron2);
            library.check_book_in(book2, due_date2, patron1);
            library.check_book_in(book3, due_date3, patron3);
    
    
            cout<<"\n\nprinting info...\n";
            cout << "The information for " << book1.book_title() << " is:\n";
            printBookData(book1);
            cout << "\n";
            cout << "The information for " << book2.book_title() << " is:\n";
            printBookData(book2);
            cout << "\n";
            cout << "The information for " << book3.book_title() << " is:\n";
            printBookData(book3);
            cout << "\nInformation on Library Patrons:\n";
            printPatronData(patron1);
            cout << "\n";
            printPatronData(patron2);
            cout << "\n";
            printPatronData(patron3);
            cout << "\n";
    
    
            keep_window_open();
        }
        catch(runtime_error& r)
        {
            cout << r.what() << "\n";
            keep_window_open();
            return 1;
        }
        catch(...)
        {
            cout << "Whoops! Unknown exception! Please try again later.\n";
            keep_window_open();
            return 2;
        }
    }
    
    
    Book::Book(const string& isbn_number, const string& title, const string& author, const int copyright_date, const Genre book_genre, const bool book_checked_in)
    :isbn_number{isbn_number}, title{title}, author{author}, copyright_date{copyright_date}, book_genre{book_genre}, book_checked_in{true}
    {
        constexpr int MaxDate = 2015;
        if (copyright_date <= 0 || copyright_date > MaxDate)
        {
            error("invalid copyright date");
        }
        stringstream ss(isbn_number);
        char valid = '-';
        char invalid = ' ';
        for (int i = 0; i < 3; i++)
        {
            int integer = -1;
            char character = invalid;
            ss >> integer >> character;
            if (integer < 0 || character != valid)
            {
                error("Invalid ISBN");
            }
        }
        string final;
        ss >> final;
        if (final.size() != 1)
        {
            error("Invalid ISBN");
        }
        else if(!isdigit(final[0]) && !isalpha(final[0]))
        {
            error("Invalid ISBN");
        }
    }
    
    
    Date::Date(const int y, const Month m, const int d)
    : y{y}, m{m}, d{d}
    {
        if (m == Month::feb && d > 28)
        {
            error("Error: Invalid date; unless this is/was a leap-year, February should only have 28 days. Try again later.");
        }
        if ((m == Month::jan || m == Month::mar || m == Month::may || m == Month::jul || m == Month::aug || m == Month::oct || m == Month::dec) && d > 31)
        {
            error("Error: Invalid date; this month only has 31 days. Try again later.");
        }
        if ((m == Month::apr || m == Month::jun || m == Month::sep || m == Month::nov) && d > 30)
        {
            error("Error: Invalid date; this month only has 30 days. Try again later.");
        }
        if (m < Month::jan || m > Month::dec || d <= 0)
        {
            error("Error: Invalid month and/or day! Try again later.");
        }
        if (y <= 0 || y > 2200)
        {
            error("Error: Invalid year! Please try again later.");
        }
    }
    
    
    void Date::add_day(int n)
    {
        d += n;
        if (m == Month::feb && d > 28)
        {
            error("Error: Invalid date; unless this is/was a leap-year, February should only have 28 days. Try again later.");
        }
        if ((m == Month::jan || m == Month::mar || m == Month::may || m == Month::jul || m == Month::aug || m == Month::oct || m == Month::dec) && d > 31)
        {
            error("Error: Invalid date; this month only has 31 days. Try again later.");
        }
        if ((m == Month::apr || m == Month::jun || m == Month::sep || m == Month::nov) && d > 30)
        {
            error("Error: Invalid date; this month only has 30 days. Try again later.");
        }
        if (d <= 0)
        {
            error("Error: Invalid day! Try again later.");
        }
    }
    
    
    void Date::add_month(int n)
    {
        m = static_cast<Month>(static_cast<int>(m) + n);
        if (m < Month::jan || m > Month::dec)
        {
            error("Error: Invalid month and/or day! Try again later.");
        }
    }
    
    
    void Date::set_day(int value)
    {
        d = value;
        if (m == Month::feb && d > 28)
        {
            error("Error: Invalid date; unless this is/was a leap-year, February should only have 28 days. Try again later.");
        }
        if ((m == Month::jan || m == Month::mar || m == Month::may || m == Month::jul || m == Month::aug || m == Month::oct || m == Month::dec) && d > 31)
        {
            error("Error: Invalid date; this month only has 31 days. Try again later.");
        }
        if ((m == Month::apr || m == Month::jun || m == Month::sep || m == Month::nov) && d > 30)
        {
            error("Error: Invalid date; this month only has 30 days. Try again later.");
        }
        if (d <= 0)
        {
            error("Error: Invalid day! Try again later.");
        }
    }
    
    
    void Date::set_month(Month value)
    {
        m = value;
        if (m < Month::jan || m > Month::dec)
        {
            error("Error: Invalid month and/or day! Try again later.");
        }
    }
    
    
    void Date::set_year(int value)
    {
        y = value;
        if (y <= 0 || y > 2200)
        {
            error("Error: Invalid year! Please try again later.");
        }
    }
    
    
    void Library::check_book_in(Book& book, const Date due_date, Patron& patron)
    {
        int fee = 10 * 100;
        bool finished_reading_book = true;
        if (finished_reading_book)
        {
            Date return_date{2015, Month::apr, 24};
            if (due_date.day() == 24 && due_date.month() == Month::apr)
            {
                return_date.set_month(Month::apr);
                return_date.set_day(24);
            }
            else if (due_date.day() == 25 && due_date.month() == Month::apr)
            {
                return_date.set_month(Month::apr);
                return_date.set_day(25);
            }
            else if (due_date.day() == 26 && due_date.month() == Month::apr)
            {
                return_date.set_month(Month::apr);
                return_date.set_day(26);
            }
            if (return_date.day() > due_date.day() || static_cast<int>(return_date.month()) > static_cast<int>(due_date.month()))
            {
                patron.set_fee(fee);
                error("error: book is overdue, please pay fee of $10.");
            }
            book.set_check(true);
        }
        else
        {
            extend_due_date(due_date);
        }
        relieve_patron_debt(patron);
    }
    
    
    void Library::check_book_out(Book& book, const Date transaction_date, const Patron& patron)
    {
        if (is_fee_owed(patron))
        {
            error("error: fee is owed; relieve fee first before borrowing another book.");
        }
        else
        {
            if (is_book_in_library(book) && is_patron_in_library(patron))
            {
                Date due_date{2015, Month::apr, 24};
                if (transaction_date.day() == 24)
                {
                    due_date.set_day(24);
                }
                else if (transaction_date.day() == 25)
                {
                    due_date.set_day(25);
                }
                else if (transaction_date.day() == 26)
                {
                    due_date.set_day(26);
                }
                Transaction transaction{book.isbn(), patron.card_number(), transaction_date};
                transactions.push_back(transaction);
                if (is_book_in_library(book))
                {
                    book.set_check(false);
                }
            }
            else
            {
                error("error: this book and patron aren't in the library");
            }
        }
    }
    
    
    void Library::extend_due_date(Date due_date)
    {
        int extension_value = 1;
        due_date.add_month(extension_value);
        if (due_date.month() > Month::dec || due_date.month() < Month::jan)
        {
            error("error: invalid month value.");
        }
    }
    
    
    void Library::relieve_patron_debt(Patron& patron)
    {
        bool fee_paid;
        if (patron.fee() > 0)
        {
            fee_paid = false;
        }
        else
        {
            fee_paid = true;
        }
    }
    
    
    int Library::number_of_checked_out_books()
    {
        int number_of_books;
        for (size_t i = 0; i < books.size(); i++)
        {
            if (!books[i].checked_in())
            {
                number_of_books = i;
            }
        }
        return number_of_books;
    }
    
    
    ostream& operator<<(ostream& os, const Date& dd)
    {
        return os << dd.year() << '-' << static_cast<int>(dd.month()) << '-' << dd.day();
    }
    
    
    void printBookData(const Book& book)
    {
        cout << "ISBN number: " << book.isbn() << "\n"
            << "Title: " << book.book_title() << "\n"
            << "Author: " << book.author_name() << "\n";
        switch(book.genre_of_book())
        {
        case Genre::biography:
            cout << "Genre: Biography\n";
            break;
        case Genre::children:
            cout << "Genre: Children\n";
            break;
        case Genre::fiction:
            cout << "Genre: Fiction\n";
            break;
        case Genre::nonfiction:
            cout << "Genre: Nonfiction\n";
            break;
        case Genre::periodical:
            cout << "Genre: Periodical\n";
            break;
        default:
            cout << "No Genre?\n";
            break;
        }
    }
    
    
    bool operator==(const Book& book1, const Book& book2)
    {
        return book1.isbn() == book2.isbn();
    }
    
    
    bool operator!=(const Book& book1, const Book& book2)
    {
        return !(book1.isbn() == book2.isbn());
    }
    
    
    void printPatronData(const Patron& patron)
    {
        cout << "Patron's name: " << patron.username() << "\n"
            << "Library card no: " << patron.card_number() << "\n"
            << "Fee owed: $" << patron.fee() << "\n";
    }
    
    
    void Library::add_book(const Book& book)
    {
        for (size_t i = 0; i < books.size(); i++)
        {
            if (is_book_in_library(book))
            {
                error("error: Book is already in library.");
            }
        }
        books.push_back(book);
    }
    
    
    void Library::add_patron(const Patron& patron)
    {
        patrons.push_back(patron);
    }
    
    
    int Library::number_of_books()
    {
        return books.size();
    }
    
    
    bool Library::is_book_in_library(const Book& book) const
    {
        for (size_t i = 0; i < books.size(); i++)
        {
            if (book == books[i])
            {
                return true;
            }
        }
        return false;
    }
    
    
    bool Library::is_patron_in_library(const Patron& patron) const
    {
        for (size_t i = 0; i < patrons.size(); i++)
        {
            if (patron.username() == patrons[i].username())
            {
                return true;
            }
        }
        return false;
    }
    
    
    bool Library::is_fee_owed(const Patron& patron)
    {
        if (patron.fee() > 0)
        {
            return true;
        }
        return false;
    }
    And the warning message:
    Code:
    C:\Users\Osman\programming\stroustrup_programming_using_c++\book\book.cpp||In member function 'void Library::relieve_patron_debt(Patron&)':|
    Code:
    C:\Users\Osman\programming\stroustrup_programming_using_c++\book\book.cpp|425|warning: variable 'fee_paid' set but not used [-Wunused-but-set-variable]|
    ||=== Build finished: 0 error(s), 1 warning(s) (0 minute(s), 1 second(s)) ===|
    Edit: I guess the reason I'm not getting any more errors or warnings than this is because my compiler version is a bit old. Stahta said he used MinGW GCC 5.1. I'm using TDM GCC 4.9.5. So I guess I should a newer version.

    Edit2:
    @Adrian: When I try to make the Book class getter functions only return by reference instead of const reference, I get an error saying I can't make a function return by reference if it's not const reference.
    Last edited by Osman Zakir; 08-03-2015 at 10:28 AM.

  8. #278
    Registered User
    Join Date
    Mar 2015
    Posts
    184
    I can't leave it out. The compiler gives me a warning about the member being required in the initialization list in the constructor when I compile it without the fee member in the initialization list for the constructor.
    You are not getting it. Did you read the chapter on constructors? I didn't say anything about changing the initializer list, just change the constructor syntax, perhaps you don't know the difference, but all you had to do was copy paste Jim's code, you even quoted the snippet! T.T T.T

    When I try to make the Book class getter functions only return by reference instead of const reference, I get an error saying I can't make a function return by reference if it's not const reference.
    Why do you even want to return by reference or const? Notice that your getter is a const function, it promises not to change any member values. What could happen if you returned a non-const reference to a member? The reference is an alias for the member variable, so it could be changed thus changing the corresponding member. This is why a const function does not approve of returning a non-const reference.
    Last edited by jiggunjer; 08-03-2015 at 11:12 AM.

  9. #279
    Registered User
    Join Date
    Mar 2015
    Posts
    384
    Sorry about that. I've got it now. Took me a while to see what you guys meant.

    I installed TDM GNU GCC 5.1 and recompiled it, but even with -std=c++14, -pedantic, -Wall, and -Effc++ flags turned on I'm still only getting that one warning about a set-but-unused variable (Boolean fee_paid) in relieve_patron_dept().

    I need help with those functions, still.

    First is this one.
    Code:
    void Library::relieve_patron_debt(Patron& patron)
    {
        bool fee_paid;
        if (patron.fee() > 0)
        {
            fee_paid = false;
        }
        else
        {
            fee_paid = true;
        }
    }
    For this one, do I change the return type to bool and return the fee_paid variable, and then also change the way I'm using the function in check_book_in(), or do I just leave it as it is? The warning about an unused variable is referring to this.

    The other one is this.
    Code:
    void Library::check_book_in(Book& book, const Date due_date, Patron& patron)
    {
        int fee = 10 * 100;
        bool finished_reading_book = true;
        if (finished_reading_book)
        {
            Date return_date{2015, Month::apr, 24};
            if (due_date.day() == 24 && due_date.month() == Month::apr)
            {
                return_date.set_month(Month::apr);
                return_date.set_day(24);
            }
            else if (due_date.day() == 25 && due_date.month() == Month::apr)
            {
                return_date.set_month(Month::apr);
                return_date.set_day(25);
            }
            else if (due_date.day() == 26 && due_date.month() == Month::apr)
            {
                return_date.set_month(Month::apr);
                return_date.set_day(26);
            }
            if (return_date.day() > due_date.day() || static_cast<int>(return_date.month()) > static_cast<int>(due_date.month()))
            {
                patron.set_fee(fee);
                error("error: book is overdue, please pay fee of $10.");
            }
            book.set_check(true);
        }
        else
        {
            extend_due_date(due_date);
        }
        relieve_patron_debt(patron);
    }
    In this function the Boolean variable finished_reading_book is always true, yes? So how do I fix this?

    And yeah, the patron and book searcher functions also need to be reviewed, as well as the function check_book_out() (the check-in function, too, for more than just the Boolean problem).

    @Adrian: I did try to recompile the code after changing the Book member getter functions to just return a reference rather than a const reference, but it gave me an error message saying I can't make a reference to a function like that; it was silenced by turning them back into const reference functions.
    Last edited by Osman Zakir; 08-03-2015 at 11:23 AM.

  10. #280
    Guest
    Guest
    I did try to recompile the code after changing the Book member getter functions to just return a reference rather than a const reference (...)
    Sorry, I might have worded that badly. What I meant is that if a function returns by value, you can ditch the const qualifier to that return value, e.g. const int becomes plain int. The reason is that your return value is decoupled from your member variables anyway, so there's no reason to attempt to restrict its usage outside of your class. Returned references should remain const; they point to the actual members in your objects!

    Code:
    void Library::relieve_patron_debt(Patron& patron)
    {
        bool fee_paid;
        if (patron.fee() > 0)
        {
            fee_paid = false;
        }
        else
        {
            fee_paid = true;
        }
    }
    For this one, do I change the return type to bool and return the fee_paid variable, and then also change the way I'm using the function in check_book_in(), or do I just leave it as it is? The warning about an unused variable is referring to this.
    This function sounds like an action to me (relieve debt), no a question (is there debt?). Can you tell me in words what exactly it is supposed to do?

    Code:
    void Library::check_book_in(...)
    The Boolean finished_reading_book is always true in this case, yes? So what should I do with this to make sure it works the way I want it to? Any suggestions?
    Where does finished_reading_book originate? Which object contains this information that you need?

  11. #281
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    I am guessing me using "-Weffc++" is NOT the same as "-Effc++" that you used.
    I also had "-Wextra" set.

    (Removing "-Wextra" resulted in no warning for a highly modified version of your code)


    I used "-std=c++11" instead of "-std=c++14" no idea if this changes the warnings reported; I will try it and see.
    (Changing to -std=c++14 made no difference)

    Tim S.
    Last edited by stahta01; 08-03-2015 at 02:52 PM.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  12. #282
    Registered User
    Join Date
    Mar 2015
    Posts
    384
    @Adrian: So you mean I should something like this?
    Code:
    const int fn() { return value; }
    Instead of this?
    Code:
    const int fn() const { return value; }
    And the ones that return a string by reference have to have a return value of const reference, but don't require the trailing const after the parameter list, as well? Like this?
    Code:
    const string fn() { return value; }
    Instead of like this?
    Code:
    const string fn() const { return value; }
    Or is it the other way around?

    The function relieve_patron_dept() is supposed to be an action, yes. And it it's supposed to check the patron's fee and see if it's greater than $0. If it is, it sets fee_paid to false since it'd mean that the dept isn't relieved, but otherwise it sets fee_paid to true. Should I do it differently? I have the sinking suspicion that I have to have the patron pay the fee in this function somehow (do I?).

    And the variable finished_reading_book originates in the check-in function itself. Do you mean I should declare it in the Library or Book class and use it in main() to determine whether a patron is done reading a particular book? Initialize it to false in the class scope itself, then find a place to change it to true to indicate that a patron has finished reading it. Where should I use it, then? In main() when I call check_book_in()? And if a book hasn't been designated as "finished_reading," its value would be set to false and if I call check_book_in() on it, the if-condition would evaluate to false and the rest of the code won't execute.[/scenario]

    @Stahta: Ah, yeah, I forgot to include the -W part. But you should know by now that there's no "Effc++" separate from "-Weffc++". I messed up the name there, so that's actually the same flag. Sorry about that. And -std=c++14 is more recent than -std=c++11, although since C++17 or so is already out, both of those might be outdated already (or are they not?).

    By the way, is this function written right?
    Code:
    int Library::number_of_checked_out_books()
    {
        int number_of_books;
        for (size_t i = 0; i < books.size(); i++)
        {
            if (!books[i].checked_in())
            {
                number_of_books = i;
            }
        }
        return number_of_books;
    }
    And Adrian, you said before you're ignoring check_book_in() and check_book_out(), so I want to ask if you're ready to look at both as a whole now (in the case of check_book_in(), that would be "look at more than just the matter of 'finished_reading_book'")? Thanks.

  13. #283
    Guest
    Guest
    Quote Originally Posted by Osman Zakir View Post
    @Adrian: So you mean I should something like this?
    Code:
    const int fn() { return value; }
    Instead of this?
    Code:
    const int fn() const { return value; }
    Exactly. Outside of your function/class, the program can do whatever it wants with value, there no reason to assume that you need to "protect" it.

    And the ones that return a string by reference have to have a return value of const reference, but don't require the trailing const after the parameter list, as well? Like this?
    No, they stay unchanged (they way they were until now), my suggestion only refers to functions returning by value. It would be helpful if you refreshed your knowledge of functions arguments, references and scope which all play into this.

    The function relieve_patron_dept() is supposed to be an action, yes. And it it's supposed to check the patron's fee and see if it's greater than $0. If it is, it sets fee_paid to false since it'd mean that the dept isn't relieved, but otherwise it sets fee_paid to true. Should I do it differently? I have the sinking suspicion that I have to have the patron pay the fee in this function somehow (do I?).
    Who owns fee_paid? I do not see this variable in any of your classes. If you want to modify a Patron object, why is this function part of the Library class? It does not appear to interact with the library at all.

    And the variable finished_reading_book originates in the check-in function itself. Do you mean I should declare it in the Library or Book class and use it in main() to determine whether a patron is done reading a particular book?
    Well, you've got to store this behaviour somewhere. If you produce it in the function, then it cannot change or react; removing it would give you the same result in that case.

    Initialize it to false in the class scope itself, then find a place to change it to true to indicate that a patron has finished reading it. Where should I use it, then? In main() when I call check_book_in()? And if a book hasn't been designated as "finished_reading," its value would be set to false and if I call check_book_in() on it, the if-condition would evaluate to false and the rest of the code won't execute.
    Seems like the Patron class would be a sensible choice. However I think you're still misunderstanding the purpose of object oriented design. The Library class is supposed to track all books, patrons and transactions. The modification of objects directly inside main() is clumsy and confusing. Since you abandoned the idea of having the library track behaviour independent of the objects it holds, the middle-way would be to at least modify the Patron objects inside the library, instead of some lone object in main().

    By the way, is this function written right?
    Code:
    int Library::number_of_checked_out_books()
    {
        int number_of_books;
        for (size_t i = 0; i < books.size(); i++)
        {
            if (!books[i].checked_in())
            {
                number_of_books = i;
            }
        }
        return number_of_books;
    }
    Dude, let's say books.size() is 5. What is the value of i during the loop's execution? That's what you're overwriting number_of_books with in every iteration. Think!

    And Adrian, you said before you're ignoring check_book_in() and check_book_out(), so I want to ask if you're ready to look at both as a whole now (in the case of check_book_in(), that would be "look at more than just the matter of 'finished_reading_book'")? Thanks.
    Ok, let's imagine finished_reading_book was retrieved properly. Unless I'm not seeing it right, it seems that you're making an effort of setting return_date equal to due_date and then comparing the two. That makes no sense.

    What really stands out though is that the whole function is hardcoded, i.e. it deals with April 24, 2015 and the following days. For me the appeal of programs is automation, i.e. their appearance of being flexible, "smart" even. A program only works on a single date, with a specific number of objects, is the antithesis of that. If you need to rewrite your functions when the amount of objects or their properties change, something is wrong in your design.

  14. #284
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Exactly. Outside of your function/class, the program can do whatever it wants with value, there no reason to assume that you need to "protect" it.
    [Edit]
    I fixed the comment being associated with the wrong example.
    [/Edit]

    O_o

    No. You got the idea right, but I think the original poster got the wrong idea.

    Code:
    const int fn() const { return value; } // Okay, but a bit silly and pointlessly restrictive.
    The return value, as explained, doesn't need to be constant.

    The method should be constant because you aren't modifying any members, but you should drop the `const` on the return.

    Code:
    const int fn() { return value; } // Pointlessly restrictive without the benefit of being a constant method.
    Code:
    int fn() const { return value; } // Right.
    Soma
    Last edited by phantomotap; 08-03-2015 at 09:57 PM. Reason: ... silly ...
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  15. #285
    Guest
    Guest
    Yeah thanks for catching that phantomotap, I didn't pay attention to what I quoted there.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Book Drill Question Help Needed
    By Osman Zakir in forum C++ Programming
    Replies: 1
    Last Post: 04-16-2015, 09:33 PM
  2. Book recomendation needed
    By baxy in forum Programming Book and Product Reviews
    Replies: 1
    Last Post: 09-22-2013, 06:02 PM
  3. I need help with this program its from a C++ book
    By dark21 in forum C++ Programming
    Replies: 7
    Last Post: 03-27-2009, 03:30 AM
  4. Easy, simple programming book needed - HELP!
    By 3boyzmom in forum C Programming
    Replies: 1
    Last Post: 05-05-2008, 09:31 AM
  5. Address Book program
    By sundeeptuteja in forum C++ Programming
    Replies: 0
    Last Post: 07-28-2002, 02:08 AM