1
votes

I'm getting hardship in calss developmen whose super classes are Number and Shape.

Actually, I decalred virtual, and this was quite causing errors for instance vtable, and I double-checked all the posts in stackoverflow regarding vtable and also, incorrect usage of void, but I couldn't at the end troubleshoot such issues.

Could you please kindly help me to think about this? I'm spending over a week to ponder upon this, and this is really antagonizing me really...

If my question needs more complementary things, don't hesitate to comment, I'll be happy to interact with.

The NumberMain program includes, Complex, Fraction and Number with NumberMain.

The ShapeMain program includes Circle, Shape, Square, and Triangle with ShapeMain.

enter image description here

enter image description here

enter image description here

enter image description here

Circle.cpp

// This class describes the implementation of a Circle

#include <iostream>
#include "Shape.h"
#include "Circle.h"

using namespace std;

Circle & Circle::setCenterX(float newX) {
   centerX = newX;
   return (*this);
}

Circle & Circle::setCenterY(float newY) {
   centerY = newY;
   return (*this);
}

// This function changes the radius of the circle. Use validation to ensure radius >=0.

void Circle::setRadius(float newRadius) {
   if(newRadius >= 0) {
       radius = newRadius;
   }
   else {
       cout << "Error: radius should be at least 0." << endl;
   }
}

// This function returns the X coordinate of the center of the circle.

float Circle::getX() const {
   return centerX;
}

// This function returns the Y coordinate of the center of the circle.

float Circle::getY() const {
   return centerY;
}

// This function returns the radius of the circle.

float Circle::getRadius() const {
   return radius;
}

// This function returns the area of the circle.

float Circle::getArea() const {
   return radius * radius * PI;
}

// This function returns the diameter of the circle.

float Circle::getDiameter() const {
   return 2 * radius;
}

// This function returns the circumference of the circle.

float Circle::getCircumference() const {
   return 2 * PI * radius;
}

Circle.h

// Circle.h
// This class describes the data and actions for a Circle
#include<iostream>

const float PI = 3.14159;

class Circle : public Shape {
   private:
       float centerX, centerY, radius;
   public:
       Circle & setCenterX(float newX);
       Circle & setCenterY(float newY);
       void setRadius(float newRadius);
       float getX() const;
       float getY() const;
       float getRadius() const;
       float getArea() const;
       float getDiameter() const;
       float getCircumference() const;
};

Shape.cpp

// Shape.cpp
// This file describes the Shape class.

#include <iostream>
#include "Shape.h"

using namespace std;

void Shape::setColor(int newColor) {
   color = newColor;
}

void Shape::printColor() const {
   switch(color) {
       case RED : cout << "Red"; break;
       case BLUE : cout << "Blue"; break;
       case GREEN : cout << "Green"; break;
       default : cout << "Black";
   }
}

Shape.h

// Shape.h
// This file describes the Shape class.

#include <iostream>

const int RED = 1;
const int BLUE = 2;
const int GREEN = 3;

class Shape {
    protected:
        int color;
    public:
        virtual void setColor(int newColor);
        void printColor() const;
        virtual float getArea() const = 0;
};

ShapeMain.cpp

#include <iostream>
#include <stdexcept>
#include "Shape.h"
#include "Circle.h"
#include "Square.h"
#include "Triangle.h"

using namespace std;

// Create and return a Square
Square * makeSquare() {
   Square * square1 = new Square();
   float sideLength;

   cout << "What is the Side Length?";
   cin >> sideLength;
   square1->setCenterX(0).setCenterY(0).setSideLength(sideLength);
   return square1;
}

// Create and return a Circle
Circle * makeCircle() {
   Circle * circle1 = new Circle;
   float radius;

   cout << "What is the Radius?";
   cin >> radius;
   circle1->setCenterX(0).setCenterY(0).setRadius(radius);
   return circle1;
}

Triangle * makeTriangle() {
   Triangle * triangle1 = new Triangle();
   float height, width;

   cout << "What is the Height?";
   cin >> height;
   cout << "What is the Width?";
   cin >> width;
   triangle1->setHeight(height).setWidth(width).setLeft(0).setBottom(0);
   return triangle1;
}

// Create and return a Color
int makeColor() {
   int color;

   cout << RED << ") Red or " << BLUE << ") Blue or " << GREEN << ") Green? ";
   cin >> color;
   return color;
}

int main() {
   Shape * shape1;
   int color;

   int shapeType;

   cout << "1) Square or 2) Circle or 3) Triangle?";
   cin >> shapeType;

   switch(shapeType) {
       case 1 : shape1 = makeSquare(); break;
       case 2 : shape1 = makeCircle(); break;
       case 3 : shape1 = makeTriangle(); break;
       default : throw runtime_error("Invalid Shape Class");
    }

   color = makeColor();
   shape1 -> setColor(color);

   // The getAre() function is polymorphic.
   cout << "The Area is " << shape1->getArea() << endl;
   cout << "The Color is ";
   shape1->printColor();
   cout << endl;

   return 0;
}

Square.cpp

// Square.cpp

#include <iostream>
#include "Shape.h"
#include "Square.h"

using namespace std;

Square & Square::setCenterX(float newX) {
    centerX = newX;
    return (*this);
}

Square & Square::setCenterY(float newY) {
    centerY = newY;
    return (*this);
}

void Square::setSideLength(float newSideLength) {
    if(newSideLength >= 0) {
        sideLength = newSideLength;
    }
    else {
        cout << "Error: Side length should be at least 0." << endl;
    }
}

float Square::getCenterX() {
    return centerX;
}

float Square::getCenterY() {
    return centerY;
}

float Square::getSideLength() {
    return sideLength;
}

float Square::getArea() {
    return sideLength * sideLength;
}

float Square::getTop() {
    return centerY + sideLength / 2;
}

float Square::getBottom() {
    return centerY - sideLength / 2;
}

float Square::getLeft() {
    return centerX - sideLength / 2;
}

float Square::getRight() {
    return centerX + sideLength / 2;
}

Square.h

#include<iostream>

class Square : public Shape {
   private:
       float centerX, centerY, sideLength;
   public:
       Square & setCenterX(float newX);
       Square & setCenterY(float newY);
       void setSideLength(float newSideLength);
       float getCenterX();
       float getCenterY();
       float getSideLength();
       float getArea() const;
       float getTop();
       float getBottom();
       float getLeft();
       float getRight();
};

Triangle.cpp

// Triangle.cpp

#include <iostream>
#include "Shape.h"
#include "Triangle.h"

using namespace std;

Triangle & Triangle::setHeight(float newHeight) {
   height = newHeight;
   return *this;
}

Triangle & Triangle::setWidth(float newWidth) {
   width = newWidth;
   return *this;
}

Triangle & Triangle::setBottom(float newBottom) {
   bottom = newBottom;
   return *this;
}

Triangle & Triangle::setLeft(float newLeft) {
   left = newLeft;
   return *this;
}

float Triangle::getHeight() const {
   return height;
}

float Triangle::getWidth() const {
   return width;
}

float Triangle::getBottom() const {
   return bottom;
}

float Triangle::getLeft() const {
   return left;
}

float Triangle::getArea() const {
   return ((height * width)/2);
}

void Triangle::setColor(int newColor) {
   if (newColor != RED) cout << "Triangles are always Red." << endl;
   color = RED;
}

Triangle.h

#include<iostream>

class Triangle : public Shape {
   private:
       float height, width, bottom, left;
   public:
       Triangle & setHeight(float newHeight);
       Triangle & setWidth(float newWidth);
       Triangle & setBottom(float newBottom);
       Triangle & setLeft(float newLeft);
       float getHeight() const;
       float getWidth() const;
       float getBottom() const;
       float getLeft() const;
       float getArea() const;
       virtual void setColor(int newColor);
};

Complex.cpp

// Complex.cpp
// This file describes the Complex class.

#include <iostream>
#include "Complex.h"

Complex::Complex() {
    real = 0;
    imag = 0;
}

Complex::Complex(float newReal) {
    real = newReal;
    imag = 0;
}

Complex::Complex(float newReal, float newImag) {
    real = newReal;
    imag = newImag;
}

void Complex::print() {
    cout << real << " + j(" << imag << ")" << endl << endl;
}

void Complex::setRealAndImaginary(float newReal, float newImag) {
    real = newReal;
    imag = newImag;
}

void Complex::setReal(float newReal) {
    real = newReal;
}

void Complex::setImaginary(float newImag) {
    imag = newImag
}

float Complex::getReal() {
    return real;
}

float Complex::getImaginary() {
    return imag;
}

// (a + bi) + (c + di) = (a + c) + (b + d)i
Complex Complex::operator+(Complex complex2) {
    Complex newComplex;
    float newReal = real + complex2.getReal();
    float newImag = imag + complex2.getImaginary();
    newComplex.setRealAndImaginary(newReal, newImag);

    return newComplex;
}

// (a + bi) - (c + di) = (a - b) + (b - d)i
Complex Complex::operator-(Complex complex2) {
    Complex newComplex;
    float newReal = real - complex2.getReal();
    float newImag = imag - complex2.getImaginary();
    newComplex.setRealAndImaginary(newReal, newImag);

    return newComplex;
}

// (a + bi) * (c + di) = (ac - bd) + (bc + ad)i
Complex Complex::operator*(Complex complex2) {
    Complex newComplex;
    float newReal = real*complex2.getReal() - imag*complex2.getImaginary();
    float newImag = imag*complex2.getReal() + real*complex2.getImaginary();
    newComplex.setRealAndImaginary(newReal, newImag);

    return newComplex;
}

// (a + bi) / (c + di) = (ac + bd) / (c^2 + d^2) + (bc - ad) / (c^2 + d^2)i
Complex Complex::operator/(Complex complex2) {
    Complex newComplex;
    float newReal = (real*complex2.getReal() + imag*complex2.getImaginary()) / (complex2.getReal()*complex2.getReal() + complex2.getImaginary()*complex2.getImaginary());
    float newImag = (imag*complex2.getReal() - real*complex2.getImaginary()) / (complex2.getReal()*complex2.getReal() + complex2.getImaginary()*complex2.getImaginary());
    newComplex.setRealAndImaginary(newReal, newImag);

    return newComplex;
}

bool Complex::operator==(Complex complex2) {
    return (real == complex2.getReal() && imag == complex2.getImaginary());
}

ostream & operator<<(ostream & output, Complex & complex1) {
    output << complex1.getReal() << " + j(" << complex1.getImaginary() << ")";
    return output;
}

Complex.h

// Complex.h
// This file describes the Complex class.

using namespace std;

class Complex : public Number {
    private:
        float real = 0;
        float imag = 0;
    public:
        Complex();
        Complex(float newReal);
        Complex(float newReal, float newImag);
        void print();
        void setRealAndImaginary(float newReal, float newImag);
        void setReal(float newReal);
        void setImag(float newImag);
        float getReal();
        float getImaginary();
        Complex operator+(Complex complex2);
        Complex operator-(Complex complex2);
        Complex operator*(Complex complex2);
        Complex operator/(Complex complex2);
        bool operator==(Complex complex2);
};

ostream & operator<<(ostream & output, Complex & complex1);

Fraction.cpp

// Fraction.cpp
// This file describes the Fraction class.

#include <iostream>
#include "Fraction.h"

// Constructors for Fraction.
// The default fraction is 0/1.
Fraction::Fraction() {
    setNumerAndDenom(0, 1);
}

// If only the numerator is given then the default denominator is 1.
Fraction::Fraction(int newNumer) {
    setNumerAndDenom(newNumer, 1);
}

Fraction::Fraction(int newNumer, int newDenom) {
    setNumerAndDenom(newNumer, newDenom);
}

//Print function for Fraction.
void Fraction::print() {
    cout << numerator << "/" << denominator;
}

// This function assigns the fraction to a new value.
void Fraction::setNumerAndDenom(int newNumer, int newDenom) {
    if (newDenom == 0) {
        cout << "Error creating a fraction with a zero denominator" << endl;
        return;
    }
    numerator = newNumer;
    denominator = newDenom;
    simplify();
}

// Return the numerator of the fraction.
int Fraction::getNumerator() {
    return numerator;
}

// Return the denominator of the fraction.
int Fraction::getDenominator() {
    return denominator;
}

// Simplify the fraction. For example 2/4 becomes 1/2.
void Fraction::simplify() {
    int gcd = GreatestCommonDenominator(numerator, denominator);

    numerator /= gcd;
    denominator /= gcd;
}

// Addition operator for Fraction
Fraction Fraction::operator+(Fraction frac2) {
    Fraction newFraction;
    int newDenom = denominator * frac2.getDenominator();
    int newNumer = numerator * frac2.getDenominator() + frac2.getNumerator() * denominator;
    newFraction.setNumerAndDenom(newNumer, newDenom);

    return newFraction;
}

// Subtraction operator for Fraction
Fraction Fraction::operator-(Fraction frac2) {
    Fraction newFraction;
    int newDenom = denominator * frac2.getDenominator();
    int newNumer = numerator * frac2.getDenominator() - frac2.getNumerator() * denominator;
    newFraction.setNumerAndDenom(newNumer, newDenom);

    return newFraction;
}

// Multiplication operator for Fraction
Fraction Fraction::operator*(Fraction frac2) {
    Fraction newFraction;
    int newDenom = denominator * frac2.getDenominator();
    int newNumer = numerator * frac2.getNumerator();
    newFraction.setNumerAndDenom(newNumer, newDenom);

    return newFraction;
}

// Division operator for Fraction
Fraction Fraction::operator/(Fraction frac2) {
    Fraction newFraction;
    int newDenom = denominator * frac2.getNumerator();
    int newNumer = numerator * frac2.getDenominator();
    newFraction.setNumerAndDenom(newNumer, newDenom);

    return newFraction;
}

// Equality comparison operator for Fraction
bool Fraction::operator==(Fraction frac2) {
    return (numerator * frac2.getDenominator() == denominator * frac2.getNumerator());
}

// Greater Than comparison operator for Fraction
bool Fraction::operator>(Fraction frac2) {
    return (numerator * frac2.getDenominator() > denominator * frac2.getNumerator());
}

// Less Than comparison operator for fraction
bool Fraction::operator<(Fraction frac2) {
    return (numerator * frac2.getDenominator() < denominator * frac2.getNumerator());
}

// Output operator for Fraction
ostream & operator<<(ostream & output, Fraction & frac) {
    output << frac.getNumerator() << "/" << frac.getDenominator();
    return output;
}

// This function returns the Greatest Common Denominator (GCD) of num1 and num2
int GreatestCommonDenominator(int num1, int num2) {
    if (num1 == 0) return num2;
    if (num1 < 0) return GreatestCommonDenominator(-num1, num2);
    if (num1 > num2) return GreatestCommonDenominator(num2, num1);
    return GreatestCommonDenominator(num2-num1, num1);
}

Fraction.h

// Fraction.h
// This file describes the Fraction class.

using namespace std;

class Fraction : public Number {
    private:
        int numerator, denominator;
    public:
        Fraction(); // Default fraction is 0/1.
        Fraction(int newNumer);
        Fraction(int newNumer, int newDenom);
        void print();
        void setNumerAndDenom(int newNumer, int newDenom);
        int getNumerator();
        int getDenominator();
        void simplify();
        Fraction operator+(Fraction frac2);
        Fraction operator-(Fraction frac2);
        Fraction operator*(Fraction frac2);
        Fraction operator/(Fraction frac2);
        bool operator==(Fraction frac2);
        bool operator>(Fraction frac2);
        bool operator<(Fraction frac2);
};

ostream & operator<<(ostream & output, Fraction & frac1);
int GreatestCommonDenominator(int num1, int num2);

Number.h

// Number.h
// This file describes the Number class.

class Number {
    public:
        void print() const;
};

NumberMain.cpp

// NumberMain.cpp
// This is the main file which demonstrates the Number class.

#include <iostream>
#include "Number.h"
#inlcude "Fraction.h"
#include "Complex.h"

using namespace std;

// Create and return a Complex
Complex * makeComplex() {
    Complex * complex1 = new Complex;
    float real, imag;

    cout << "What is the Real Part? ";
    cin >> real;
    cout << "What is the Imaginary Part? ";
    cin >> imag;
    complex1->setReal(real).setImaginary(imag);
    return complex1;
}

// Create and return a Fraction
Fraction * makeFraction() {
    Fraction * frac1 = new Fraction;
    int numer, denom;

    cout << "What is the Numerator? ";
    cin >> numer;
    cout << "What is the Denominator? ";
    cin >> denom;
    frac1->setNumerator(numer).setDenominator(denom).simplify();
    return frac1;
}

int main() {
    Number * num1;
    int numberType;

    cout << "1) Complex or 2) Fraction ";
    cin >> numberType;

    switch(numberType) {
        case 1 : num1 = makeComplex(); break;
        case 2 : num1 = makeFraction(); break;
        default : cout << "Error: Invalid Number Class" << endl; return 1;
    }

    // The print() function is polymorphic
    num1->print();
    cout << endl;

    return 0;
}

Thank you kindy.

1
In addition to other points in my answer, the spellings of include are not correct i.e. #inlcude "Fraction.h". Pay attention to these errors also. - Azeem
If your solution works correctly, consider asking over at Code Review. If you go this route, read through the linked page so you can adapt your question to fit their rules. - user4581301
You may want to review How to Ask, if you want your questions to get more attention. I got to the end of the textual part of your question without finding out what your question was, only that you have a problem. (More accurately, the existence of your SO question told me you had a problem; the text of your question merely confirmed this.) Your first paragraph is neither engaging nor informative. It's easy to quit reading early and leave this question for "someone else". - JaMiT

1 Answers

0
votes

Following are some points in your code that you need to take care of:

  • There are no header guards in any header files i.e. circular inclusion of the same file resulting in redefinitions errors.
  • The methods names in header and source files are NOT the same.
  • The method chaining is being used with methods returninng void type.
  • In some cases, the functions are declared in the header file but not defined in the source file.

Header Files

Use the following format in your headers files:

// Use pragma directive where compilers support this
#pragma once

// ... code ...

Otherwise, use header guards like this:

#ifndef MY_HEADER
#define MY_HEADER

// ... code ...

#endif

Method Names

Make sure that the names of methods in the header and source files are the same.

// Test.hpp
class Test
{
public:
    void print() const;
};

// Test.cpp
void Test::print() const
{
    // ...
}

Method Chaining

The methods have been chained like this:

complex1->setReal(real).setImaginary(imag);

But, the methods setReal() and setImaginary() return nothing i.e. void. [Note: setImaginary() doesn't exist in header. It is setImag() but in source file it is defined as setImaginary().]

For chaining, the methods should return the reference of the current object. There are a number of Q&As addressing this on SO!

However, in your current code, you need to do this:

complex1->setReal(real);
complex1->setImaginary(imag);

The above points are just some of the issues that exist in your code. There might be more. You need to follow the errors that your compiler reports and resolve those issues.

In the future, please create an MCVE to reduce your code so that others may easily follow and reproduce on their own to provide an adequate response.