Statements in a derived class override, but still use the parent class

In particular, I would like to be able to use ostream operator <<in two derived classes from the base class.

The program I am creating must print product details for different "products" in a "virtual store." Among the products are two different types of books. Each of these books should contain its own:

ID number
Author
NumberOfPages
Year

In addition, the type ChildrensBookmust contain a minimum age, and TextBookmust contain a grade.

I defined a class Bookand received classes from it ChildrensBookand TextBook. My question is to use ostream operator <<for printing information.

Can I define a common <function in the Book class that will print all the information common to both derived classes and then refer to it when overriding <in derived classes?

For instance,

//The parent class

ostream& operator<<(ostream& bookOutput, const Book& printBook) {
    return bookOutput << printBook.ID << "Name " << printBook.name << "year:" << printBook.year";
}

And then in the derived class somehow:

//The derived classes
ostream& operator<<(ostream& TextBookOutput, const TextBook& printTextBook) {
    return TextBookOutput << "TextBook: " 
           << "[Here is where I want to print out all the details of the book that are members of the base class]" << "Grade:" << printTextBook.grade;
}

So, I think my question can be summarized as follows: can I call the parent statement from the child statement, and if so, what syntax do I use?

Another idea that arose for me was to write a function for a child element that uses the parent print statement, and then call that function from the child print statement. This would mean that I did not try to call the operator when overriding it, but still calls for using the parent operator and redefining the child operator separately.

+3
3

.

Book s, . , , .

ostream& operator<<(ostream& TextBookOutput, const TextBook& printTextBook) {
    return TextBookOutput << "TextBook: " << static_cast<const Book&>(printTextBook) << "Grade:" << printTextBook.grade;
}
+4
return TextBookOutput << static_cast<Book const &>(printTextBook) << ...
0

, downcasting , . , : , , - , ( ).

, , :

class Book { ... };
class TextBook : public Book { ... };
ostream& operator<<(ostream& os, const Book& book) {
    return os << "Book: " << book.name << "\n";
}
ostream& operator<<(ostream& os, const TextBook& book) {
    return os << "TextBook: " << book.name << "\n";
}
, , :

Book book;
TextBook textBook;
cout << book << "\n";     // prints out: Book: XYZ
cout << textBook << "\n"; // prints out: TextBook: XYZ 
, ().

:

Book * textBook = new TextBook();
cout << *textBook << "\n";    // prints out: Book: XYZ !

This is due to the fact that the compiler cannot know what a higher type is; it can be a Book, TextBook or ChildrensBook. This can only be determined at runtime (dynamically) using virtual functions, etc.

Therefore, if you think about using dynamic polymorphism, I would prefer this approach:


class Book {
  public:
  virtual ostream& print(ostream& os) const { return os << "Book: XYZ"; }
  // Don't forget virtual destructor.
  virtual ~Book() {}
};
class TextBook : public Book {
  public:
  virtual ostream& print(ostream& os) const
  {
    // Here, you can also call the "print" method of the parent class
    // like this: os << Book::print(os);
    // or just invent your own like this:
    return os << "TextBook: XYZ";
  }
};
ostream& operator<<(ostream& os, const Book& book) {
  // Will correctly decide during runtime whether
  // to use Book::print or TextBook::print.
  return book.print(os);
}
0
source

All Articles