Question on polymorphism on C++

Hi all!
This is more a C++ question that OF, but i’m trying to implement in OF, so i think it should’n be too off topic.
This is what i’d like to do:

class Shape{
	int x,y;
	Shape(int _x, int _y){
		x = _x;
		y = _y;
	}
	virtual void draw() = 0;
};

class Circle: public Shape{
	float r;
	void draw(){
		drawCircle();
	}
	Circle(int _x, int _y, float _r): Shape(_x,_y){
		r = _r;
	}
};

class Rectangle: public Shape{
	float w,h;
	void draw(){
		drawRectangle();
	}
	Rectangle(int _x, int _y, float _w, float _h): Shape(_x,_y){
		w = _w;
		h = _h;
	}
};

With a predefined number of shapes, i’ve managed to get what i want. Like this:

Rectangle * rect1, rect2;
Circle * circle1;
vector<shared_ptr<Shape>> shapes;
int currShape;

void ofApp::setup(){
	rect1 = new Rectangle(x1,y1,w1,h1);
	rect2 = new Rectangle(x2,y2,w2,h2);
	circle1 = new Circle(x3,y3,r3);

	shapes.emplace_back(rect2);
	shapes.emplace_back(circle1);
	shapes.emplace_back(rect1);
}

void afApp::update(){
	currShape = selectShapeToDraw();
}

void ofApp::draw(){
	shapes[currShape]->draw();
}

But i’d like to use an arbitrary number/type of shapes, so i was thinking to something like this:

vector<Rectangle> rectangles;
vector<Circles> circles;
vector<shared_ptr<Shape>> shapes;

but cannot get it working… I know that a vector of pointers to another vector is wrong, and i was trying with a fixed vector, because i’m doing this just in app setup (so rectangles.resize(numOfRect), circles.resize(numOfCircle), shapes.resize(numOfRect+numOfCircle) )

Any hints?

Hi,
So you want shapes as a vector that contains all the shapes (the rectangles and circles), but also be able to access them by type?

I would do it like this, with typecasting the pointer (if I’m correct with the terminology):

vector<Shape*> shapes;
vector<Rectangle*> rectangles;
for(int i=0; i<5; i++){
	rectangles.push_back(new Rectangle(i*100, 0, 50, 50));
	shapes.push_back((Shape*)rectangles.back());
}

And then do the same for the circles.

Thanks for your reply!

Yes. In fact i need to access the single shape just at init time, to avoid a super class with all the needed parameters. Maybe i’ve not specified before, but the shapes are just an example, in fact i’m doing this with more complicated object.
Regarding your example, it works as expected! But only with pointers. If i try with shared_ptr<>, as in my pseudo code, cannot get it to compile… It fails with

error: no matching function for call to ‘std::vector<std::shared_ptr<Rectangle> >::push_back(Rectangle*)’
         rectangles.push_back(new Rectangle(ofRandom(550,ofGetWidth()),ofRandom(100,500),ofRandom(100,200),ofRandom(50,100)));
                                                                                                                            ^

Ideas?

Thanks!

I’m doing exatly that on https://github.com/dimitre/ofxMicroUI/
Im using some lookup tables to find the element by name without the need of iterating the primitive vector every time.

1 Like

Hi, I never use shared_ptr, so not sure if I’m stating the obvious, but this compiles:

vector<shared_ptr<Shapes>> shapes;
shapes.push_back(make_shared<Rectangle>());

A lookup table is my second choice. I’d like to avoid it, so i can do

shape[currShape].draw();

instead of something like

switch(shapeType){
  case(typeRect):
        rectangle.draw();
  case(typeCirc):
        circle.draw()
}

that’s more difficult to maintain.

Yes, it compiles! I was not aware of make_shared, so probably i need to study a little bit more the smart pointer stuff.
Regarding your code, it compiles, but it seems that i cannot access any more the single Rectangle object with

rectangles[i].someProperties(someVal);

After some tryal&error, this seems to work:

Circle * tmp = new Circle(ofRandom(10,500),ofRandom(100,200),ofRandom(100,200));
circles.emplace_back(tmp);
shapes.push_back(circles.back());