>
virtual std::ostream& print( std::ostream& stm ) const = 0 ;
> could you explain this a little. This is the print function right?
> I have only seen the ostream& used with the << >> overloads.
We can have several overloaded stream insertion operators which are themselves overloaded on the type of object being sent to the stream, one for each Shape. For example,
1 2 3 4 5
|
std::ostream& operator<< ( std::ostream& stm, const circle& c ) ;
std::ostream& operator<< ( std::ostream& stm, const quadrilateral& q ) ;
std::ostream& operator<< ( std::ostream& stm, const cone& c ) ;
std::ostream& operator<< ( std::ostream& stm, const tetrahedron& t ) ;
// etc
|
This would be polymorphic with respect to the
std::ostream
(well, actually polymorphic wrt the
std::streambuf
associated with the stream, but we'll ignore that nicety for the moment). So if the stream is one that sends output to stdout, the Shape would be written to stdout. In other cases, it may be written to a file (
std::ofstream
), memory(
std::ostringstream
), or a window in a GUI (a stream with a suitable user-defined streambuf).
But it is not polymorphic wrt the Shape itself - if we get a reference to the shape, we need to find out if it is a tetrahedron or not (via a dynamic_cast), and if it is call
std::ostream& operator<< ( std::ostream& stm, const tetrahedron& t ) ;
If we try to make it polymorphic on the Shape this way:
virtual void print() const = 0 ;
with each derived class implementing print in its own way, it would not be polymorphic wrt the stream.
Like much of polymorphism in real life,
print()
is a multimethod - it is polymorphic on the combination of objects involved. What information is to be printed is determined by the Shape, and how is it to be printed is determined by the stream. And we are programming in a language that has no direct support for multimethods (well, object oriented multimethods - generic multimethods are well supported). So we simulate multiple-polymorphism using multiple dispatch:
virtual std::ostream& print( std::ostream& stm ) const = 0 ;
first dispatch to the right implementation based on the run-time type of the Shape on which print() is called, and within that implementation of print() dispatch to the insertion operations based on the run-time type of the std::streambuf.
> Also what is the reason for saying override at the end of the other functions in the derived classes.
Other than the obvious advantage of the code being self-documenting, it also protects us against silly programming mistakes. For example if we forget a
const
qualifier while overriding
print()
, the compiler will know that we have hidden and not overridden a base class virtual function and will emit an error diagnostic. Other than that it makes no other difference - the virtual function is overridden even if you omit it.
The
override
keyword was introduced in C++11, so your compiler may not suppor it. In this case, you can safely remove the
override
specifier.
Or alternatively, do something like this in a common header:
1 2 3
|
#if __cplusplus < 201103L // not C++11
#define override
#endif
|