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.
Related
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
I am trying to figure out how to find the axis of class Square's axis as shown below? But I've been trying for hours and still did not managed to solve it. Can someone with their high level expertise show me the ropes to do it? Because both center function call and axis function call in main() does call the same x() and y(), hence brought me to a state of confusion. I know the inheritance of square from circle is weird. But it is what my school wants. Note: Main() CANNOT be modified! Thanks!
Output:
Square::axis test failed
8.87627 0.284967
3.82567 0.958537
Tests passed: 50%
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
class Object
{
public:
private:
float d;
public:
Object(float n) : d(n){}
Object(){}
float depth() const
{
return d;
}
struct PointType
{
float x2;
float y2;
PointType( float x1, float y1) :x2(x1),y2(y1){}
PointType(){}
float x()
{
return x2;
}
float y()
{
return y2;
}
PointType center()
{
return *this;
}
};
struct VectorType
{
float tx;
float ty;
VectorType( float tx1, float ty1) :tx(tx1),ty(ty1){}
VectorType( ){}
};
virtual ~Object()
{}
};
class Point :public Object
{
private:
PointType mpoint;
public:
Point(const PointType& pt, float& y1) :Object(y1), mpoint(pt) {}
Point(const PointType& pt):mpoint(pt){}
Point(){}
Point center() const
{
return *this;
}
float x()
{
return mpoint.x2;
}
float y()
{
return mpoint.y2;
}
virtual ~Point(){}
};
class Circle : public Point
{
private:
Object::PointType m_pt;
float r;
public:
Circle(const PointType pts, float rad, float dep)
: Point(m_pt,dep),m_pt(pts),r(rad) {}
Circle(const PointType pts, float rad):m_pt(pts),r(rad){}
Circle(){}
float radius() const
{
return r;
}
Circle center() const
{
return *this;
};
float x()
{
return m_pt.x2;
}
float y()
{
return m_pt.y2;
}
};
class Square: public Circle
{
private:
Object::PointType s_pt;
Object::VectorType v_pt;
float a=getRadius();
public:
Square(const PointType spts,const VectorType vpts,float depth) :
Circle(spts,a,depth),s_pt(spts),v_pt(vpts){}
Square(const Object::PointType& spts, const VectorType vpts):s_pt(spts),v_pt(vpts){}
Square axis() const
{
return Square(s_pt,v_pt,getRadius());
}
Square center() const
{
return *this;
}
float radius() const
{
return a;
}
float getRadius() const
{
float rad= sqrt(v_pt.tx * v_pt.tx + v_pt.ty * v_pt.ty);
return rad;
}
float x() const
{
return s_pt.x2;
// v_pt.tx/radius();
}
float y() const
{
return s_pt.y2;
// v_pt.ty/radius();
}
};
const float EPSILON = 1e-5f;
bool is_near(float x, float y)
{
return std::abs(x - y) < EPSILON;
}
float frand()
{
return 10.0f * float(rand()) / float(RAND_MAX);
}
int main()
{
srand(unsigned(time(0)));
int count = 0;
int max_count = 0;
float x = frand();
float y = frand();
float sx = frand();
float sy = frand();
float depth = frand();
Square square(Square::PointType(x, y), Square::VectorType(sx, sy), depth);
if (is_near(square.center().x(), x) &&
is_near(square.center().y(), y))
{
++count;
}
else
{
std::cout << " - Square::center test failed" << std::endl;
}
++max_count;
float radius = std::sqrt(sx * sx + sy * sy);
if (is_near(square.axis().x(), sx / radius) &&
is_near(square.axis().y(), sy / radius))
{
++count;
}
else
{
std::cout << " - Square::axis test failed" << std::endl;
}
++max_count;
std::cout << square.axis().x()<< " " << sx / radius<<std::endl;
std::cout << square.axis().y()<< " " << sy / radius<<std::endl;
int result = static_cast<int>(
100.0f * static_cast<float>(count) / static_cast<float>(max_count) + 0.5f
);
std::cout << "Tests passed: " << result << "%" << std::endl;
return result;
}
When I try to compile the following code:
Alien::Action::Action(ActionType type, float x, float y) {
Action::type = type;
pos = Vec2(x, y);
}
Alien::Alien(float x, float y, int nMinions) {
srand(time(NULL));
sp = Sprite("img/alien.png");
box = Rect(x, y, sp.GetWidth(), sp.GetHeight());
box.x = x - box.h/2;
box.y = y - box.w/2;
hitpoints = 100;
speed.x = 0.5;
speed.y = 0.5;
minionArray = std::vector<Minion>();
for(int i = 0; i < nMinions; i++) {
int a = rand()%501;
float b = a/1000.0;
float c = b+1;
minionArray.emplace_back(Minion(get(), i*(360/nMinions), c));
}
taskQueue = std::queue<Action>();
}
The IDE (Eclipse) gives the following error message: "undefined reference to 'vtable for Alien'" (line 6 of the code). Since there's no virtual method inside Alien, I don't know the cause of the error. The following is the header file for Alien:
#ifndef ALIEN_H_
#define ALIEN_H_
#include "GameObject.h"
class Alien: public GameObject {
private:
class Action {
public:
enum ActionType {MOVE, SHOOT};
ActionType type;
Action(ActionType type, float x, float y);
Vec2 pos;
};
int hitpoints;
std::queue<Action> taskQueue;
std::vector<Minion> minionArray;
public:
Alien(float x, float y, int nMinions);
~Alien();
void Update(float dt);
void Render();
Alien* get();
bool IsDead();
};
#endif
The code for GameObject is :
#include "GameObject.h"
#include "InputManager.h"
#include "Camera.h"
#include "State.h"
GameObject::~GameObject() {
}
GameObject* GameObject::get() {
return this;
}
Minion::~Minion() {
}
Minion::Minion(GameObject* minionCenter, float arcOffset, float minionSize) {
sp = Sprite("img/minion.png");
center = minionCenter;
translation = arcOffset;
box = Rect(center->box.GetCenter().x+(cos(translation*M_PI/180)*200)-(sp.GetWidth()/2),
center->box.GetCenter().y+(sin(translation*M_PI/180)*200)-(sp.GetHeight()/2),
sp.GetWidth(), sp.GetHeight());
}
void Minion::Shoot(Vec2 pos) {
State::AddObject(new BulletWheel(box.GetCenter().x, box.GetCenter().y, center->box.GetCenter().GetDX(pos.x),
center->box.GetCenter().GetDY(pos.y), center->box.GetCenter().GetDS(pos), 0.3,
translation, center->box.GetCenter(), "img/minionbullet1.png"));
}
void Minion::Update(float dt) {
if(translation < 360)
translation += 0.03*dt;
else
translation += 0.03*dt-360;
/*rotation = translation-90;*/
if(rotation < 360)
rotation += 0.15*dt;
else
rotation += 0.15*dt-360;
box.x = center->box.GetCenter().x+(200*cos((translation)*M_PI/180))-(box.w/2);
box.y = center->box.GetCenter().y+(200*sin((translation)*M_PI/180))-(box.h/2);
}
void Minion::Render() {
sp.Render(box.x - Camera::GetInstance().pos.x, box.y - Camera::GetInstance().pos.y, rotation);
}
bool Minion::IsDead() {
return false;
}
Bullet::Bullet(float x, float y, float dx, float dy, float maxDistance, float speed, std::string sprite) {
sp = Sprite(sprite);
box = Rect(x-(sp.GetWidth()/2), y-(sp.GetHeight()/2), sp.GetWidth(), sp.GetHeight());
Bullet::speed = Vec2(speed*(dx/maxDistance), speed*(dy/maxDistance));
distanceLeft = maxDistance;
rotation = atan2(dy, dx)*(180/M_PI);
}
void Bullet::Update(float dt) {
if(distanceLeft > 0) {
box.x += speed.x*dt;
box.y += speed.y*dt;
distanceLeft -= pow(pow(speed.x*dt,2)+pow(speed.y*dt,2),0.5);
}
}
void Bullet::Render() {
sp.Render(box.x - Camera::GetInstance().pos.x, box.y - Camera::GetInstance().pos.y, rotation);
}
bool Bullet::IsDead() {
return (distanceLeft < 1) ? true : false;
}
Bullet* Bullet::get() {
return this;
}
BulletWheel::BulletWheel(float x, float y, float dx, float dy, float maxDistance, float speed, float arcOffset, Vec2 center, std::string sprite) {
sp = Sprite(sprite);
sp.SetScaleX(2);
sp.SetScaleY(2);
box = Rect(x-(sp.GetWidth()/2), y-(sp.GetHeight()/2), sp.GetWidth(), sp.GetHeight());
BulletWheel::speed = Vec2(speed*(dx/maxDistance), speed*(dy/maxDistance));
distanceLeft = maxDistance;
rotation = atan2(dy, dx)*(180/M_PI);
translation = arcOffset;
BulletWheel::center = center;
}
void BulletWheel::Update(float dt) {
if(translation < 360)
translation += 0.1*dt;
else
translation += 0.1*dt-360;
if(distanceLeft > 0.01) {
center.x += speed.x*dt;
center.y += speed.y*dt;
box.x = center.x+(200*cos((translation)*M_PI/180))-(box.w/2);
box.y = center.y+(200*sin((translation)*M_PI/180))-(box.h/2);
distanceLeft -= pow(pow(speed.x*dt,2)+pow(speed.y*dt,2),0.5);
}
}
void BulletWheel::Render() {
sp.Render(box.x - Camera::GetInstance().pos.x, box.y - Camera::GetInstance().pos.y, rotation);
}
bool BulletWheel::IsDead() {
return distanceLeft < 1;
}
BulletWheel* BulletWheel::get() {
return this;
}
and its header file is:
#ifndef GAMEOBJECT_H_
#define GAMEOBJECT_H_
#include "Sprite.h"
#include "Rect.h"
#include "Vec2.h"
#include <queue>
#include <vector>
#include <cmath>
#include <ctime>
class GameObject{
private:
public:
virtual ~GameObject();
virtual void Update(float dt) = 0;
virtual void Render() = 0;
virtual bool IsDead() = 0;
virtual GameObject* get();
int rotation = 0;
int translation = 0;
Sprite sp = Sprite();
Vec2 speed = Vec2();
Rect box = Rect();
};
class Minion : public GameObject {
private:
GameObject* center;
public:
Minion(GameObject* minionCenter, float arcOffset, float minionSize = 1);
~Minion();
void Shoot(Vec2 pos);
void Update(float dt);
void Render();
bool IsDead();
Minion* get();
};
class Bullet : public GameObject {
private:
float distanceLeft;
public:
Bullet(float x, float y, float dx, float dy, float maxDistance, float speed, std::string sprite);
void Update(float dt);
void Render();
bool IsDead();
Bullet* get();
};
class BulletWheel : public GameObject {
private:
float distanceLeft;
Vec2 center;
public:
BulletWheel(float x, float y, float dx, float dy, float maxDistance, float speed, float arcOffset, Vec2 center, std::string sprite);
void Update(float dt);
void Render();
bool IsDead();
BulletWheel* get();
};
#endif /* GAMEOBJECT_H_ */
There are the virtual functions of GameObject, declared inside Alien.cpp:
void Alien::Update(float dt) {
if(rotation > 0)
rotation -= 0.1*dt;
else
rotation -= 0.1*dt+360;
if(InputManager::GetInstance().MousePress(RIGHT_MOUSE_BUTTON)) {
taskQueue.push(Action(Action::MOVE,(InputManager::GetInstance().GetMouseX() + Camera::GetInstance().pos.x - (box.w/2)),
(InputManager::GetInstance().GetMouseY() + Camera::GetInstance().pos.y - (box.h/2))));
}
if(InputManager::GetInstance().MousePress(LEFT_MOUSE_BUTTON)) {
taskQueue.push(Action(Action::SHOOT,(InputManager::GetInstance().GetMouseX() + Camera::GetInstance().pos.x),
(InputManager::GetInstance().GetMouseY() + Camera::GetInstance().pos.y)));
}
if(taskQueue.size() > 0) {
Vec2 pos = taskQueue.front().pos;
if(taskQueue.front().type == Action::MOVE) {
float cos = (box.GetDX(pos.x)/box.GetDS(pos));
float sin = (box.GetDY(pos.y)/box.GetDS(pos));
if(cos != cos) {
cos = 0;
}
if(sin != sin) {
sin = 0;
}
if((box.x+speed.x*cos*dt > pos.x && pos.x > box.x) || (box.x+speed.x*cos*dt < pos.x && pos.x < box.x)) {
box.x = pos.x;
}
else {
box.x += speed.x*cos*dt;
}
if((box.y+speed.y*sin*dt > pos.y && pos.y > box.y) || (box.y+speed.y*sin*dt < pos.y && pos.y < box.y)) {
box.y = pos.y;
}
else {
box.y += speed.y*sin*dt;
}
if(box.x == pos.x && box.y == pos.y) {
taskQueue.pop();
}
}
else {
for(unsigned i = 0; i < minionArray.size(); i++) {
minionArray.at(i).Shoot(pos);
taskQueue.pop();
}
}
}
for(unsigned i = 0; i < minionArray.size(); i++) {
minionArray.at(i).Update(dt);
}
}
void Alien::Render() {
sp.Render(box.x - Camera::GetInstance().pos.x, box.y - Camera::GetInstance().pos.y, rotation);
if(minionArray.size() > 0) {
for(unsigned i = 0; i < Alien::minionArray.size(); i++) {
minionArray.at(i).Render();
}
}
}
bool Alien::IsDead() {
return (Alien::hitpoints <= 0);
}
EDIT: the destructor of Alien was missing.
All classes derived from GameObject must define all pure virtual functions in GameObject. In your case, this is:
virtual void Update(float dt) = 0;
virtual void Render() = 0;
virtual bool IsDead() = 0;
Here is a similar question with more information. Hope this helps!
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] = ○ //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() << ...
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
{
//...
};