Accessing Object names from Array - c++

Using inheritance classes, I am looking to calculate the area of 2d shapes and area and volume of 3d shapes. I am now need to access the array determine the shape and then determine whether to calculate the area or the volume of the shape. The end goal is to loop through and provide output saying the name of the shape the area and/or the volume. How do I access the object names of the array? Thanks
/---------------------------------------------------------
#ifndef SHAPE_H
#define SHAPE_H
const double PI = 3.14159265359;
//Base Class---------------------------------------------
Class Shape {
protected:
//Dimensions
int dimensions;
double area;
double volume;
public:
//Default Constructor
Shape();
//Destructor
~Shape();
//Get Dimension function
double getDimensions();
//virtual function
virtual double getArea();
virtual double getVolume();
};
//Shape Type-----------------------------------------------
class TwoDimensionalShape : public Shape {
protected:
double d1, d2;
public:
double get_d1() { return d1; }
double get_d2() { return d2; }
double set_d1(double x) { d1 = x; }
double set_d2(double x) { d2 = x; }
};
class ThreeDimensionalshape : public Shape {
protected:
double d1, d2, d3;
public:
double get_d1() { return d1; }
double get_d2() { return d2; }
double get_d3() { return d3; }
double set_d1(double x) { d1 = x; }
double set_d2(double x) { d2 = x; }
double set_d3(double x) { d3 = x; }
};
//two dimensionals Shape classes-------------------------
class Circle : public TwoDimensionalShape {
public:
Circle(); //default constructor
Circle( double r); //regular constructor
double getArea(); //get area function
};
class Square : public TwoDimensionalShape {
public:
Square();
Square(double dim);
double getArea();
};
class Triangle : public TwoDimensionalShape {
public:
Triangle();
Triangle(double dim, double dim2);
double getArea();
};
//three dimensional shape classes-------------------------
class Sphere : public ThreeDimensionalshape {
public:
Sphere();
Sphere(double dim);
double getArea();
double getVolume();
};
class Cube : public ThreeDimensionalshape{
public:
Cube();
Cube(double dim);
double getArea();
double getVolume();
};
class Tetrahedron : public ThreeDimensionalshape{
public:
Tetrahedron();
Tetrahedron(double dim);
double getArea();
double getVolume();
};
--
//---------------------------------------------------------
#include <stdlib.h>
#include <cmath.h>
#include "shape.h" //header file
using namespace std;
//----------------------------------------------
//Default constructor
Shape::Shape() : dimensions(0), area(0), volume(0) { }
//Regular constructor
Shape::Shape(int d) : {
dimensions = d;
}
//Function getDimensions
double Shape::getDimensions() {
return dimensions;
}
//Two dimensional shapes-----------------------------------
//Default constructor--------------------
Circle::Circle() {
d1 = 1 ;
}
//Regular constructor--------------------
Circle::Circle( double r ) {
d1 = r;
}
//Circle area
double Circle::getArea() {
area = PI * pow( d1, 2 );
return area;
}
//Default constructor--------------------
Square::Square() {
d1 = 1 ;
d2 = 1;
}
//Regular constructor--------------------
Square::Square( double dim ){
d1 = dim;
d2 = dim;
}
//Square area
double Square::getArea(){
area = pow( d1, 2 );
return area;
}
//Default constructor--------------------
Triangle::Triangle(){
d1 = 1;
d2 = 1;
}
//Regular constructor--------------------
Triangle::Triangle(double dim, double dim2){
d1 = dim;
d2 = dim2;
}
//Triangle area
double Triangle::getArea(){
area = (d1 * d2) / 2;
}
//Three dimensional shapes-----------------------------------
//Default constructor---------------------
Sphere::Sphere(){
d1 = 1;
d2 = 1;
d3 = 1;
}
//Regular constructor---------------------
Sphere::Sphere(double dim) : {
d1 = dim;
d2 = dim;
d3 = dim;
}
//Sphere area
double Sphere::getArea(){
area = 4 * PI * pow( d1, 2 );
return area;
}
//Sphere volume
double Sphere::getVolume(){
volume = (4/3) * PI * pow( d1, 3 );
return volume;
}
//Default constructor---------------------
Cube::Cube(){
d1 = 1;
d2 = 1;
d3 = 1;
}
//Regular constructor---------------------
Cube::Cube(double dim){
d1 = dim;
d2 = dim;
d3 = dim;
}
//Cube area
double Cube::getArea(){
area = pow( d1, 2 );
return area;
}
//Cube Volume
double Cube::getVolume(){
volume = pow( d1, 3 );
return volume;
}
//Default constructor---------------------
Tetrahedron::Tetrahedron(){
d1 = 1;
d2 = 1;
d3 = 1;
}
//Regular constructor---------------------
Tetrahedron::Tetrahedron(double dim){
d1 = dim;
d2 = dim;
d3 = dim;
}
//tetrahedron area
double Tetrahedron::getArea(){
area = sqrt(3) * pow( d1, 2);
return area;
}
//tetrahedron volume
double Tetrahedron::getVolume(){
volume = pow(d1, 3) / (6 * sqrt(2));
return volume;
}
--
/---------------------------------------------------------
#include <stdlib.h>
#include <cmath.h>
#include "shape.h" //header file
using namespace std;
int main() {
//Pointer Array--------------------------------------------
Shape* arr[6];
//Assign Shape Dimensions and to Array
Circle cir(2); //declares value for circle ~ cir is var name
arr[0] = &cir; //assigns cir var to array position 0
Square sqr(3);
arr[1] = &sqr;
Triangle tri(4, 2);
arr[2] = &tri;
Sphere sph(5);
arr[3] = &sph;
Cube cb(6);
arr[4] = &cb;
Tetrahedron trhd(7);
arr[5] = &trhd;
//Loop each index of array and perform calculation
for (int i = 0; i < 6; ++i)
{
cout << ""
}
}

I suggest to add something like toString method to your Shape class and try to override it in your inherited classes like :
Class Shape{
...
public:
std::string toString();
...
}
Implement and override it in the subclasses:
std::string Shape::toString()
{
return "This is a simple shape";
}
std::string Cube::toString()
{
return "Cube";
}
...
through the power of polymorphism, you will get the object name in your for loop just by calling:
cout << arr[i].toString() << ...

Related

How do I feed a function containing a vector with different data types with these different data types?

I am still struggling to realize what I want to do.
My code shall take user-defined segments (e.g. either a line, a circle, or whatever geometric segment definition I will implement) and chain them together in a vector. However, the order of segment type ("line", "circle",...) is user-defined and may hence vary from execution to execution.
Before I go on: Each segment has different input data needed for its own creation (e.g. a line has no radius, only starting and ending point).
My preferred approach would be to
read user input and identify order of segments
create each segment
Feed these to a function (e.g. member function/method for a class implementing the contour).
This function creates the contour, e.g. by implementing a vector.
My current test code has a hard-coded segment sequence but the trick that I want to achieve is that the order (and number) of segments is not hard-coded. Unfortunately I cannot figure out how.
Here's the code:
#include <iostream>
#include <vector>
struct point
{
double x;
double y;
};
class segment
{
public:
segment()
{
P1.x = 0;
P1.y = 0;
P2.x = 0;
P2.y = 0;
};
virtual ~segment() {};
virtual double get_radius() { return 0; };
virtual double get_length() { return 0; };
virtual double get_angle() { return 0; };
int segment_id = 0;
protected:
point P1;
point P2;
};
class Line : public segment
{
public:
Line() {};
Line(const point pt1, const point pt2)
{
P1.x = pt1.x;
P1.y = pt1.y;
P2.x = pt2.x;
P2.y = pt2.y;
segment_id = 1;
};
~Line() {};
double get_length() { return calc_length(); };
double get_angle() { return calc_angle(); };
private:
double calc_length()
{
// calculate length (here: dummy value)
return 1;
}
double calc_angle()
{
// calculate angle (here: dummy value)
return 0.5;
}
double length = 0;
double angle = 0;
}
;
class circle : public segment
{
public:
circle()
{
center.x = 0;
center.y = 0;
};
circle(const double r, const point c)
{
radius = r;
center.x = c.x;
center.y = c.y;
segment_id = 2;
};
~circle() {};
double get_radius() { return radius; };
point get_center() { return center; };
double get_length() { return 3.14 * radius; }; //returns circumference
private:
double radius = 0;
point center;
};
//-------------------------------------------------------
int main()
{
int nbr = 5;
point start;
start.x = 1;
start.y = 2;
point end;
end.x = 3;
end.y = 4;
point c;
c.x = 0;
c.y = 0;
double r = 9;
auto anotherCircle = std::make_unique<circle>(r, c);
auto anotherLine = std::make_unique<Line>(start, end);
std::unique_ptr<circle> yet_anotherCircle;
circle* myCircle = new circle(r, c);
Line* myLine = new Line(start, end);
//VERSION 1: Does not compile. I get an exception in <memory> line 1762 when trying to delete _Ptr
//std::vector<std::unique_ptr<segment>> v1;
//v1.emplace_back(anotherCircle);
//v1.emplace_back(anotherLine);
//std::cout << v1[0]->get_radius() << std::endl;
//v1.emplace_back(myLine);
//std::cout << v1[1]->segment_id << std::endl;
//VERSION 2: Compiles
std::vector<std::unique_ptr<segment>> v2;
v2.emplace_back(std::make_unique<circle>(r, c));
v2.emplace_back(std::make_unique<Line>(start, end));
}
The straight forward way that I imagine but that does not seem to work would require version 1 to work. I could then probably use template objects that I feed into the vector. Unfortunately this is not the way to go and I have not the slightest idea how to approach this. It would be awesome if somebody could help me here! Thanks!
You need to move items in vector, as your items are no copyable:
v1.emplace_back(std::move(anotherCircle));

Undefined Reference to vtable with abstract class

When building my C++ program, I'm getting the error message.
undefined reference to vtable
I have two virtual abstract classes called and I can't quite figure out what I'm doing wrong if I'm doing anything wrong.
I'm getting errors from both of the classes that are inheriting from the abstract class.
My abstract class is
undefined reference to `vtable for hittable_list'
undefined reference to `vtable for sphere'
hittable.h
#ifndef HITTABLE_H
#define HITTABLE_H
#include "ray.h"
struct hit_record {
hit_record() {}
~hit_record() {}
float t;
vecfloat p;
vecfloat normal;
float MAXFLOAT = 100.0;
};
//Abstract Class containing Sphere and hittablelist
class hittable
{
public:
virtual ~hittable() = 0;
virtual bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const = 0;
};
#endif
Classes inherting from my abstract class are.
sphere.h
#ifndef SPHERE_H
#define SPHERE_H
#include "hittable.h"
class sphere : public hittable
{
public:
sphere() {}
~sphere() {}
sphere(vecfloat cen, float r) : center(cen), radius(r) {}
bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const;
protected:
vecfloat center;
float radius;
};
#endif
sphere.cc
#include "include/sphere.h"
bool sphere::hit(const ray &r, float t_min, float t_max, hit_record &rec) const
{
vecfloat oc = r.origin() - center;
float a = oc.dot_product(r.direction());
float b = oc.dot_product(oc) - radius * radius;
float c = oc.dot_product(oc) - radius * radius;
float discriminant = b * b - a * c;
if (discriminant > 0)
{
float temp = (-b - sqrt(b * b - a * c)) / a;
if (temp < t_max && temp > t_min)
{
rec.t = temp;
rec.p = r.point_at_parameter(rec.t);
rec.normal = (rec.p - center) / radius;
return true;
}
temp = (-b + sqrt(b * b - a * c)) / a;
if (temp < t_max && temp > t_min)
{
rec.t = temp;
rec.p = r.point_at_parameter(rec.t);
rec.normal = (rec.p - center) / radius;
return true;
}
}
return false;
}
hittable.h
#ifndef HITTABLELIST_H
#define HITTABLELIST_H
#include "hittable.h"
class hittable_list : public hittable
{
public:
hittable_list() {}
hittable_list(hittable **l, int n)
{
list = l;
list_size = n;
}
bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const;
~hittable_list() {}
protected:
hittable **list;
int list_size;
};
#endif
hittable.cc
#include "include/hittablelist.h"
bool hittable_list::hit(const ray &r, float t_min, float t_max, hit_record &rec) const
{
hit_record temp_rec;
auto hit_anything = false;
auto closet_so_far = t_max;
for (int i = 0; i < list_size; i++)
{
if (list[i]->hit(r, t_min, closet_so_far, temp_rec))
{
hit_anything = true;
closet_so_far = temp_rec.t;
rec = temp_rec;
}
}
return hit_anything;
}
Solution
Change
virtual ~hittable() = 0;
into
virtual ~hittable() = default;
or
virtual ~hittable()
{
// does nothing
}
The destructor can remain pure virtual, but it must have a definition.
hittable::~hittable()
{
// does nothing
}
So what happened?
We can crush the given code down to the following example (Note I can't reproduce the missing vtable with this code or the given code, but regardless, the above will fix it)
Minimal example:
class hittable
{
public:
virtual ~hittable() = 0; // here we have a destructor,
// but there's no implementation
// so there is nothing for the
// destructors of derived classes
// to call
virtual bool hit() const = 0;
};
class sphere: public hittable
{
public:
bool hit() const;
};
bool sphere::hit() const
{
return false;
}
destructors call any base class destructors, and when shpere goes to call ~hittable, it finds that while ~hittableis declared, there is no implementation. Nothing to call.

pointer array of parent class having a pure virtual function and object type of pointer array

here in the main function i want to make a pointer array. object type should change every time.
Something like this.
shape* a[10]=new rectangle;
but i want to make a[0] rectangle type. a[1] circle type and so on.
class shape
{
public:
virtual float boundary_length()=0;
};
class rectangle: public shape
{
public:
float boundary_length()
{
cout<<"Boundary length of rectangle"<<endl;
return 2*(length+width);
}
};
class circle: public shape
{
public:
float boundary_length()
{
return 2*(3.14*radius);
}
};
class triangle: public shape
{
float boundary_length()
{
return (base+perp+hyp);
}
};
int main()
{
shape* a=new rectangle;
return 0;
}
If I have understood you correctly you need something like the following
#include <iostream>
class shape
{
public:
virtual float boundary_length() const = 0;
virtual ~shape() = default;
};
class rectangle: public shape
{
public:
rectangle( float length, float width ) : length( length ), width( width )
{
}
float boundary_length() const override
{
return 2*(length+width);
}
protected:
float length, width;
};
class circle: public shape
{
public:
circle( float radius ) : radius( radius )
{
}
float boundary_length() const override
{
return 2*(3.14*radius);
}
private:
float radius;
};
//...
int main(void)
{
const size_t N = 10;
shape * a[N] =
{
new rectangle( 10.0f, 10.0f ), new circle( 5.0f )
};
for ( auto s = a; *s != nullptr; ++s )
{
std::cout << ( *s )->boundary_length() << '\n';
}
for ( auto s = a; *s != nullptr; ++s )
{
delete *s;
}
}
The program output is
40
31.4

Nesting Inheritance LNK2001 and LNK1120 error

My code isn't working. I'm trying simple inheritance Shape as base class and two classes under Shape "Two Dimension" and "Three Dimension" and shapes under that classes. Here's my code but when I try to define a new class as Triangle it gives me error LNK2001 LNK1120. It looks complicated but I must get area, volume and perimeter for every each object.
My full error:
Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol "public: virtual double __thiscall TwoDimensionShape::Area(void)" (?Area#TwoDimensionShape##UAENXZ) Shape c:\Users\aleyn\documents\visual studio 2015\Projects\Shape\Shape\Source.obj 1
That's .h
#pragma once
#define M_PI 3.14159265358979323846
class Shape
{
private:
double width, height, depth;
public:
Shape(double w, double h, double d);
virtual void Display() = 0;
virtual double Area() = 0;
virtual double Perimeter() = 0;
virtual double Volume() = 0;
};
class TwoDimensionShape: public Shape
{
public:
TwoDimensionShape(double w, double h, double d = 0) :
Shape(w, h, d)
{
}
double Area();
double Perimeter();
double Volume();
void Display();
};
class ThreeDimensionShape: public Shape
{
private:
double width, height, depth;
public:
ThreeDimensionShape(double w, double h, double d) :
Shape(w, h, d)
{
depth = d;
}
double Area();
double Volume();
double Perimeter();
void Display();
};
class Triangle: public TwoDimensionShape
{
private:
double side1, side2, base;
public:
Triangle(double w, double h, double d = 0) :
TwoDimensionShape(w, h, d)
{
}
double Area()
{
return Area() / 2;
}
void setTriangleSides(double s1, double s2, double b);
double Perimeter()
{
return side1, side2, base;
}
double Volume()
{
return 0;
}
};
class Square: public TwoDimensionShape
{
public:
Square(double w, double h, double d = 0) :
TwoDimensionShape(w, h, d)
{
}
double Volume()
{
return 0;
}
};
class Rectangle: public TwoDimensionShape
{
public:
Rectangle(double w, double h, double d = 0) :
TwoDimensionShape(w, h, d)
{
}
double Volume()
{
return 0;
}
};
class Circle: public TwoDimensionShape
{
private:
double radius;
public:
Circle(double r, double a = 0, double d = 0) :
TwoDimensionShape(r, a, d)
{
radius = r;
}
double Area()
{
return M_PI * (radius) * (radius);
}
double Perimeter()
{
return 2 * M_PI * radius;
}
double Volume()
{
return 0;
}
};
class Sphere: public ThreeDimensionShape
{
private:
double radius;
public:
Sphere(double r, double a = 0, double b = 0) :
ThreeDimensionShape(r, a, b)
{
radius = r;
}
double Volume()
{
return (4 / 3 * M_PI * (radius * radius * radius));
}
double Area()
{
return 4 * M_PI * radius * radius;
}
double Perimeter()
{
return 0;
}
};
class Cylinder: public ThreeDimensionShape
{
private:
double radius, height;
public:
Cylinder(double r, double h, double a = 0) :
ThreeDimensionShape(r, h, a)
{
}
double Volume()
{
return M_PI * radius * radius * height;
}
double Area()
{
return (2 * M_PI * radius * height) + 2 * M_PI * radius * radius;
}
double Perimeter()
{
return 0;
}
};
class Cone: public ThreeDimensionShape
{
private:
double radius, height, side;
public:
Cone(double r, double h, double s) :
ThreeDimensionShape(r, h, s)
{
}
double Volume()
{
return 1 / 3 * M_PI * radius * radius * height;
}
double Area()
{
return (M_PI * radius * side) + M_PI * radius * radius;
}
double Perimeter()
{
return 0;
}
};
class RectPrism: public ThreeDimensionShape
{
public:
RectPrism(double w, double h, double d) :
ThreeDimensionShape(w, h, d)
{
}
double Area();
double Volume();
double Perimeter();
};
my .cpp
#include "Shape.h"
#include <iostream>
using namespace std;
Shape::Shape(double w, double h, double d)
{
width = w;
height = h;
depth = d;
}
double Shape::Area()
{
return width * height;
}
double Shape::Perimeter()
{
return (width + height) * 2;
}
double Shape::Volume()
{
return width * height * depth;
}
double ThreeDimensionShape::Area()
{
return (2 * (height * width) + 2 * (depth * width) + 2 * (depth * height));
}
double ThreeDimensionShape::Volume()
{
return width * height * depth;
}
double ThreeDimensionShape::Perimeter()
{
return (4 * width + 4 * height + 4 * depth);
}
void Triangle::setTriangleSides(double s1, double s2, double b)
{
side1 = s1;
side2 = s2;
base = b;
}
void TwoDimensionShape::Display()
{
cout << "Perimeter: " << Perimeter() << endl;
cout << "Area: " << Area() << endl;
cout << "Volume: " << Volume() << endl;
}
main .cpp
#include <iostream>
#include "Shape.h"
using namespace std;
int main()
{
Triangle t1(8, 5, 0);
system("pause");
return 0;
}
the error message says it all
LNK2001 unresolved external symbol "public: virtual double __thiscall TwoDimensionShape::Area(void)"
You have not written TwoDimenionalShape::Area
In your header file you promised to write one, but you didnt

how to resolve an ambigious base class in c++

Both base classes, Arc and Lines, are derived from class Shape.
The compiler says Ojbect b1 "error: shape is ambiguous". I know that two instances of Shape are being created, but don't know how to resolve it?
Graph_lib::Box b1(Point,100,100), 100,100);
win1.attach(b1);
This class will be able to draw a box with rounded corners. I just wrote the code for the Box Lines part, I didn't get to the Arc yet since this won't even work.
//------------------------------------------------------------------------------
struct Box : Lines , Arc {
Box(Point xy, int ww, int hh);
void Top_segment();
void Bottom_segment();
void Left_side_segment();
void Right_side_segment();
void draw_lines() const;
int height() const { return h; }
int width() const { return w; }
private:
int h; // height
int w; // width
double width_tenth; //10% of the width that will calculate the length to remove from each side to make room for the arcs
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Box::Box(Point xy, int ww, int hh): w(ww), h(hh)
{
width_tenth = (xy.x + w) * 0.10;
if (h<=0 || w<=0) error("Bad box: non-positive side");
}
//------------------------------------------------------------------------------
void Box::Top_segment()
{
double top_seg_begin_w; //where the line segment will begin after deducting 10% of w;
double top_seg_end_w; //where the line segment will end after deducting 10% of w;
top_seg_begin_w = xy.x + width_tenth;
top_seg_end_w = (xy.x + w) - width_tenth;
Lines::add(Point(top_seg_begin_w,xy.y),Point(top_seg_end_w,xy.y));
}
//------------------------------------------------------------------------------
void Box::Bottom_segment()
{
double bottom_seg_begin_w;
double bottom_seg_end_w;
bottom_seg_begin_w = xy.x + width_tenth;
bottom_seg_end_w = (xy.x + w) - width_tenth;
double y_bottom = xy.y + h;
Lines::add(Point(bottom_seg_begin_w,y_bottom),Point(bottom_seg_end_w,y_bottom));
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Box::Left_side_segment()
{
double left_seg_begin_h;
double left_seg_end_h;
left_seg_begin_h = xy.y + width_tenth;
left_seg_end_h = (xy.y + h) - width_tenth;
double x_left = xy.x;
Lines::add(Point(x_left,left_seg_begin_h),Point(x_left,left_seg_end_h));
}
//------------------------------------------------------------------------------
void Box::Right_side_segment()
{
double right_seg_begin_h;
double right_seg_end_h;
right_seg_begin_h = xy.y + width_tenth;
right_seg_end_h = (xy.y + h) - width_tenth;
double x_right = xy.x + w;
Lines::add(Point(x_right,right_seg_begin_h),Point(x_right,right_seg_end_h));
}
//------------------------------------------------------------------------------
Use virtual inheritance for classes Lines and Arc. For example
class Lines : virtual public Shape
{
//...
};
class Arc : virtual public Shape
{
//...
};