Someone recommended me to use boost::variant as shape variable to store different types of shapes in it. But, when implemented boost::variant to my code, I got an error while compiling. Error says: 'Shape': base class undefined and more errors.
Here is my code (Object.h):
using Shape = boost::variant<Rectangle, Circle>;
enum Shape_Type
{
RECTANGLE,
CIRCLE
};
struct Position
{
float x, y;
Position(float position_x, float position_y)
{
x = position_x;
y = position_y;
}
};
class Object : private Shape
{
private:
std::string name;
public:
Object() = default;
Object(std::string name, Rectangle rectangle) : name(name), Shape(rectangle)
{
}
Object(std::string name, Circle circle) : name(name), Shape(circle)
{
}
void setPosition(float, float);
void setAngle(float);
Shape* getShape()
{
Shape* shape = this;
return shape;
}
Position getPosition();
const std::string* getName()
{
return &name;
}
};
class Rectangle
{
private:
sf::RectangleShape rectangleshape;
public:
Rectangle() = default;
Rectangle(float width, float height)
: rectangleshape(sf::RectangleShape(sf::Vector2f(width, height)))
{
}
void setPosition(float position_x, float position_y)
{
rectangleshape.setPosition(position_x, position_y);
}
void setAngle(float angle)
{
rectangleshape.setRotation(angle);
}
sf::RectangleShape* getRectangleShape()
{
return &rectangleshape;
}
Position getPosition()
{
return Position(rectangleshape.getPosition().x,
rectangleshape.getPosition().y);
}
};
class Circle
{
private:
sf::CircleShape circleshape;
public:
Circle() = default;
Circle(std::string name, float radius)
: circleshape(sf::CircleShape(radius))
{
}
void setPosition(float position_x, float position_y)
{
circleshape.setPosition(position_x, position_y);
}
void setAngle(float angle)
{
circleshape.setRotation(angle);
}
sf::CircleShape* getCircleShape()
{
return &circleshape;
}
Position getPosition()
{
return Position(circleshape.getPosition().x,
circleshape.getPosition().y);
}
};
And btw is getShape() function good?
Variants are used for static polymorphism, so you don't need the base class at all (that's dynamic - or virtual - polymorphism).
The members in a variant typically do not share a common base class, so you wouldn't have the getShape function, or you'd need to template it:
template <typename T>
T const& getShape() const { return boost::get<T>(_shape); }
Related
I am trying to make all my classes to be generic.But the issue arose with class Circle and the ones following right after it.Where am I making a mistake?
It seems to work when I exchange them for "int". But that seems to fail my original needs of having the classes be generic.
class DrawableObject
{
public:
virtual void print()=0;
};
template <typename T>
class Point : public DrawableObject
{
T x;T y;
public:
Point()
{ x=0;
y=0;
}
Point(T a)
{ x=a;
y=a;
}
Point(T a,T b)
{ x=a;
y=b;
}
void setX(T newX)
{
x=newX;
}
void setY(T newY)
{
y=newY;
}
T getX()
{ return x;
}
T getY()
{ return y;}
void print()
{ cout<<"(X,Y) Coordinates are ("<<x<<","<<y<<")"<<endl;}
};
template <typename U>
class Rectangle : public Point<U>
{
U width,height;
public:
Rectangle()
{ width=0;
height=0;
}
Rectangle(U a)
{ width=a;
height=a;
}
Rectangle(U a,U b)
{ width=a;
height=b;
}
void setWidth(U newWidth)
{ width=newWidth;}
void setHeight(U newHeight)
{ height=newHeight;}
U getHeight()
{ return height;}
U getWidth()
{ return width;}
void print()
{ cout<<"Rectangle is of area "<<width<<"X"<<height<<endl;}
};
Issue arises from here onwards
template <typename V>
class Circle : public Point<V>
{
V radius;
public:
Circle():Point()
{
radius=0;
}
Circle(V a):Point(a)
{
radius=a;
}
Circle(V a,V b,V c):Point(a,b)
{
radius=c;
}
void setRadius(V newRadius)
{radius=newRadius;}
V getRadius()
{return radius;}
void print()
{cout<<"Circle with centre at ("<<getX()<<","<<getY()<<") and of radius "<<radius<<endl;}
};
Error appears like this one below.
oops_case_study.cpp: In constructor ‘Circle<V>::Circle()’:
oops_case_study.cpp:81:12: error: class ‘Circle<V>’ does not have any field named ‘Point’
Circle():Point()
^~~~~
When you call the base class constructor from the derived constructor you also need to specify the template parameter for the bases class, like below.
Circle() : Point<V>()
{
radius=0;
}
note that Point's constructor is called like Point<V>()
I've got the following code currently (not working):
#include <iostream>
#include <vector>
class Circle;
class Rectangle;
class Shape {
private:
Shape() {};
public:
virtual ~Shape() {};
friend class Circle;
friend class Rectangle;
};
class Creator {
public:
virtual ~Creator() {};
virtual Shape* create() = 0;
virtual bool equals(Shape& s) { return false; };
};
class Circle : public Shape {
private:
Circle() : Shape() {};
public:
class CircleCreator : public Creator {
public:
virtual Shape* create() { return new Circle(); };
virtual bool equals(Shape& other_shape) { return false; };
};
};
class Rectangle : public Shape {
private:
Rectangle() : Shape() {};
public:
class RectangleCreator : public Creator {
public:
virtual Shape* create() { return new Rectangle(); };
virtual bool equals(Shape& other_shape) { return false; };
};
};
int main() {
/* First step, build the list */
std::vector<Shape*> shapeList;
std::vector<Shape*>::iterator it;
Rectangle::RectangleCreator rc;
Circle::CircleCreator cc;
Shape* s = cc.create();
Shape* s1 = rc.create();
shapeList.push_back(s);
shapeList.push_back(s1);
/* Second step: check if we've got a shape starting from a creator */
for (it = shapeList.begin(); it != shapeList.end(); ++it) {
if (rc.equals(**it)) {
std::cout << "same shape" << std::endl;
}
}
return 0;
}
My goal is to use a factory pattern and avoid the creation of a new object if in a list I've got already that object. I tried to use a double dispatch pattern but it isn't easy to apply in this case. How can I do?
Edit: Since the code is used in a "critical" path, I want to avoid RTTI like dynamic_cast and so on.
Maybe something like this could do it using member variables
#include <iostream>
#include <vector>
enum
{
CIRCLE,
RECTANGLE
};
class Circle;
class Rectangle;
class Shape {
private:
Shape() {};
public:
unsigned shapeType;
virtual ~Shape() {};
friend class Circle;
friend class Rectangle;
};
class Creator {
public:
unsigned shapeType;
virtual ~Creator() {};
virtual Shape* create() = 0;
bool equals(Shape& s) { return (this->shapeType == s.shapeType); };
};
class Circle : public Shape {
private:
Circle() : Shape() {shapeType=CIRCLE;};
public:
class CircleCreator : public Creator {
public:
CircleCreator() {shapeType=CIRCLE;};
virtual Shape* create() { return new Circle(); };
};
};
class Rectangle : public Shape {
private:
Rectangle() : Shape() {shapeType=RECTANGLE;};
public:
class RectangleCreator : public Creator {
public:
RectangleCreator() {shapeType=RECTANGLE;};
virtual Shape* create() { return new Rectangle(); };
};
};
int main() {
/* First step, build the list */
std::vector<Shape*> shapeList;
std::vector<Shape*>::iterator it;
Rectangle::RectangleCreator rc;
Circle::CircleCreator cc;
Shape* s = cc.create();
Shape* s1 = rc.create();
shapeList.push_back(s);
shapeList.push_back(s1);
/* Second step: check if we've got a shape starting from a creator */
for (it = shapeList.begin(); it != shapeList.end(); ++it) {
if (rc.equals(**it)) {
std::cout << "same shape" << std::endl;
}
}
return 0;
}
or this - using virtual function to return type
#include <iostream>
#include <vector>
enum
{
CIRCLE,
RECTANGLE,
UNKNOWN
};
class Circle;
class Rectangle;
class Shape {
private:
Shape() {};
public:
virtual ~Shape() {};
friend class Circle;
friend class Rectangle;
virtual unsigned iAmA(){return UNKNOWN;};
};
class Creator {
public:
virtual ~Creator() {};
virtual Shape* create() = 0;
virtual bool equals(Shape& s) { return false; };
};
class Circle : public Shape {
private:
Circle() : Shape() {};
virtual unsigned iAmA(){return CIRCLE;};
public:
class CircleCreator : public Creator {
public:
CircleCreator() {};
virtual Shape* create() { return new Circle(); };
virtual bool equals(Shape& other_shape) { return (CIRCLE == other_shape.iAmA()); };
};
};
class Rectangle : public Shape {
private:
Rectangle() : Shape() {};
virtual unsigned iAmA(){return RECTANGLE;};
public:
class RectangleCreator : public Creator {
public:
RectangleCreator() {};
virtual Shape* create() { return new Rectangle(); };
virtual bool equals(Shape& other_shape) { return (RECTANGLE == other_shape.iAmA()); };
};
};
int main() {
/* First step, build the list */
std::vector<Shape*> shapeList;
std::vector<Shape*>::iterator it;
Rectangle::RectangleCreator rc;
Circle::CircleCreator cc;
Shape* s = cc.create();
Shape* s1 = rc.create();
shapeList.push_back(s);
shapeList.push_back(s1);
/* Second step: check if we've got a shape starting from a creator */
for (it = shapeList.begin(); it != shapeList.end(); ++it) {
if (rc.equals(**it)) {
std::cout << "same shape" << std::endl;
}
}
return 0;
}
I'm not sure what you're trying to do, but I guess this could point you some direction
enum class Shapes
{
Rectangle,
Circle,
...
};
class Shape
{
private:
Shapes m_shape;
protected:
Shape(Shapes shape)
{
m_shape = shape;
}
public:
Shapes GetShape() { return m_shape; } // this is used to check whether two shapes are equal
virtual ~Shape() = default;
};
And now for factory pattern you'd do:
class ShapeFactory
{
public:
static Shape* CreateShape(Shapes shape)
{
switch (shape)
{
case Shapes::Circle:
return new Circle();
// etc.
}
}
};
This feels very redundant and not very clever to me. Also, this can put alot of code into one place.
For the dispatch, you could do (I assume, I'm not really a fan of this concept as it can be made less verbose with a simple template use)
class ShapeCreator
{
public:
virtual Shape* Create() = 0;
virtual ~ShapeCreator() = default;
};
class Circle : public Shape
{
public:
class Creator : ShapeCreator
{
public:
Shape* Create() { return new Circle(); }
};
Circle() : Shape(Shapes::Circle)
{}
};
bool SomethingWithCircle()
{
Circle::Creator circleCreator;
Shape* first = circleCreator.Create();
Shape* second = circleCreator.Create();
// notice memleak here
return first->GetShape() == second->GetShape();
}
If using C++11, you can go even further and avoid the whole idea /which feels very java-like to me anyway/ using a proper template masturbation techniques. (Can still be applied to pre-C++11, you just won't be able specify the parameters.)
template<class T>
class ShapeCreator
{
public:
template<class... TParams>
static T* Create(TParams&&... parameters) { return new T(std::forward<TParams>(parameters)...); }
};
class Rectangle : public Shape
{
private:
int m_width;
int m_height;
public:
Rectangle(int width, int height) : Shape(Shapes::Rectangle)
{
m_width = width;
m_height = height;
}
};
bool DoSomethingWithRectangles()
{
Rectangle* first = ShapeCreator<Rectangle>::Create(10, 15);
Shape* second = ShapeCreator<Rectangle>::Create(20, 25);
// notice memleak here
return first->GetShape() == second->GetShape();
}
TL;DR
You don't really need RTTI but you need to store the type info somewhere in the base type. I'm using the enum Shapes for this.
Both Factory and Dispatch may seem as a good idea, but you will still need dynamic casting somewhere when using them.
You can replace those two patterns using templates, but as soon as you'll get a vector of the base objects, you'll still have to dynamic_cast at some point.
I didn't measure this whatsoever, but I'm really interested in performance comparison of using virtual functions and dynamic cast as I imagine they'd be very similar...
End note:
Please notice, that I personally feel that using methods like equals or operator== on classes defining the basic interface is not very wise, since there are two possible outcomes:
The equals is virtual -> slow but acceptable
The equals is not virtual -> cannot be used in inherited types to actually do more advanced/relevant comparison, breaking the idea of Open to extension, closed for modification
Obviously, if you don't define the equals, you'd have to write comparison code every time. Or possibly use some templated Comparison class with possible specializations through traits yielding again the best performance with no code duplicity.
Generally speaking, you can get to point where you'd ask yourself "why isn't there base object and reflection like in java or c# in c++? It would allow me to use all these nice and clever patterns." The answer is templates. Why do it run-time, when you can do it compile time?
I have two classes:
class CEnemy : CObject
{
protected:
int hitPoints;
};
class COgro : public CEnemy
{
COgro::COgro() {hitPoints = 100}
};
and in other file I have class 'CRocket', which can collide with COgro, there is it function:
void CRocket::OnCollision(CObject *collisionObject)
{
if (typeid(*collisionObject) == typeid(COgro))
{
//collisionObject->hitPoints -= 10; ?? or what?
}
}
I want to shoot 10 times to ogro before it dies. How to do this?
I've already tried:
collisionObject->hitPoints -= 10;
(CEnemy)collisionObject->hitPoints -= 10;
but I can't compile it...how to edit this hitPoints value, but without changing '(CObject *collisionObject)'?
Thx
EDIT:
//===============================================================
//------------------------------------CLASS CRocket-----------------------
class CRocket : public CObject
{
protected:
void OnAnimate(scalar_t deltaTime);
void OnCollision(CObject *collisionObject);
void OnDraw(CCamera *camera);
public:
float pitch;
float distanceTravel;
CVector forward;
bool isExplosion;
CTexture *explosionTex;
CExplosion *explosion;
CRocket();
~CRocket();
void Load();
void Unload();
};
void CRocket::OnCollision(CObject *collisionObject)
{
if (typeid(*collisionObject) == typeid(COgroEnemy))
{
isExplosion = true;
velocity = CVector(0.0, 0.0, 0.0);
explosion = new CExplosion(500, position, 8.0, explosionTex->texID);
PlaySound();
}
}
//-----------------------------------------class CObject
class CObject : public CNode
{
protected:
virtual void OnAnimate(scalar_t deltaTime)
{
position += velocity * deltaTime;
velocity += acceleration * deltaTime;
}
virtual void OnDraw(CCamera *camera) {}
virtual void OnCollision(CObject *collisionObject) {}
virtual void OnPrepare()
{
ProcessCollisions(FindRoot());
}
public:
CVector position;
CVector velocity;
CVector acceleration;
scalar_t size;
bool isDead;
CObject() {isDead = false;}
~CObject() {}
...
...
...
}
//---------------------------------------class CEnemy
class CEnemy : public CObject
{
public:
int hitPoints;
protected:
float distFromPlayer;
float runSpeed;
AIState_t aiState;
virtual void OnProcessAI() {}
void OnCollision(CObject *collisionObject)
{
// if this enemy collides with another enemy
if (typeid(*collisionObject) == typeid(CEnemy))
{
modelState = MODEL_IDLE;
velocity = CVector(0.0, 0.0, 0.0);
}
// if this enemy collides with the terrain (always)
else if (typeid(*collisionObject) == typeid(CTerrain))
{
position.y = ((CTerrain*)collisionObject)->GetHeight(position.x, position.z) + size;
}
else
{
}
}
public:
CPlayer *player;
...
...
//----------------------------------class COgro-------------------------
class COgroEnemy : public CEnemy
{
protected:
void OnProcessAI();
void OnCollision(CObject *collisionObject);
void OnPrepare();
public:
COgroEnemy() { Load(); }
COgroEnemy(float x, float z) { position.x = x; position.z = z; Load(); }
~COgroEnemy() {}
void Load();
};
You'll need to cast the pointer to a pointer type CEnemy* (or a subclass), or the dereferenced pointer to a reference type CEnemy&. For maximum safety, I'd suggest dynamic_cast, rather than an evil C-style cast; although that's slightly paranoid since you're checking the type before casting.
// no checks, undefined behaviour if type is wrong
((CEnemy*)collisionObject)->hitPoints -= 10;
static_cast<CEnemy*>(collisionObject)->hitPoints -= 10;
// throws if type is wrong
dynamic_cast<CEnemy&>(*collisionObject).hitPoints -= 10;
// does nothing if type is wrong
if (CEnemy* enemy = dynamic_cast<CEnemy*>(collisionObject)) {
enemy->hitPoints -= 10;
}
You might combine that with the type check, rather than using typeid:
if (COgro * ogro = dynamic_cast<COgro*>(collisionObject)) {
ogro->hitPoints -= 10;
}
Note that this isn't exactly the same as your test: it will pass if the object is a subtype of COgro, while your test checks for an exact match.
You code is not compiling because you are trying to access a class's protected data member from an external source.
The collisionObject parameter is an instance of CObject, which does not have a hitPoints data member.
Also, when you pass around pointers to base classes to functions, the functions should assume that they can only access the interface or features of the base class.
You should write another overloaded method:
void CRocket::OnCollision(CEnemy& enemy);
Or move the hitPoints data member to the CObject class.
I want to go from this:
To this:
How would I do this? How would the functions of subclasses square and rectangle know to use the variable of the parent class shape?
How would I set length and width from main?
#include <iostream>
#include <cmath>
using namespace std;
class SHAPES
{
public:
class SQUARE
{
int perimeter(int length, int width)
{
return 4*length;
}
int area(int length, int width)
{
return length*length;
}
};
public:
class RECTANGLE
{
int perimeter(int length, int width)
{
return 2*length + 2*width;
}
int area(int length, int width)
{
return length*width;
}
};
};
I recommend other (better?!) format:
class Shape
{
protected:
int length,width;
public:
Shape(int l, int w): length(l), width(w){}
int primeter() const
{
return (length + width) * 2;
}
int area() const
{
return length * width;
}
};
class Rectangle : public Shape
{
public
Rectangle(int l, int w) : Shape(l,w){}
};
class Square : public Shape
{
public:
Square(int l): Shape(l,l){}
};
int main()
{
Rectangle r(5,4);
Square s(6);
r.area();
s.area();
}
Or use interface with virtual function.
Those are not subclasses (i.e. derived classes), but rather nested classes (as the title of your question says).
I don't think I would answer your real question if I were to tell you how to make those variables visible in nested classes. Based on what I can understand from the names of your classes, you should rather use inheritance to model the IS-A relation between them:
class SHAPE
{
public: // <-- To make the class constructor visible
SHAPE(int l, int w) : length(l), width(w) { } // <-- Class constructor
...
protected: // <-- To make sure these variables are visible to subclasses
int length;
int width;
};
class SQUARE : public SHAPE // <-- To declare public inheritance
{
public:
SQUARE(int l) : SHAPE(l, l) { } // <-- Forward arguments to base constructor
int perimeter() const // <-- I would also add the const qualifier
{
return 4 * length;
}
...
};
class RECTANGLE : public SHAPE
{
// Similarly here...
};
int main()
{
SQUARE s(5);
cout << s.perimeter();
}
I am trying to implement a factory for two classes Circle, Square both of which inherits from Shape.
class Shape {
public:
virtual static
Shape * getInstance() = 0;
};
class Circle : public Shape {
public:
static const std::string type;
Shape * getInstance() {
return new Circle;
}
};
const std::string Circle::type = "Circle";
class Square : public Shape {
public:
static const std::string type;
Shape * getInstance() {
return new Square;
}
};
const std::string Square::type = "Square";
I want to now create a map with key as shape type (string) and value as a function pointer to getInstance() of the corresponding derived class. Is it possible?
Thanks,
Kiran
Okay I got the mistake.
1) shouldn't declare - virtual static Shape * getInstance() = 0; - in Shape class.
2) getInstance() should be static in all other classes.
Here is the complete implementation
class Shape {
public:
virtual
std::string getType() = 0;
};
class Circle : public Shape {
public:
static const std::string type;
Circle() {
}
std::string getType() {
return type;
}
static
Shape * getInstance() {
return new Circle;
}
};
const std::string Circle::type = "Circle";
class Square : public Shape {
public:
static const std::string type;
Square() {
}
std::string getType() {
return type;
}
static
Shape * getInstance() {
return new Square;
}
};
const std::string Square::type = "Square";
class Triangle : public Shape {
public:
static const std::string type;
Triangle() {
}
std::string getType() {
return type;
}
static
Shape * getInstance() {
return new Triangle;
}
};
const std::string Triangle::type = "Triangle";
typedef Shape * (*getShape)();
typedef std::map<std::string, getShape > factoryMap;
class ShapeFactory {
public:
static factoryMap shapes;
Shape * getInstance(const std::string & type){
factoryMap::iterator itr = shapes.find(type);
if (itr != shapes.end()){
return (*itr->second)();
}
return NULL;
}
};
factoryMap ShapeFactory::shapes;
class ShapeFactoryInitializer {
static ShapeFactoryInitializer si;
public:
ShapeFactoryInitializer() {
ShapeFactory::shapes[Circle::type] = &Circle::getInstance;
ShapeFactory::shapes[Square::type] = &Square::getInstance;
ShapeFactory::shapes[Triangle::type] = &Triangle::getInstance;
}
};
ShapeFactoryInitializer ShapeFactoryInitializer::si;
Although not much relevant to your question, but if you are interested in modern C++ design (factories, smart pointers, etc.), you may like to check this book:
http://www.amazon.co.uk/Modern-Design-Applied-Generic-Patterns/dp/0201704315/ref=sr_1_20?s=books&ie=UTF8&qid=1293359949&sr=1-20
It talk about factories, how to design them, etc.
PS: I am not the author of the book, nor I have been given any thing in return for posting this answer :-)
Change the last line of your code to ShapeFactoryInitializer ShapeFactoryInitializer::si;, then it will pass compilation.