Need some help with polymorphism and overloading the extraction operator

I have a basic shape class hierarchy

shape
2dShape 3dShape
square, circle, triangle, cube, sphere

this only for area, volume, and surface area respectively. My problem is this I must use a virtual print member function for this program. The print member
function will be called in the overloaded << operator of the Shape class.
So do i use a pure virtual print function starting at the Shape class until i reach a derived class where i have some info to print, and then keep using the previous print function with the scope resolution operation (2dShape::print)? Then some how tell the overloaded extraction operator to call the print function like it says, but how. I also have main that uses a vector of base class pointers to concrete class objects, which is the whole point to this.

Also i'm confused as to how to use implement a constructor since as far as i can tell the original shape class has no data members to it.
Runon sentences give me a headache, and they make your question very unclear.
Your teacher wants you to do something like this for the shape hierarchy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>

struct base
{
    virtual ~base() noexcept {}
    virtual std::ostream& print( std::ostream& stm ) const = 0 ;
};

std::ostream& operator<< ( std::ostream& stm, const base& b )
{ return b.print(stm) ; } // overloaded << operator

struct derived : base
{
    derived( int d ) : data(d) {} // constructor

    virtual std::ostream& print( std::ostream& stm ) const override
    { return stm << "derived::data==" << data ; }

    int data ;
};

struct more_derived : derived
{
    more_derived( int d, int md ) : derived(d), more_data(md) {} // constructor

    virtual std::ostream& print( std::ostream& stm ) const override
    {
        derived::print(stm) ; // first call the base class print function
        // then print the additional stuff that this class has
        return stm << " + more_derived::more_data== " << more_data ;
    }

    int more_data ;
};

#include <vector>

int main()
{
    std::vector< base* > objects = { new derived(20), new more_derived(10,20),
        new more_derived(30,40), new derived(50), new more_derived(60,70) } ;

    for( base* ptr : objects ) std::cout << *ptr << '\n' ;

    for( base* ptr : objects ) delete ptr ;
}

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. Also what is the reason for saying override at the end of the other functions in the derived classes.
What I'm reading doesn't say anything about that. All and all i think i get the idea. It really doesn't seem like that easy of a concept and the book i'm reading doesn't explain anything about this specifically.
> 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 

Topic archived. No new replies allowed.