/* Notes about scoring: * * See comments in code for things that was checked for goodness or * correctness. Reading carefully and interpreting the specification * is an important part of the assignment, as producing the correct * output is easily done by only using "cout". * * File separation was not required, but is good, and even better with * a Makefile. * */ #include #include class Written_Text { public: virtual ~Written_Text() {} /* Must be virtual on polymorph class. */ /* Must be public and preferably const. Must not be virtual. */ std::string getAuthor() const { return author_; } std::string getTitle() const { return title_; } /* Must be friend and can not be polymorphic. Must only call the * polymorphic print to have each class responsible of it's own * printing. * * It can not be member of the class due to left hand side of the * operator must be of std::ostream type (but will be of * Written_Text type if this is written as member function). This * is the reason it can not be polymorphic and must be friend to * gain access to theprotected (or private) print function). * * Must not use if-statements, as that "ties" the function to this * specific classes. New classes will then require modifications of * this operator, which is bad. With a polymorphic print new classes * need only define their own print and it works. */ friend std::ostream& operator<<(std::ostream& os, Written_Text const& t) { t.print(os); os << std::endl; return os; } protected: /* May not be public and must take two arguments by specification. * No default constructors (anywhere) shall exist. */ Written_Text(std::string const& author, std::string const& title) : author_(author), title_(title) {} /* Needed by print operator but may not be public by specification. * The ONLY function that need to be polymorphic (virtual). * All member functions that can be are const according to specification. */ virtual void print(std::ostream& os) const { os << title_ << " is written by " << author_; } /* Common for all, should be ONLY in base class and protected. */ std::string author_; std::string title_; // std::string text_; // sensible addition }; class Book : public Written_Text { public: /* Only a book have binding, must be declared only in Book. */ std::string getBinding() const { return binding_; } /* Must call base class constructor and preferably use initiation list. * Must have exactly three parameters, and no default values specified. */ Book(std::string const& author, std::string const& title, std::string const& binding) : Written_Text(author, title), binding_(binding) {} protected: void print(std::ostream& os) const { /* Good to call base-class function to avoid duplicated code. */ Written_Text::print(os); os << " with " << binding_ << " binding."; } private: /* Extra members declared only in it's subclass. */ std::string binding_; }; class Hardback : public Book { public: /* Must have only two parameters. */ Hardback(std::string const& author, std::string const& title) : Book(author, title, "stitched") {} }; class Paperback : public Book { public: Paperback(std::string const& author, std::string const& title) : Book(author, title, "glued") {} }; class Textfile : public Written_Text { public: /* Class type parametesr (anywhere) is preferably const& */ Textfile(std::string const& author, std::string const& title, std::string const& format) : Written_Text(author, title), format_(format) {} std::string getFormat() const { return format_; } private: void print(std::ostream& os) const { Written_Text::print(os); os << " in " << format_ << " format."; } std::string format_; }; class Magazine : public Written_Text { public: Magazine(std::string const& author, std::string const& title) : Written_Text(author, title) {} private: void print(std::ostream& os) const { Written_Text::print(os); os << " as a Journal."; } }; int main() { Written_Text* text[4]; int n = 0; // Some things that SHOULD give compilation error // new Hardback("Novik", "Temeraire", "sewn"); // new Book("Rowling", "Potter"); // new Paperback(); // new Textfile("Meyer"); text[n++] = new Book("Novik", "Temeraire", "sewn"); text[n++] = new Hardback("Rowling", "Potter"); text[n++] = new Paperback("Paolini", "Eragon"); text[n++] = new Magazine("Times company", "NY Times Magazine"); text[n++] = new Textfile("Meyer", "Midnight Sun", "PDF"); for (int i = 0; i < n; ++i) { std::cout << *text[i] << std::endl; } for (int i = 0; i < n; ++i) { const Written_Text* index = text[i]; std::cout << index->getTitle() << ", " << index->getAuthor(); const Book* b = dynamic_cast(index); if ( b != 0 ) std::cout << ", " << b->getBinding(); const Textfile* t = dynamic_cast(index); if ( t != 0 ) std::cout << ", " << t->getFormat(); std::cout << std::endl; } for (int i = 0; i < n; ++i) { delete text[i]; text[i] = 0; } return 0; }