Thread: Confused by Assertion Errors.

  1. #1
    Registered User
    Join Date
    Nov 2008
    Posts
    14

    Confused by Assertion Errors.

    I'm currently writing a basic program with 6 classes, Shape, TwoDimensionalShape, ThreeDimensionalShape, Square, Circle, Cube. They inherit from one another, square and circle from two dimensional, and two dimensional from Shape.

    In the execution of the main program I'm getting an assertion error. After some reading I see that the compiler is throwing an error because it got an unexpected input. Im still confused where I went wrong, long code segment below. Any tips on proper indenting and what not to make it more readable is appreciated.

    Code:
    #include<iostream>
    #include<string>
    using namespace std;
    class Shape{
    public:
    	double length, width;
    	char* type;
    
    Shape::Shape(double l, double w)
    {
    	length = l;//basic constructor
    	width = w;
    	type = "undefined";
    }
    
    Shape::~Shape()
    {
    	delete type;//delete the pointer variable so it isnt randomly at memory.
    }
    double Shape::  getArea()
    {
    	return 0.0;//to be overridden in every child class that uses it.
    }
    double Shape :: getVolume()
    {
    	return 0.0;//to be overridden in every child class that uses it.
    }
    char* Shape::getShapeType()
    {
    	return type;
    }
    int Shape::getType()
    {
    	if(strcmp(type, "Square") || strcmp(type, "Circle"))
    	{
    		return 0;/*Utilized strings instead of number type identifying, didnt see the reason.
    				 Square and Circle are the only 2 dimensional shapes created.*/
    	}
    	else return 1;
    
    }
    };
    
    class TwoDimensionalShape : virtual public Shape{
    public:
    	double area;
    	TwoDimensionalShape::TwoDimensionalShape()
    	{
    		length = 0;
    		type = "TwoDimensionalShape";
    	}
    	TwoDimensionalShape::~TwoDimensionalShape(){delete type;}
    
    };
    class ThreeDimensionalShape : virtual public Shape{
    protected:
    	double volume;
    	ThreeDimensionalShape::ThreeDimensionalShape()
    	{
    		volume = 0;
    		type = "ThreeDimensionalShape";
    	}
    	ThreeDimensionalShape::~ThreeDimensionalShape(){delete type;}
    };
    class Square : public TwoDimensionalShape
    {
    public:
    	double sideLength;
    	Square::Square(double a)
    	   {
    		   sideLength = a;
    		   type = "Square";
    	   }
    	Square::~Square(){delete type;}
    	double Square::getArea()
    	   {
    		   return (sideLength * sideLength);
    	   }
    };
    class Circle: public TwoDimensionalShape
    {
    public:
    	double radius, pi;
    	Circle::Circle(double r)
    	{
    		radius = r;
    		pi = 3.14;
    		type = "Circle";
    	}
    	Circle::~Circle(){delete type;}
    	double Circle::getArea()
    	{
    		return (pi *(radius * radius));
    	}
    };
    class Cube: public ThreeDimensionalShape
    {
    public:
    	double length;
    	Cube::Cube(double l)
    	{
    		length = l;
    		type = "Cube";
    	}
    	Cube::~Cube(){delete type;};
    	double Cube:: getVolume()
    	{
    		return (length * length * length);
    	}
    };
    
    
    int main()
    {
     Shape * s[4];
     Square s1(2.1);
    
     s[0]= &s1;
     s[1]=new Circle(3.0);
     s[2]=new Cube(2.0);
     s[3]=new Square(6.0);
    
    
     for(int i = 0 ; i < 4 ; i++){
     if(s[i]->getType() == 0)
     cout<<"Type=" <<s[i]->getShapeType()<<"\t area="<< s[i]->getArea()<<endl;
     else
     cout<<"Type=" <<s[i]->getShapeType()<<"\t volume"<< s[i]->getVolume()<<endl;
     }
    
     return 0;
    }

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    At a glance, the problem probably as to do with the type member variable. You appear to be setting it to point to a string literal, and then attempt to use delete on it. I suggest that you simply make it a std::string and get rid of that delete. You could also turn it into an enum... or simply get rid of it entirely and make use of polymorphism.
    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

  3. #3
    Registered User
    Join Date
    Nov 2008
    Posts
    14
    I thought I was using polymorphism, when I just use the same instance of the type string for all my subclasses. Is that wrong?

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by ASURugger
    I thought I was using polymorphism, when I just use the same instance of the type string for all my subclasses. Is that wrong?
    Not necessarily wrong, but such type checking tends to break the Open-Closed principle: software entities (classes and functions, in C++'s context) should be open for extension but closed for modification. If you add a new derived class, the code in main() must change (and the code in Shape::getType() as well). Sure, you say that "Square and Circle are the only 2 dimensional shapes created", but that kind of assumption can be rather fragile.

    Basically, the problem is that if the object is 2D shape, you want to get the area, but if the object is a 3D shape, you want to get the volume. One way I can think of is to have a virtual function named getQuantity() that returns the quantitative measure of the shape, be it area, volume, or some other measure devised for shapes of higher dimensions:
    Code:
    class Shape
    {
    public:
        virtual ~Shape() {}
        virtual double getQuantity() const = 0;
    
        friend std::ostream& operator<<(std::ostream& out, const Shape& shape)
        {
            shape.print(out);
            return out;
        }
    private:
        virtual void print(std::ostream& out) const = 0;
    };
    Notice that I made Shape into an abstract base class. There is no way of computing the quantitative measure of a Shape, hence getQuantity() is pure virtual. The operator<< will be used to print the shape. Notice that it calls print(), which is pure virtual. This allows derived classes to determine what to print.

    Oh, and the destructor is virtual - base class destructors should be virtual in order to avoid undefined behaviour if you should delete a derived class object through a base class pointer.

    Now, a TwoDimensionalShape is-a Shape, but it is also an abstract base class:
    Code:
    class TwoDimensionalShape : public Shape
    {
    public:
        virtual double getArea() const = 0;
    
        virtual double getQuantity() const
        {
            return getArea();
        }
    };
    Likewise, define ThreeDimensionalShape.

    Great, now we can begin to implement the concrete classes:
    Code:
    class Square : public TwoDimensionalShape
    {
    public:
        Square(double length) : sideLength(length) {}
    
        virtual double getArea() const
        {
            return sideLength * sideLength;
        }
    private:
        double sideLength;
    
        virtual void print(std::ostream& out) const
        {
            out << "Type=Square\t area=" << getArea();
        }
    };
    Right, so you have implemented Square, Circle and Cube. Defining main() is easy:
    Code:
    int main()
    {
        using namespace std;
    
        Square square1(2.1);
        Circle circle(3.0);
        Cube cube(2.0);
        Square square2(6.0);
    
        Shape* shapes[] = { &square1, &circle, &cube, &square2 };
        const size_t num_shapes = sizeof(shapes) / sizeof(shapes[0]);
    
        for (size_t i = 0 ; i < num_shapes; ++i)
        {
            cout << *shapes[i] << "\tquantity=" << shapes[i]->getQuantity() << endl;
        }
    
        return 0;
    }
    I have chosen to demonstrate the polymorphic nature of getQuantity() in the above code, though it is not actually part of your desired output. Notice that if you add say, a Rectangle class, the only code that needs to be added is the code for the Rectange class. This is the Open-Closed principle at work.
    Last edited by laserlight; 11-19-2008 at 04:16 PM. Reason: getQuantity() can be implemented with getArea() in TwoDimensionalShape.
    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

  5. #5
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    The basica rule that you must ALWAYS follow when it comes to memory allocation is that you must delete what you new (and only what you new). You didn't use new on 'type', therefore you don't use delete.
    In fact you don't even need destructors at all!
    Going even furthur, you don't even need that 'type' variable at all either. Just make a virtual function that returns the name of the class, like it was a property.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by iMalc
    Just make a virtual function that returns the name of the class, like it was a property.
    I considered that, but it will not be enough for ASURugger: the text to be printed includes "area" and "volume", which in turn depends on whether the underlying Shape object is a TwoDimensionalShape or a ThreeDimensionalShape, thus a dynamic_cast would still be needed. Using a pure virtual print function works around this problem.
    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

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Header File Errors...
    By Junior89 in forum C++ Programming
    Replies: 5
    Last Post: 07-08-2007, 12:28 AM
  2. Sneaky little linker errors...
    By Tozar in forum C++ Programming
    Replies: 8
    Last Post: 10-25-2006, 05:40 AM
  3. Errors when including winsock2.h
    By skiingwiz in forum Windows Programming
    Replies: 2
    Last Post: 12-27-2002, 07:32 PM
  4. executing errors
    By s0ul2squeeze in forum C++ Programming
    Replies: 3
    Last Post: 03-26-2002, 01:43 PM