C++ Sorting a Array of Pointer to Objects [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ how to sort an array variable
I got a parent class call
Shape
Shape got 2 child call
Square and Rectangle
Shape class got a variable call area, which is of int type
So i created some object of Square, Rectangle like this
int main()
{
Shape *shaped[100];
//then i did some adding of object..
int areaValue;
areaValue=1;
shaped[0] = new Rectangle();
shaped[0]->setArea(areaValue);
areaValue=7;
shaped[1] = new Square();
shaped[1]->setArea(areaValue);
areaValue=5;
shaped[2] = new Square();
shaped[2]->setArea(areaValue);
shapeCounter = 3;
sort(shaped, shaped + 3, sort_by_area());
for (int i=0;i<shapeCounter;i++)
{
cout << shaped[i].getArea() << endl;
}
}
Then at e.g Square.cpp
I did this
struct sort_by_area
{
static bool operator()(Shape* x, Shape* y)
{
return x->getArea() < y->getArea();
}
};
This code above works. and can sort by area, but my question is that can i still sort if i don't use struct , cause if i don't use struct, it will say the sort_by_area is not declared in scope.
Must i really use struct so my main.cpp can access the sort code that is located at the child class .cpp
Thanks

This works perfectly:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class Shape{
private:
int x;
public:
void setArea(int x){
this->x = x;
}
int getArea(){
return this->x;
}
};
class Rectangle: public Shape{
public:
};
class Square: public Shape{
public:
};
bool sort_by_area (Shape* x,Shape* y) { return (x->getArea() < y->getArea()); }
int main()
{
Shape *shaped[100];
//then i did some adding of object..
int areaValue,shapeCounter = 0;
areaValue=1;
shaped[0] = new Rectangle();
shaped[0]->setArea(areaValue);
areaValue=7;
shaped[1] = new Square();
shaped[1]->setArea(areaValue);
areaValue=5;
shaped[2] = new Square();
shaped[2]->setArea(areaValue);
shapeCounter = 3;
sort(shaped, shaped + 3, sort_by_area);
for (int i=0;i<shapeCounter;i++)
{
cout << shaped[i]->getArea() << endl;
}
return 0;
}

Related

Array of arrays of different types of shapes

I want to create a "3D console game" using RayCasting. To begin with, I needed a container with all the information about the world. First of all, I started with just two shapes, a rectangle and a circle. Actually, here's how I implemented them:
enum POINTS
{
POINT_1,
POINT_2
};
enum ASIXS
{
ASIX_X,
ASIX_Y,
};
class Point
{
private:
double properties[2];
public:
Point()
{
properties[ASIX_X] = 0;
properties[ASIX_Y] = 0;
}
Point(double x, double y)
{
properties[ASIX_X] = x;
properties[ASIX_Y] = y;
}
double& operator[] (int index)
{
return properties[index];
}
};
class Rectangle
{
private:
Point base[2];
public:
//Points getter
Point& operator[](int index)
{
return base[index];
}
};
class Circle
{
private:
Point center;
double radius = 0;
public:
Point& getCenter()
{
return center;
}
double& getRadius()
{
return radius;
}
};
Next, I need a generic container. Obviously this should be a pattern:
template<typename T>
class ObjectArr
{
protected:
int qty;
T* objs;
public:
ObjectArr()
{
qty = 0;
objs = nullptr;
}
~ObjectArr()
{
delete[] objs;
}
void add()
{
T* temp = new T[++qty];
for (int i = 0; i < qty - 1; i++)
temp[i] = objs[i];
delete[] objs;
objs = temp;
}
T getObj(int index)
{
return objs[index];
}
};
Here's what it will look like:
#include <iostream>
using namespace std;
int main()
{
ObjectArr<Rectangle> rect;
rect.add();
//rect.getObj(id)[point][asix]
rect.getObj(0)[POINT_1][ASIX_X] = 5;
cout << rect.getObj(0)[POINT_1][ASIX_X]; //Out 5
ObjectArr<Circle> cir;
cir.add();
//cir.getObj(id).getCenter()[asix]//getRadius()
cir.getObj(0).getCenter() = {0, 0};
return 0;
}
And in the end, I would like one common container that would store ObjectArr<>. From the beginning I thought about polymorphism. Something like this:
#include <vector>
class Container
{
//...
};
template<typename T>
class ObjectArr : public Container
{
//...
};
int main()
{
vector<Container*> test;
test.push_back(new ObjectArr<Rectangle>);
test.push_back(new ObjectArr<Circle>);
test[0]->add();
//...
return 0;
}
But with this approach, the function T getObj(int index) cannot be used from such a container. And writing it as a virtual one will not work either because of the template. And I also don’t want to prescribe every possible shape, so that it would be easier to add new shapes. Wrote a class of a new figure and all. Tell me, please, how should I be and what should I do, maybe I need to completely change the approach?

std::sort of polymorphic types not sorting as expected

I have taken sample code from ch9 Open Closed Principle in Agile Software Development, as below, which is supposed to sort shapes by precedence in the order given by the table typeOrderTable in the code below. Well, I did have to add a main and test code but pretty much copied the book code. But the output shows it is not sorting as per the table. And if I try to debug the code, the code path does not enter the Shape::Precedes function.
How can I fix this?
Code:
#include <typeinfo>
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Shape {
public:
virtual void Draw() const = 0;
bool Precedes(const Shape& s) const;
bool operator<(const Shape& s) const {
return Precedes(s);
}
private:
static const char* typeOrderTable[];
};
bool Shape::Precedes(const Shape& s) const {
const char* thisType = typeid(*this).name();
const char* argType = typeid(s).name();
bool done{ false };
int thisOrd{ -1 };
int argOrd{ -1 };
for (int i = 0; !done; ++i) {
const char* tableEntry = typeOrderTable[i];
if (tableEntry != 0) {
if (strcmp(tableEntry, thisType) == 0)
thisOrd = i;
if (strcmp(tableEntry, argType) == 0)
argOrd = i;
if (argOrd >= 0 && thisOrd >= 0)
done = true;
}
else done = true;
}
return thisOrd < argOrd;
}
class Square : public Shape {
public:
virtual void Draw() const {
cout << "square\n";
}
};
class Circle : public Shape {
public:
virtual void Draw() const {
cout << "circle\n";
}
};
class Rectangle : public Shape {
public:
virtual void Draw() const {
std::cout << "rectangle\n";
}
};
const char* Shape::typeOrderTable[] = {
typeid(Circle).name(),
typeid(Rectangle).name(),
typeid(Square).name(),
0
};
void DrawAllShapes(vector<Shape*> shapes) {
vector<Shape*> orderedList = shapes;
sort(orderedList.begin(), orderedList.end());
for (auto shape : orderedList) {
shape->Draw();
}
}
int main() {
Shape* circle = new Circle();
Shape* square = new Square();
Shape* rectangle = new Rectangle();
Shape* rectangle2 = new Rectangle();
vector<Shape*> shapes{ rectangle, square, circle, rectangle2 };
DrawAllShapes(shapes);
/* should print:
circle
rectangle
rectangle
square
but instead prints:
rectangle
square
rectangle
circle
ie unsorted - actually it is random in the output
*/
}
You need to change your call to std::sort(...) to use a comparator. The way you have it, it is pointers to shapes being sorted not shapes so the operator< defined for shapes will not be called, instead the numeric values of the pointers will be compared.
One way to fix this is to sort like this
sort(orderedList.begin(), orderedList.end(),
[](Shape* s1, Shape* s2) { return s1->Precedes(*s2); }
);
providing a lambda taking Shape*'s to do the actual comparing.

What is the best way to call a derived class's function that isn't part of the base class?

Given the following piece of code:
(This is mostly about what is happening in the Function() method, the rest is just setup/context.)
enum class class_type { a, b };
class Base {
public:
Base(class_type type) : type(type) {}
class_type type;
};
class DerivedA : public Base {
public:
DerivedA() : Base(class_type::a) {}
void FunctionA() {}
};
class DerivedB : public Base {
public:
DerivedB() : Base(class_type::b) {}
void FunctionB() {}
};
void Function(Base& base) {
switch (base.type) {
case class_type::a: {
DerivedA& temp = (DerivedA&)base; // Is this the best way?
temp.FunctionA();
break;
}
case class_type::b: {
base.FunctionB(); // This obviously doesn't work.
break;
}
}
}
int main() {
DerivedA derived_class;
Function(derived_class);
}
Is the way I'm doing it here with DerivedA the best/most efficient way to do it? I feel like there is a better method of doing this, but I don't know how.
The answer is You DON'T do that, it totally handled by the polymorphism, read this code:
And try to map it to your code:
Shap is your Base
Rectangle is your DerivedA
Triangle is your DerivedB
#include <iostream>
using namespace std;
class Shape {
protected:
int width, height;
public:
Shape( int a = 0, int b = 0){
width = a;
height = b;
}
int area() {
cout << "Parent class area :" <<endl;
return 0;
}
};
class Rectangle: public Shape {
public:
Rectangle( int a = 0, int b = 0):Shape(a, b) { }
int area () {
cout << "Rectangle class area :" <<endl;
return (width * height);
}
};
class Triangle: public Shape {
public:
Triangle( int a = 0, int b = 0):Shape(a, b) { }
int area () {
cout << "Triangle class area :" <<endl;
return (width * height / 2);
}
};
// Main function for the program
int main() {
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);
// store the address of Rectangle
shape = &rec;
// call rectangle area.
shape->area();
// store the address of Triangle
shape = &tri;
// call triangle area.
shape->area();
return 0;
}
This is far enough for what you need:
DerivedA& temp = static_cast<DerivedA&>(base);
temp.FunctionA();
Under the hood, this is the same as the C Style cast that you just did, but it's considered a good practice to make them explict.

C++ class inherit (game structure)

I'm trying to make some game engine (I know, should do an actual game instead).
Sadly have defeat at project structure. it looks like this (footage from my fifth attempt):
#include <iostream>
#include <vector>
#include <windows.h>
using namespace std;
class Player;
class Engine {
private:
CHAR_INFO *chiBuffer;
int width = 0;
int height = 0;
vector <Player> players;
public:
Engine(int x = 120, int y = 30) {
chiBuffer = new CHAR_INFO[x*y];
}
void addPlayer(Player player) {
players.push_back(player);
}
void render() {
for (int i = 0; i < players.size(); i++) {
Player *player = &players[i];
player->draw();
}
}
protected:
inline CHAR_INFO& getPixel(int x, int y) { return chiBuffer[x + width * y]; }
};
class Drawable : Engine {
protected:
inline CHAR_INFO& getPixel(int x, int y) { return Engine::getPixel(x, y); }
virtual void draw() = 0;
};
class Player : Drawable {
protected:
int x = 0;
int y = 0;
public:
void draw() {
getPixel(x, y).Char.UnicodeChar = L'*';
}
};
int main() {
Engine *eng = new Engine(120, 30);
Player p;
eng->addPlayer(p);
return 0;
}
I would like to make it easily extensible, so in my mind had been born an idea of creating master class (Engine) sub class Drawable which will have draw() method and later Tickable which would have onTick() etc... But I'm pretty sure I'm doing it so wrong. Could you tell me better idea of doing this? Or make this just working because this gives me too many errors to write it right here (VS 2017)
First, why use this ?
for (int i = 0; i < players.size(); i++) {
Player *player = &players[i];
player->draw();
}
It's the same as: for(...) { players[i].draw() ;}.
Don't use variables and pointers where you don't need to (like in your main, don't use the new keyword: it's pointless. Engine e = Engine(120,30) is ok.).
The for loop on a vector should use Iterators :
for (auto it = begin (vector); it != end (vector); ++it) {
it->draw;
}
In manners of good practice, you should write your code in different files.
Engine.h for Engine declaration, Engine.cpp for implementation.
Same for Player.

given a vector with different figures find out how many are circles and how many are squares [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
So i got this example :
class figures
{};
class square:public figures
{};
class circle : public figures
{};
.....
int main()
{
geometric figures* *p;
p[0]=new Circle;
p[1]=new Square;
return 0;
};
and so on. My question is how can i find out later how many circles or squares do I have in my geometric figure array if all the pointers are the geometric figures type?
You can use a dynamic_cast:
std::vector<geometric_figures *> shapes;
int num_circles = 0;
int num_squares = 0;
for (geometric_figures * shape : shapes)
{
if(dynamic_cast<circle*>(shape))
num_circles++;
if(dynamic_cast<square*>)(shape))
num_squares++;
}
You could also add an enum to correspond to the type of shape, and add a GetType() method that returns that enum.
You could have an enum in your class
class geometric_figures
{
public:
enum shape {eSquare, eCircle};
virtual shape GetShapeType() const = 0;
};
class square : public geometric_figures
{
public:
shape GetShapeType() const override { return eSquare; }
};
class circle : public geometric_figures
{
public:
shape GetShapeType() const override { return eCircle; }
};
Then you can use std::count_if
#include <algorithm>
#include <vector>
int main()
{
using GF = geometric_figures;
std::vector<GF*> p;
p.push_back(new circle);
p.push_back(new square);
int num_circles = std::count_if(p.begin(), p.end(), [](GF const* fig){ return fig->GetShapeType() == GF::eCircle; });
}
Working demo
You could use dynamic casts. For example:
// Returns true if 'a' is of type 'square'
bool isSquare(Figure* a)
{
return dynamic_cast<Square*>(a) != nullptr;
}
// Returns true if 'a' is of type 'circle'
bool isCircle(Figure* a)
{
return dynamic_cast<Circle*>(a) != nullptr;
}
int main()
{
Figure *p = new Figure[5];
p[0] = new Circle;
p[1] = new Circle;
p[2] = new Square;
p[3] = new Square;
p[4] = new Square;
int circleCnt = 0;
int squareCnt = 0;
for(int i = 0; i < 5; i++)
{
if(isCircle(p[i]))
{
circleCnt++;
}
if(isSquare(p[i]))
{
squareCnt++;
}
}
cout << "Number of circles: " << circleCnt << endl;
cout << "Number of squares: " << squareCnt << endl;
}
The output of this program will be:Number of circles: 2Number of squares: 3
Note that this is highly inefficient compared to keeping the number of circles and squares up-to-date somewhere.