-5

I can't seem to get my cylinder class to properly perform its print and volume functions. Here are the instructions for the assignment: Design a class named Shape which is an abstract base class. Shape has two pure virtual functions, printShapeName and print.

Shape contains two other virtual functions, area and volume, each of which has a default implementation that returns a value of zero.

Point class inherits these implementations (both area and volume of a point are zero) from Shape. A Point has x and y coordinate private members.

Class Circle is derived from Point with public inheritance. A Circle has a volume of 0.0, so base-class member function volume is not overridden. A Circle has nonzero area, so the area function is overridden in this class. Write get and set functions to return and to assign a new radius to a Circle.

Class Cylinder is derived from Circle with public inheritance. A Cylinder has area and volume different from those of Circle, so the area and volume functions are both overridden in this class. Write get and set functions to return height and assign new height.

Create one point, one circle, and one Cylinder then print the results.

//
//  Shape.hpp
//  HW6_VirtualFunctions
//
//  Created by Aviv Fedida on 11/25/17.
//  Copyright © 2017 Aviv Fedida. All rights reserved.
//

#ifndef Shape_hpp
#define Shape_hpp

#include <stdio.h>
#include <iostream>
#include <cmath>
using namespace std;

class Shape {
protected:  // protected members
    double width, height, radius, pi, x, y;
public:
    void setWidth(double a);    // prototype for width setter
    void setHeight(double b);   // prototype for height setter
    void setX(double c);
    void setY(double d);
    void setRad(double r);
    void setPi(double p);
    double getWidth() { // get width to return only
        return width;
    }
    double getHeight() { // get height to return only
        return height;
    }
    double getX() {
        return x;
    }
    double getY() {
        return y;
    }
    double getRad() {
        return radius;
    }
    double getPi() {
        return pi;
    }
    // Create public virtual functions
    virtual void printShapeName() = 0; // pure virtual for printing shape's name
    virtual void print(double a, double b) = 0; // pure virtual print function
    virtual double area() {  // virtual area function returns default null
        return 0;
    }
    virtual double volume() {  // virtual default volume function returns null
        return 0;
    }
};  // END BASE CLASS -------------------------------------------------------------------------------------

class Point: public Shape {
    // x & y coordinates needed for a point
public:
    // Prototypes for print & set functions
    void printShapeName();
    void print(double a, double b);
    };  // end first derived class ------------------------------------------------------------------------

class Circle: public Point {
public:
    //  Protoypes for print functions
    void printShapeName();
    void print(double r, double p);
    //  Prototypes for area & volume functions
    double area(double r, double p);
};  // end second derived class ----------------------------------------------------------------------------

class Cylinder: public Circle {
public:
    double area(double r, double p);
    void printShapeName();
    double volume(double r, double p, double h);
    void print(double r, double p, double h);
}; // end third and final derived class --------------------------------------------------------------------------

//  Some definitions outside classes
//--------------------------------------------------    BEGIN   -----------------------------------------------------------
//  Shape base class setter functions defined
void Shape::setWidth(double a) {
    width = a;
}
void Shape::setHeight(double b) {
    height = b;
}
void Shape::setX(double c) {
    x = c;
}
void Shape::setY(double d) {
    y = d;
}
void Shape::setRad(double r) {
    radius = r;
}
void Shape::setPi(double p) {
    p = 3.1416;
    pi = p;
}

void Point::printShapeName() {   // Print name of class
    cout << "Point " << endl;
}
void Point::print(double a, double b) {   // Print values within class
    cout << "(" << a << "," << b << ")" << endl;
}

void Circle::printShapeName() {
    cout << "Circle " << endl;
}
//  Circle area function defined
double Circle::area(double r, double p) {
    double area;
    area = p*(pow(r,2));
    return area;
}
void Circle::print(double r, double p) {
    cout << "Area of circle is: " << area(r, p) << endl;
    cout << "Volume of circle is: " << volume() << endl;
}

void Cylinder::printShapeName() {
    cout << "Cylinder " << endl;
}
double Cylinder::area(double r, double p) {
    double area;
    area = 2*p*r;
    return area;
}
double Cylinder::volume(double r, double p, double h) {
    double volume;
    volume = p*(pow(r,2))*h;
    return volume;
}
void Cylinder::print(double r, double p, double h) {
    cout << "Area of cylinder is: " << area(r, p) << endl;
    cout << "Volume of cylinder is: " << volume(r, p, h) << endl;
}



#endif /* Shape_hpp */

//
//  main.cpp

#include <iostream>
#include "Shape.hpp"
#include "Shape.cpp"

using namespace std;

int main() {
    double pi = 3.1416; // Variable for pi
    //  Instantiate class objects
    Point guard;
    Circle k;
    Cylinder cid;
    //  Instantiate pointers to class objects
    Shape *pptr;
    Shape *kptr;
    Shape *cptr;
    //  Assign memory of objects to pointer variables
    pptr = &guard;
    kptr = &k;
    cptr = &cid;
    //  Call objects via pointers and print members
    pptr->printShapeName();
    pptr->print(5,6);
    cout << '\n';
    kptr->printShapeName();
    kptr->print(9,pi);
    cout << '\n';
    cptr->printShapeName();
    cptr->getHeight();
    cptr->setHeight(8);
    cptr->print(5,pi);
    return 0;
}

If I try to add a third height argument to my print function for Cylinder class, I get an error. It ends up using my Circle class definition.

halfer
  • 19,824
  • 17
  • 99
  • 186
Avivsta
  • 11
  • 1
  • 1
  • 1
    "PLEASE ASSIST" That's kind of the point here. "I can't seem to get my cylinder class to properly perform its print and volume functions." What goes wrong? The answers are always better when you and the answerer know what the problem is. – user4581301 Nov 28 '17 at 01:20
  • 1
    I very strongly recommend against doing this: `#include "Shape.cpp"`. Include header files. Compile and link implementation files. May IDEs will do what they should do and compile and link this file for you resulting in scads of linker errors. Since we don't know what your problem is, this might be it. Or maybe not. – user4581301 Nov 28 '17 at 01:23
  • You are not implementing OO programing correctly which its not the error it is most likely linked to the error. – Jake Freeman Nov 28 '17 at 01:33
  • See http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html ... I would say that getters and setters add no value. – 2785528 Nov 28 '17 at 02:47
  • @user4581301Thank you for the only comment that provides an intent to help. Yes, I should have been more clear. That certainly was an error. The other one was in the output from print() funct in cylinder class. Here is what it reads: – Avivsta Nov 28 '17 at 05:58
  • Cylinder Area of circle is: 78.54 Volume of circle is: 0 – Avivsta Nov 28 '17 at 05:58
  • @JakeFreeman Not helpful. – Avivsta Nov 28 '17 at 05:59

1 Answers1

0

On the off chance you haven't found the answer yet, cptr->print(5,pi); calls print with 2 parameters. Circle has a 2 parameter print Cylinder has a 3 parameter print. Since Cylinder inherits the 2 parameter print from Circle, the Cylinder is printed as if it were a Circle.

JakeFreeman's comment may not be helpful, but it is exactly right. Let's try and make it helpful without repeating a couple chapters of your textbook.

You have run afoul of two major OO concepts: Encapsulation and polymprphism.

Encapsulation is the major problem here and dealing with it solves the polymporphism problem.

A Cylinder object should represent one and only one Cylinder. It should have it's radius and height stored within it. Calling a function and passing in the radius and height is ideologically dead wrong. When you execute a method on a Cylinder, it should already know its radius and height. A volume method should take no parameters because everything needed to compute volume should already be known. This allows any shape to have the same volume interface even though the method backing the interface will likely be different for each shape.

Exactly the same logic applies to area.

Next, not all shapes have a radius, so Shape should know nothing about radius. Or height. Or depth. Maybe shape knows some anchoring point, but that's about all a shape should know.

Likewise print should require no parameters except perhaps a reference to the IO stream you want to print to because IOstreams are not something one would normally expect a Cylinder to know or care about enough to contain.

One nag: Why pass around pi at all? If you have a system in which pi is not a constant, you have one hell of a bizarre system.

revised shape:

class Shape {
protected:  // protected members
    static constexpr double pi = 3.1459 // add more precision as needed
    double x, y;
public:
    Shape (double posx, double posy): x(posx), y(posy)
    { // set up as much as you can in a constructor because otherwise you always 
      // have to look over your shoulder and test, "Did the object get properly 
      // initialized?"
    }
    void setX(double c)
    {
         if (c is within logical bounds)
         { // because a setter that does not protect the object is no better for
           encapsulation than a public member variable
             x = c;
         }
    }
    void setY(double d);
    {
         if (d is within logical bounds)
         {
             x = d;
         }
    }
    double getX() {
        return x;
    }
    double getY() {
        return y;
    }
    // Create public virtual functions
    virtual void printShapeName() = 0; // pure virtual for printing shape's name
    virtual void print() = 0; // pure virtual print function
    virtual double area() {  // virtual area function returns default null
        return 0;
    }
    virtual double volume() {  // virtual default volume function returns null
        return 0;
    }
}; 

Note No setting of anything bey the bare bones of a shape. Forcing a setRadius function on a square is just plain stupid.

Note also that this eliminates the need for Point, but this is a good thing. Is a circle a type of a point? No. A circle is AT a point. With very rare exceptions, do not extend unless there is what is called an is-a relationship. A square is-a specialized rectangle. A rectangle is a specialized shape. But neither is a point.

I recommend grouping setX and setY into a setPosition that does both at the same time because you will have an easier time turning it into an atomic transaction later.

Revised Circle:

class Circle: public Shape {
protected:
    double radius;
public:
    Circle(double posx, double posy, double rad): Shape(posx, posy), radius(rad)
    {
    }
    void setRadius(double rad)
    {
        if (rad makes sense)
        {
            radius = rad;
        }
    }
    double getRadius()
    {
        return radius;
    }
    //  Protoypes for print functions
    void printShapeName();
    virtual void print();
    double area();
};

double Circle::area() {
    return  pi*radius*radius; // note on pow. It can be very slow. For simple 
                              // exponents just multiply
}
void Circle::print() {
    cout << "Area of circle is: " << area() << '\n';
    // also shy away from `endl` in favour of a raw end of line.
    // endl flushes the stream to the underlying media, also very expensive,
    // so something best done when you have to or you have nothing better to do. 
    cout << "Volume of circle is: 0\n";
}

Circle adds what it needs to add to Shape. Nothing more. Nothing less. Cylinder will do the same. It is a circle plus a height, a accessors for height, a volume computation using Circle's area method and height, its own area method to compute its surface area, and another print method that prints out its statistics

Addendum: if your compiler supports it, and by this time it should, take advantage of the override keyword. If the compiler finds a method marked override and it doesn't override anything, you get a nice clean error message rather than a bunch of debugging.

user4581301
  • 33,082
  • 7
  • 33
  • 54