Thread: Program with Shapes using Virtual Functions

  1. #1
    Registered User
    Join Date
    Nov 2004
    Posts
    73

    Program with Shapes using Virtual Functions

    Hi everyone,

    I am doing a Windows BGI graphics program with C++ that randomly draws different types of shapes on the screen and calculates the area of each shape and displays the area inside the shape and then calculates and displays the total area of all the shapes at the end of the program.

    I am trying to declare new objects of each type of shape. For example, I'm trying to create a pointer *r to a rectangle but it is saying that 'r' is undeclared for Rectangle and I can't figure out why.

    Here is the code:

    Code:
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <time.h>
    #include "C:\Dev-C++\Graphics\winbgim.h"
    
    using namespace std;
    
    // Draw Shape class
    
    class DrawShape
    {
    private:
       int colour;
       static int count;
    public:
       static int getCount() { return count; }
       int getColour()       { return colour; }
       DrawShape() {};
       DrawShape(int c) // All Shapes have a colour
       {
          colour = c;
          count++;      // Increment the count
       }
       ~DrawShape()     // Decrement count
       {
          count--;
       }
    
       // All shapes require a Label.
       // best to implement the label method in the base class.
       // Note the call to Area.  This calls the Area function in the 
       // actual shape object that has been instantiated.
    
       void label (int x, int y)
       {
          char s[20];
          sprintf (s, "%d", (int)Area());
          setcolor(WHITE);
          setbkcolor(BLACK);
          settextjustify(CENTER_TEXT, CENTER_TEXT);
          outtextxy(x, y, s);
       }
     
       // virtual functions - MUST be implemented in derived classes
       virtual double Area() = 0; 
       virtual void   Draw() = 0;
    };
    
    class Circle:DrawShape {
       private:
          int xpos, ypos, radius;
       public:
          Circle(int);
    
          virtual double Area() {
             return 3.14*radius*radius;
          }
    
          virtual void Draw() {
    
          }
    };
    
    Circle::Circle(int rad) {
       radius = rad;
    }
    
    class Ellipse:DrawShape {
       private:
          int xpos, ypos, length, width;
       public:
          Ellipse(int, int, int, int);
    
          virtual double Area() {
             return 3.14*length*width;
          }
    
          virtual void Draw() {
    
          }
    };
    
    Ellipse::Ellipse(int x, int y, int len, int wid) {
       length = len;
       width = wid;
       xpos = x;
       ypos = y;
    }
    
    class Rectangle:DrawShape {
       private:
          int xpos, ypos, length, width;
       public:
          Rectangle(int, int, int, int);
    
          virtual double Area() {
             return length*width;
          }
    
          virtual void Draw() {
             rectangle(length, width, xpos, ypos);
          }
    };
    
    Rectangle::Rectangle(int x, int y, int len, int wid) {
       length = len;
       width = wid;
       xpos = x;
       ypos = y;
    }
    
    class Square:DrawShape {
       private:
          int xpos, ypos, length;
       public:
          Square(int);
    
          virtual double Area() {
             return length*length;
          }
    
          virtual void Draw() {
    
          }
    };
    
    Square::Square(int len) {
       length = len;
    }
    
    int DrawShape::count = 0;
    
    int main() {
       initwindow(1024, 768);
       settextstyle(GOTHIC_FONT, HORIZ_DIR, 2);
       setcolor(WHITE);
       outtextxy(0, 0, "CO856 Lab 4B: [S]quare [C]ircle [R]ectangle [E]llipse [T]otal Area");
       srand(time(NULL));
       DrawShape *shape[100];
       char choice;
       int RandXPos, RandYPos, RandRadius, RandLength, RandWidth;
       int NumShapes = 0;
       double totarea;
       getch(choice);
       while (choice != 'q') {
          RandXPos = rand() % 1000;
          RandYPos = rand() % 700;
          RandLength = rand() % 400;
          RandWidth = rand() % 400;
          RandRadius = rand() % 500;
          if (choice == 'r' || choice == 'R') {
             Rectangle *r = new Rectangle(RandXPos, RandYPos, RandLength, RandWidth);
             shape[NumShapes] = r;
             NumShapes++;
          }
       }
       return 0;
    }
    I am using virtual functions because of the fact that there are different types of shapes (Circle, Rectangle, Square and Ellipse up to a maximum of 100 shapes total) that use the same two functions Draw() and Area(). It is saying 'r' is not declared for the pointer to type Rectangle and I don't understand why it's giving me that compile error.

    If anyone has any help or suggestions, it would be greatly appreciated. Thanks.

  2. #2
    Registered User
    Join Date
    May 2002
    Posts
    66
    First DrawShape should have a virtual destructor if you indend to use any virtual methods. But this does not asnwer why it is complaining.

    Can you post the exact error you are getting?

  3. #3
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Is r declared anywhere? I'm guessing the error is here:
    Code:
    Rectangle *r = new Rectangle(RandXPos, RandYPos, RandLength, RandWidth);
    This is an infinite loop, I think:
    Code:
        getch(choice);
        while (choice != 'q') {
            //...
        }
    Ah, now I see your error.
    Code:
    // in drawshape...
    // virtual functions - MUST be implemented in derived classes
       virtual double Area() = 0; 
       virtual void   Draw() = 0;
    You're trying to declare an instance of drawshape (DrawShape *shape[100], when there are pure virtual functions in it. Get rid of the =0's and it might work.

    [note]
    Code:
             shape[NumShapes] = r;
             NumShapes++;
    could be
    Code:
        shape[NumShapes++] = r;
    [/note]
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  4. #4
    Registered User
    Join Date
    Nov 2004
    Posts
    73

    Re:

    Thanks for the suggestions dwks and I wish I could report that the '=0' being included in the virtual functions definitions was the problem with 'r' being undeclared but it wasn't.

    I'm still trying to change things around to see what the problem is but so far it's been to no avail.

    To answer your question though, it is the line Rectangle *r = new Rectangle(RandXPos, RandYPos, RandLength, RandWidth); that is giving me the compile error that 'r' is undeclared.

    As for the inifinite loop, I realized that too after you mentioned it but first I want to fix my current problem before I fix that.

    Thanks again.

  5. #5
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Post the exact text of all your compile errors (you can remove the file paths if you want).

  6. #6
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    If you have '=0' then you can't declare instances of the class. Remove it and then report the errors, like Daved said.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  7. #7
    Registered User
    Join Date
    Nov 2004
    Posts
    73
    Here is the error:

    all errors are on the Rectangle *r... line:

    Compiler error text:
    'r' undeclared (first use this function)
    (Each identifier is reported only once for each function it appears in)
    parse error before '('

    it's the same problem that I stated above. It's not recognizing 'r' as being a declared pointer to type Rectangle.

    If it's still too unclear, I can post the .cpp file as an attachment.

  8. #8
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    What's the parse error?
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    dwks, the =0 is fine, an instance of DrawShape is never declared from what I can see. Only an array of pointers to DrawShape objects, which is correct use of polymorphism.

    goron350, You say all errors are on the Rectangle *r line, but then you only post one error. My guess is that it is not recognizing Rectangle for some reason. Maybe you have a typo in your actual code. I notice that your Draw function in Rectangle calls something called rectangle. Is that a typo or is there a function called rectangle in your graphics library?

    Also, you are inheriting privately from DrawShape in all your derived classes. Maybe you meant to inherit publicly:
    Code:
    class Rectangle: public DrawShape {

  10. #10
    Registered User
    Join Date
    Nov 2004
    Posts
    73
    Dave, There is a rectangle function in the winbgim graphics library that draws a rectangle based on the four parameters(x position, y position, length and width) and that is what I used in the Draw() function to draw that shape based on the random numbers generated in main() so that is not a typo.

  11. #11
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Ok, then make your inheritance public unless you specifically meant private, and things should be better.

  12. #12
    Registered User
    Join Date
    Nov 2004
    Posts
    73
    I am trying now to chain to the base class so that all the shapes can get at the colour data member to randomize the colours of each shape pressed by the user. How can I chain to the base class from the derived classes?

    Here is my updated code so far for this program:

    Code:
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <time.h>
    #include "C:\Dev-C++\Graphics\winbgim.h"
    
    using namespace std;
    
    // Draw Shape class
    
    class DrawShape
    {
    private:
       int colour;
       static int count;
    public:
       static int getCount() { return count; }
       int getColour()       { return colour; }
       DrawShape() {};
       DrawShape(int c) // All Shapes have a colour
       {
          colour = c;
          count++;      // Increment the count
       }
       ~DrawShape()     // Decrement count
       {
          count--;
       }
    
       // All shapes require a Label.
       // best to implement the label method in the base class.
       // Note the call to Area.  This calls the Area function in the 
       // actual shape object that has been instantiated.
    
       void label (int x, int y)
       {
          char s[20];
          sprintf (s, "%d", (int)Area());
          setcolor(WHITE);
          setbkcolor(BLACK);
          settextjustify(CENTER_TEXT, CENTER_TEXT);
          outtextxy(x, y, s);
       }
     
       // virtual functions - MUST be implemented in derived classes
       virtual double Area() = 0;
       virtual void   Draw() = 0;
    };
    
    class Circle: public DrawShape {
       private:
          int xpos, ypos, radius;
       public:
          Circle(int, int, int);
    
          virtual double Area() {
             return 3.14*radius*radius;
          }
    
          virtual void Draw() {
             circle(xpos, ypos, radius);
          }
    };
    
    Circle::Circle(int x, int y, int rad) {
       xpos = x;
       ypos = y;
       radius = rad;
    }
    
    class Ell: public DrawShape {
       private:
          int xpos, ypos, length, width;
       public:
          Ell(int, int, int, int);
    
          virtual double Area() {
             return 3.14*length*width;
          }
    
          virtual void Draw() {
             ellipse(xpos, ypos, 0, 0, xpos+length, ypos+width);
          }
    };
    
    Ell::Ell(int x, int y, int len, int wid) {
       length = len;
       width = wid;
       xpos = x;
       ypos = y;
    }
    
    class Rect: public DrawShape {
       private:
          int xpos, ypos, length, width;
       public:
          Rect(int, int, int, int);
    
          virtual double Area() {
             return length*width;
          }
    
          virtual void Draw() {
             rectangle(xpos,ypos,xpos+length,ypos+width);
          }
    };
    
    Rect::Rect(int x, int y, int len, int wid) {
       length = len;
       width = wid;
       xpos = x;
       ypos = y;
    }
    
    class Square: public DrawShape {
       private:
          int xpos, ypos, length;
       public:
          Square(int, int, int);
    
          virtual double Area() {
             return length*length;
          }
    
          virtual void Draw() {
             rectangle(xpos, ypos, xpos+length, ypos+length);
          }
    };
    
    Square::Square(int x, int y, int len) {
       xpos = x;
       ypos = y;
       length = len;
    }
    
    int DrawShape::count = 0;
    
    int main() {
       initwindow(1024, 768);
       settextstyle(GOTHIC_FONT, HORIZ_DIR, 2);
       setcolor(WHITE);
       outtextxy(0, 0, "CO856 Lab 4B: [S]quare [C]ircle [R]ectangle [E]llipse [T]otal Area");
       srand(time(NULL));
       DrawShape *shape[100];
       char choice;
       char a[20];
       int RandXPos, RandYPos, RandRadius, RandLength, RandWidth;
       int NumShapes = 0;
       double totarea;
       while (choice != 'q' && NumShapes < 100) {
          choice = getch();
          if (choice != 'q') {
             RandXPos = rand() %400+100;
             RandYPos = rand() %400+100;
             RandLength = rand() %100+100;
             RandWidth = rand() %100+100;
             RandRadius = rand() %50+50;
             if (choice == 'r' || choice == 'R') {
                Rect *r = new Rect(RandXPos, RandYPos, RandLength, RandWidth);
                shape[NumShapes] = r;
                shape[NumShapes]->Draw();
                shape[NumShapes]->label(RandXPos+(RandLength/2), RandYPos+(RandWidth/2));
                totarea += shape[NumShapes]->Area();
                NumShapes++;
             }
             else if (choice == 'c' || choice == 'C') {
                Circle *c = new Circle(RandXPos, RandYPos, RandRadius);
                shape[NumShapes] = c;
                shape[NumShapes]->Draw();
                shape[NumShapes]->label(RandXPos+(RandRadius/2), RandYPos+(RandRadius/2));
                totarea += shape[NumShapes]->Area();
                NumShapes++;
             }
             else if (choice == 's' || choice == 'S') {
                Square *s = new Square(RandXPos, RandYPos, RandLength);
                shape[NumShapes] = s;
                shape[NumShapes]->Draw();
                shape[NumShapes]->label(RandXPos+(RandLength/2), RandYPos+(RandLength/2));
                totarea += shape[NumShapes]->Area();
                NumShapes++;
             }
             else if (choice == 'e' || choice == 'E') {
                Ell *e = new Ell(RandXPos, RandYPos, RandLength, RandWidth);
                shape[NumShapes] = e;
                shape[NumShapes]->Draw();
                shape[NumShapes]->label(RandXPos+(RandLength/2), RandYPos+(RandWidth/2));
                totarea += shape[NumShapes]->Area();
                NumShapes++;
             }
             else if (choice == 't' || choice == 'T') {
                setactivepage(1);
                setvisualpage(1);
                sprintf(a, "%d", totarea);
                setcolor(WHITE);
                outtextxy(150, 20, "Total area is: ");
                outtextxy(180, 60, a);
                getch();
                setvisualpage(0);
                setactivepage(0);
             }
          }
       }
       return 0;
    }
    I am looking to chain the derived classes to the base class so that every shape (derived class) can get at and utilize the colour variable from the base class so that the colour can be randomized for every shape selected by the user. I know there is way to do this but I don't know what the syntax is to do it.

    If anyone can explain the syntax to achieve this, it would be greatly appreciated. Thanks.

  13. #13
    Registered User
    Join Date
    Nov 2004
    Posts
    73
    Hi again everyone,

    I am getting close to completing this shapes program but now I am trying to chain to the base class so that all the shapes can get at the colour data member to randomize the colours of each shape pressed by the user. Right now, the colours of the shapes are just white and I want a way to randomize the colours of the shapes. How can I chain to the base class from the derived classes? The program accepts a maximum of 100 shapes selected by the user.

    Here is my updated code so far for this program:

    Code:
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <time.h>
    #include "C:\Dev-C++\Graphics\winbgim.h"
    
    using namespace std;
    
    // Draw Shape class
    
    class DrawShape
    {
    private:
       int colour;
       static int count;
    public:
       static int getCount() { return count; }
       int getColour()       { return colour; }
       DrawShape() {};
       DrawShape(int c) // All Shapes have a colour
       {
          colour = c;
          count++;      // Increment the count
       }
       ~DrawShape()     // Decrement count
       {
          count--;
       }
    
       // All shapes require a Label.
       // best to implement the label method in the base class.
       // Note the call to Area.  This calls the Area function in the 
       // actual shape object that has been instantiated.
    
       void label (int x, int y)
       {
          char s[20];
          sprintf (s, "%d", (int)Area());
          setcolor(WHITE);
          setbkcolor(BLACK);
          settextjustify(CENTER_TEXT, CENTER_TEXT);
          outtextxy(x, y, s);
       }
     
       // virtual functions - MUST be implemented in derived classes
       virtual double Area() = 0;
       virtual void   Draw() = 0;
    };
    
    class Circle: public DrawShape {
       private:
          int xpos, ypos, radius;
       public:
          Circle(int, int, int);
    
          virtual double Area() {
             return 3.14*radius*radius;
          }
    
          virtual void Draw() {
             circle(xpos, ypos, radius);
          }
    };
    
    Circle::Circle(int x, int y, int rad) {
       xpos = x;
       ypos = y;
       radius = rad;
    }
    
    class Ell: public DrawShape {
       private:
          int xpos, ypos, length, width;
       public:
          Ell(int, int, int, int);
    
          virtual double Area() {
             return 3.14*length*width;
          }
    
          virtual void Draw() {
             ellipse(xpos, ypos, 0, 0, xpos+length, ypos+width);
          }
    };
    
    Ell::Ell(int x, int y, int len, int wid) {
       length = len;
       width = wid;
       xpos = x;
       ypos = y;
    }
    
    class Rect: public DrawShape {
       private:
          int xpos, ypos, length, width;
       public:
          Rect(int, int, int, int);
    
          virtual double Area() {
             return length*width;
          }
    
          virtual void Draw() {
             rectangle(xpos,ypos,xpos+length,ypos+width);
          }
    };
    
    Rect::Rect(int x, int y, int len, int wid) {
       length = len;
       width = wid;
       xpos = x;
       ypos = y;
    }
    
    class Square: public DrawShape {
       private:
          int xpos, ypos, length;
       public:
          Square(int, int, int);
    
          virtual double Area() {
             return length*length;
          }
    
          virtual void Draw() {
             rectangle(xpos, ypos, xpos+length, ypos+length);
          }
    };
    
    Square::Square(int x, int y, int len) {
       xpos = x;
       ypos = y;
       length = len;
    }
    
    int DrawShape::count = 0;
    
    int main() {
       initwindow(1024, 768);
       settextstyle(GOTHIC_FONT, HORIZ_DIR, 2);
       setcolor(WHITE);
       outtextxy(0, 0, "CO856 Lab 4B: [S]quare [C]ircle [R]ectangle [E]llipse [T]otal Area");
       srand(time(NULL));
       DrawShape *shape[100];
       char choice;
       char a[20];
       int RandXPos, RandYPos, RandRadius, RandLength, RandWidth;
       int NumShapes = 0;
       double totarea;
       while (choice != 'q' && NumShapes < 100) {
          choice = getch();
          if (choice != 'q') {
             RandXPos = rand() %400+100;
             RandYPos = rand() %400+100;
             RandLength = rand() %100+100;
             RandWidth = rand() %100+100;
             RandRadius = rand() %50+50;
             if (choice == 'r' || choice == 'R') {
                Rect *r = new Rect(RandXPos, RandYPos, RandLength, RandWidth);
                shape[NumShapes] = r;
                shape[NumShapes]->Draw();
                shape[NumShapes]->label(RandXPos+(RandLength/2), RandYPos+(RandWidth/2));
                totarea += shape[NumShapes]->Area();
                NumShapes++;
             }
             else if (choice == 'c' || choice == 'C') {
                Circle *c = new Circle(RandXPos, RandYPos, RandRadius);
                shape[NumShapes] = c;
                shape[NumShapes]->Draw();
                shape[NumShapes]->label(RandXPos+(RandRadius/2), RandYPos+(RandRadius/2));
                totarea += shape[NumShapes]->Area();
                NumShapes++;
             }
             else if (choice == 's' || choice == 'S') {
                Square *s = new Square(RandXPos, RandYPos, RandLength);
                shape[NumShapes] = s;
                shape[NumShapes]->Draw();
                shape[NumShapes]->label(RandXPos+(RandLength/2), RandYPos+(RandLength/2));
                totarea += shape[NumShapes]->Area();
                NumShapes++;
             }
             else if (choice == 'e' || choice == 'E') {
                Ell *e = new Ell(RandXPos, RandYPos, RandLength, RandWidth);
                shape[NumShapes] = e;
                shape[NumShapes]->Draw();
                shape[NumShapes]->label(RandXPos+(RandLength/2), RandYPos+(RandWidth/2));
                totarea += shape[NumShapes]->Area();
                NumShapes++;
             }
             else if (choice == 't' || choice == 'T') {
                setactivepage(1);
                setvisualpage(1);
                sprintf(a, "%d", totarea);
                setcolor(WHITE);
                outtextxy(150, 20, "Total area is: ");
                outtextxy(180, 60, a);
                getch();
                setvisualpage(0);
                setactivepage(0);
             }
          }
       }
       return 0;
    }
    I am looking to chain the derived classes to the base class so that every shape (derived class) can get at and utilize the colour variable from the base class so that the colour can be randomized for every shape selected by the user. I know there is way to do this but I don't know what the syntax is to do it.

    If anyone can explain the syntax to achieve this, it would be greatly appreciated. Thanks.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Program skips functions in main
    By En-Motion in forum C++ Programming
    Replies: 5
    Last Post: 02-18-2009, 09:35 PM
  2. Client-server system with input from separate program
    By robot-ic in forum Networking/Device Communication
    Replies: 3
    Last Post: 01-16-2009, 03:30 PM
  3. Virtual Functions
    By guda in forum C++ Programming
    Replies: 3
    Last Post: 11-16-2004, 04:13 PM
  4. virtual functions and templates
    By ygfperson in forum C++ Programming
    Replies: 7
    Last Post: 07-22-2003, 01:10 PM
  5. Exporting Object Hierarchies from a DLL
    By andy668 in forum C++ Programming
    Replies: 0
    Last Post: 10-20-2001, 01:26 PM