Thread: polymorphism and inheritance

  1. #1
    Registered User
    Join Date
    Jan 2009
    Posts
    20

    polymorphism and inheritance

    hi

    I have a base class called shape and 3 drived classes: line, rect, circle.
    in addition I have drawing class that contins array of shape*.
    I successfully overloaded opertor << for line, rect and circle and now i try to overload << for drawing class. I tried the following:
    Code:
    ostream& operator << (ostream& os, const Drawing& drw)
     {
         for(int i=0; i<drw.size_;i++)
              if (!(drw.drawing_[i].is_empty()))
     	os << drw.drawing_[i]<<endl;
         return os<<endl;
     }
    and I got this error:
    no match for operator << in 'os<<*shape'
    so I tried casting:
    Code:
    ...
    switch ( int(drw.drawing_[i].type()) ){
        case 1:
        		os << dynamic_cast<Line*>(&drw.drawing_[i]) <<endl;
    		break;
        case 2:
        		os << dynamic_cast<Rect*>(&drw.drawing_[i]) <<endl;
    		break;
        case 3:
        		os << dynamic_cast<Circle*>(&drw.drawing_[i]) <<endl;
    		break;
    	}
    ...
    and then I got:
    error: cannot dynamic cast shape* to Line* (source is not polymorphic)

    any ideas??

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Seems like you want a virtual function that "does the right thing" for output of a shape. For example, you could have a "draw()" function that takes an ostream and does the right output.

    The switch statement is absolutely not right [in fact, if you do inheritance right, you should not need a "type" field].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    Jan 2009
    Posts
    20
    At first I didn't use switch:
    Code:
    ostream& operator << (ostream& os, const Drawing& drw)
     {
         for(int i=0; i<drw.size_;i++)
              if (!(drw.drawing_[i].is_empty()))
     	os << drw.drawing_[i]<<endl;
         return os<<endl;
     }
    I have operator << for each type of shape that prints what it needs
    I thought that was enough

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by stewie griffin View Post
    At first I didn't use switch:
    Code:
    ostream& operator << (ostream& os, const Drawing& drw)
     {
         for(int i=0; i<drw.size_;i++)
              if (!(drw.drawing_[i].is_empty()))
     	os << drw.drawing_[i]<<endl;
         return os<<endl;
     }
    I have operator << for each type of shape that prints what it needs
    I thought that was enough
    The problem with overloaded operators is that they are not virtual. So to solve that, I'd suggestion you do something like this:
    Code:
    class Shape
    {
    ...
      public:
    ...
         virtual void Draw(ostream& os) = 0;
    };
    
    class Line : public Shape
    {
    ... 
       public:
    ...
         virtual void Draw(ostream& os);
    };
    
    void Line::Draw(ostream &os)
    {
        ... do your ACTUAL drawing for line, using basic << operator.
    }
    
    ostream& operator << (ostream& os, const Shape& sh)
     {
         sh.Draw(os);
         return os;
     }

    That way, each drawing can do it's own thing, but you can still use a generic form with << .

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Jan 2009
    Posts
    20
    and what if I can't use virtual functions (exercise restrictions)?

  6. #6
    The larch
    Join Date
    May 2006
    Posts
    3,573
    If that is so, the dynamic_casts must be static_casts instead. dynamic_cast only works if there is a vtable, which there isn't if the class doesn't have any virtual methods.

    Style-wise an enum might be preferable to magic values 1, 2, and 3.

    You should also have an array of pointer. If it is an array of Shapes, objects in it will be sliced, i.e they will all be of type Shape and you can't cast them to anything.

    The restriction is quite stupid since you learn little useful, unless the morale is to demonstrate how polymorphism is simpler than manual RTTI.
    Last edited by anon; 01-15-2009 at 03:30 PM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  7. #7
    Registered User
    Join Date
    Jan 2009
    Posts
    20
    I don't know the reason for this restriction......
    anyway, when using static_cast I got the following error:
    no matching function to call Line::Line(shape&)
    so I guess I need to build a constructor with shape& as argument
    but then I wouldn't have access to the Line private members.
    let's say that I declare:
    Code:
     Line::Line (shape& s);
    now when this constructor is being called s is actually a Line but
    how can I assign s's private members of Line class to the new object?

    BTW
    1. in the .H file I declared:
    Code:
    enum Type{_line,_rect,_circ};
    I just didn't write it in the post
    2.Drawing class contains an array of pointers to shape

  8. #8
    The larch
    Join Date
    May 2006
    Posts
    3,573
    You must have some function that does the drawing (or perhaps overload << for each class as well). The you cast the pointer to the correct type and invoke that function.

    If the compiler thinks you are trying to call the constructor, your code is probably that wrong...
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by stewie griffin
    and what if I can't use virtual functions (exercise restrictions)?
    I concur with anon. If you are not allowed to use virtual functions, then a hierarchy of classes does not make sense (unless you are using private inheritance to make use of the base class implementation). You might want to check with your teacher if you are even supposed to solve this using public inheritance. If not, ask your teacher to explain why he or she contradicts Stroustrup's statement that "in the context of C++ (object oriented programming) means programming using class hierarchies and virtual functions to allow manipulation of objects of a variety of types through well-defined interfaces and to allow a program to be extended incrementally through derivation".
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User
    Join Date
    Jan 2009
    Posts
    20
    As I said, each derived class has its overloaded operator<<
    I thought that when calling cout<<drw.drawing[i] the correct operator would be called
    but something here is wrong....

    And I definitely have to use public inheritance....
    Last edited by stewie griffin; 01-16-2009 at 01:28 AM.

  11. #11
    The larch
    Join Date
    May 2006
    Posts
    3,573
    drw.drawing[i] should be a pointer, so it should print the address?

    Have you tried something like:

    Code:
    case _line:
       os << *static_cast<Line*>( drw.drawing[i] ); break;
    case _circle:
       os << *static_cast<Circle*>(drw.drawing[i] ); break;
    etc.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  12. #12
    Registered User
    Join Date
    Jan 2009
    Posts
    20
    well couple of days ago I tried something like this:
    Code:
     case _line:
       os << static_cast<Line>( drw.drawing[i] ); break;
    and It didn't work....
    but when I tried now your code (with a minor change)
    Code:
     os << *static_cast<Line*>( &drw.drawing[i] ); break;
    it worked!!!

    thank you very much!!!

    all of you....
    Last edited by stewie griffin; 01-16-2009 at 02:02 AM.

  13. #13
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by stewie griffin View Post
    and what if I can't use virtual functions (exercise restrictions)?
    That's sort of like being required to ride a bicycle but not allowed to use the pedals. A class hierarchy often makes little sense if virtual functions aren't allowed.

    As others have said, it is necessary to convert base class pointers/references to the correct type.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. inheritance, polymorphism, and virtual functions
    By cs_student in forum C++ Programming
    Replies: 8
    Last Post: 08-04-2008, 08:47 AM
  2. Replies: 8
    Last Post: 01-13-2008, 05:57 PM
  3. Polymorphism, inheritance and containers
    By musicalhamster in forum C++ Programming
    Replies: 6
    Last Post: 11-27-2007, 10:23 AM
  4. Inheritance and Polymorphism
    By bench386 in forum C++ Programming
    Replies: 2
    Last Post: 03-18-2004, 10:19 PM
  5. inheritance and polymorphism uses...
    By tetra in forum C++ Programming
    Replies: 5
    Last Post: 05-06-2003, 05:30 PM