Operators in derived class redefining but still using parent class
Specifically, I would like to be able to use the ostream
operator <<
in two derived classes from a base class.
The program I am creating is supposed to print out product details for various "products" in a "virtual store". Among the products are two different kinds of books. Each of these books is supposed to hold their own:
ID number
Author
NumberOfPages
Year
In addition, type ChildrensBook
needs to hold a minimum age, and TextBook
needs to hold a grade.
I defined class Book
and derived from it classes ChildrensBook
and TextBook
. My question is about using the ostream
operator <<
to print out the information.
Can I define a generic << function in the Book class, which will print out all of the information common to both derived classes, and then refer to it in the redefinition of << in the derived classes?
For example,
//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 guess my question can be summed up as: Can I call the parent operator from wi开发者_JAVA技巧thin the child operator, and if so, what syntax do I use?
Another idea that occurred to me is to write a function for the child that uses the parent print operator, and then call that function from within the child's print operator. That would mean that I wasn't trying to call an operator while redefining it, but still calls for using the parent operator and separately redefining the child operator.
Sure.
You have an operator for Book
s, so use it. You can invoke it by giving it a reference to a book, and you can use the power of polymorphism to obtain a reference-to-base.
ostream& operator<<(ostream& TextBookOutput, const TextBook& printTextBook) {
return TextBookOutput << "TextBook: " << static_cast<const Book&>(printTextBook) << "Grade:" << printTextBook.grade;
}
return TextBookOutput << static_cast<Book const &>(printTextBook) << ...
As others pointed out, you should use downcasting to achieve what you are asking for. But I think you should consider a different approach as well: What you are doing right now is mixing static and dynamic polymorphism, this often isn't a good idea (which usually only manifests itself later on).
Here is the problem, consider what you've got already:
Everything will go as expected if you use it like this:
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";
}
That is because the compiler will correctly determine the type of the book during compilation time (statically).
Book book;
TextBook textBook;
cout << book << "\n"; // prints out: Book: XYZ
cout << textBook << "\n"; // prints out: TextBook: XYZ
Now consider this other case:
Book * textBook = new TextBook();
cout << *textBook << "\n"; // prints out: Book: XYZ !
This is because the compiler can't know what higher type it is, it can be Book, TextBook or ChildrensBook. This can only be determined during runtime (dynamically) using virtual functions etc.
So in case you consider utilizing 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);
}
精彩评论