Adding Classes to an Array - c++

I'm working on a university assignment about finding the array of different shapes using OOP.
I have created all of my shape classes so they derive from my main Shape Class. Shape class is being used like an interface, so that all the shape classes derived from the shape class have to have a calculate area function, etc.
I want to create an array of different shapes. I have declared an array with a type of shape, which is the parent class and i want to add new instances of each different shape, circle, square, rectangle and triangle to the array list so that all the information about each shape is stored in one array. I have the follow code but i have an error on the line aShapes[i] = square; saying that shape is an inaccessible base of square.
If anyone could help out that would be great.
Thanks in advanced.
Here is my code
#include <cstdlib>
#include <iostream>
#define M_PI 3.14159265358979323846
using namespace std;
class Shape{
public:
string sName;
float nArea;
void fnAddData();
float fnCalculateArea();
};
class Square : private Shape {
private:
float nSide;
void fnAddData()
{
cout << "Please enter the length of a side: ";
cin >> nSide;
}
float fnCalculateArea(float side)
{
return (side * side);
}
public:
Square()
{
sName = "Square";
fnAddData();
nArea = fnCalculateArea(nSide);
}
};
Shape aShapes[5];
/*
*
*/
int main(int argc, char** argv)
{
int decision;
Square square;
for (int i = 0; i < 5; i++)
{
cout << "Shape number";
cin >> decision;
switch (decision)
{
case 1:
aShapes[i] = square;
}
}
return 0;
}

Arrays aren't polymorphic: Everything stored in the array must be the same type. Your array of Shape won't work.1
So how do you get polymorphism when using an array, then? Change your array to store pointers to Shape:
Shape *aShapes[5];
That solves the problem nicely: A Shape* can point to a Shape or any of its descendants,2 and all the Shape* themselves are the same type.
And then in your main code, store the addresses of the objects in the array:
aShapes[i] = &square;
You will need to make a couple other changes to your existing code to make this work:
Use public inheritance, not private inheritance.
Make the methods in Shape virtual.
Make the methods in Square that override the interface defined by Shape public.
Add a virtual destructor.
1 If you do manage to copy a descendent of Shape into the array, you end up slicing the object.
2 Technicality: If you give Shape pure virtual methods, you won't be able to create an instance of a pure Shape. In that event, Shape* can't point at an instance of Shape because you can't create one! A Shape* would only point to one of its descendents that implements all of the virtual methods.

The reason you're getting that particular error is because you're using private inheritance when it looks like you really want to be using public inheritance.
class Square : public Shape {
^^^^^^
A further problem is that polymorphism works only with pointers or references. You cannot put a Square into an array of Shapes. It will simply slice out the Shape part of the Square and put that in the array. Shape aShapes[5]; is nothing more than an array of Shapes - there are no Squares, no Triangles, just Shapes. What you need is something like:
Shape* aShapes[5];
You can then set the pointers in this array to point at objects of types that derive from Shape.
You'll also need to make the functions that you want to override in the derived classes virtual. When the compiler sees something like aShapes[0]->fnCalculateArea(), and then sees that fnCalculateArea is a virtual function, it will only then look up the dynamic type of the object that aShapes[0] points to - it will then see that it's a Square and call Square::fnCalculateArea.

1) You're privately inheriting from Shape, which is more typically an undesirable form of composition. You should be publicly inheriting from Shape for your purposes.
class Square : public Shape
2) None of Shape's member functions are declared virtual, so none of them will be overridden by derived classes. You also don't have a virtual destructor. If you want the CalculateArea function of Square to be used when you call it on a Shape pointer that points to a Square, you have to declare as virtual in Shape, and override it in Square:
In Shape:
virtual float fnCalculateArea();
In Square:
void float fnCalculateArea() override;
3) If Shape should act only as an abstract interface, not to be instantiated itself, then you should make it so by making one of its functions pure virtual (the destructor at least, if nothing else).
virtual ~Shape() = 0 {}
4) If you want to store the different derived types in a single container, then you have to store them by reference, IE through a pointer to their base class.
Shape* aShapes[5];
5) I also noticed that you're prefixing many variable names with n even though they are floats. Hungarian notation typically uses n to refer to ints and f to refer to floats.

Arrays of values do NOT behave polymorphically. You will have to use an array of pointers to Shape, as access and assignment to pointers does behave polymorphically.
What you have here is object slicing, you're cutting off the Derived class chunk so that your object fits into a Base. This is bad.
With a pointer, however, you get no slicing.
Your particular error stems from use of private inheritance, which forbids conversion to the inherited class. Use public inheritance. This is just masking the issue above.

Related

Getting derived member variable through base class pointer

consider this base class:
struct drawable
{
virtual void draw(sf::RenderWindow &window) const = 0;
};
and this derived class:
struct rectangle : drawable
{
rectangle(sf::Vector2f pos, sf::Vector2f size);
void draw(sf::RenderWindow &window) const;
sf::RectangleShape body;
};
I have similar derived classes for other shapes like circle, line and triangle. I use this function to return shapes based on a string of text I get from a file:
drawable * string_to_object(std::string name)
{
if (name == "RECTANGLE")
{
return new rectangle(sf::Vector2f(20,20), sf::Vector2f(5,5));
}
else if (name == "BALL")
{
return new ball(sf::Vector2f(10,10), 5, sf::Vector2f(0,0));
}
else if (name == "LINE")
{
return new line(sf::Vector2f(30,30), 10, 5);
}
}
Now in my main I have variables like this to test if it works:
auto game_object = string_to_object("BALL");
Now the problem is I need to perform actions/checks on the shape's body, which is a member of the derived class that I cannot access from the drawable pointer variables. It's also a problem that the type of the body is not set, it can be a RectangleShape, CircleShape etc so a getBody() function would need a variable return type. How would I go about getting access to the body in a generic way? I've tried templates but I realized that won't work since it's a runtime problem.
If I understand your question correctly, there are multiple ways how to solve this issue.
Re-think your architecture. You could introduce other virtual functions to drawable that every subclass implements. In these functions you'd implement all the checks/actions you need. Since they are implemented in the base class, they have access to the shape's body and since it is a virtual function of the base you can call these functions from the outside.
Since your drawable object has a virtual function, you could use RTTI to check the type at runtime and perform a dynamic_cast
See: https://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI
I'd prefer the first option whenever you can.
It sounds like you're having trouble deciding what functionality is generic to all drawable objects, and what is specific to rectangle, ball and so on. Attributes and methods that apply to all drawable objects can be declared within drawable, but anything that only applies to a particular kind of drawable (like the width and height of rectangle vs. the radius of a ball) go in the derived classes.
In your example, each of the derived classes must implement the draw method if you want to instantiate them (because it is declared pure virtual in the base drawable class). Each of these specific derived implementations can access the specific attributes of the derived class. So the rectangle::draw method can access the width and height, while the ball::draw method can access the radius.
Then, when you have a collection of pointers to drawable objects (which are really instances of the derived classes) you can simply call the draw method for each of them.
Sorry if this seems overly simplistic - I hope it's clear.

How can I be flexible with a method parameter that can hand 2D and 3D shapes when using a shape parameter

The title sucks I know.
The problem here is that I have a 2D and 3D shape class that inherits from a shape class
class Shape {
public:
virtual double area() = 0;//Calculates the area of some kind of shape
~Shape() { delete this; }
};
class Shape2D :public Shape {
public:
virtual double perimeter() = 0;//Calculates the perimeter of some kind of 2D-shape
~Shape2D() {};
};
class Shape3D :public Shape {
public:
virtual double volume() = 0;//Calculates the volume of some kind of 3D-shape, area function will return surface area
~Shape3D() {};
};
It is decided that all shapes will default have an area. In 2D shapes, it'll have a virtual perimeter method and also and area from Shape. In 3D shapes, it'll have a volume and the vitual area method will be treated as a surface area.
The way that I've gone about is that within a menu that can choose 2d or 3d shapes: within the 2d menu, I initiate:
Shape2D * s = nullptr;
and within the 3d menu, I'll initiate:
Shape3D * s = nullptr;
and then to display whatever information, I use the methods:
void displayShape2D(Shape2D *)
and
void displayShape3D(Shape3D *)
However, the way that I want to go about it is to declare:
Shape *s = nullputr;
at the beginning of main and then at whatever shape the user chooses, I can just set:
s= new Triangle()
or
s = new cube();
The initialization works but when I try to make a display method, that's where I run into a problem. I want to be able to do:
displayShape(Shape *s)
When given a 2d shape and within the method I try:
cout <<s->perimeter();
It'll say that the perimeter member is not within the shape class.
The problem then is trying to be able to determine if a the shape is 2d or 3d and then display the area and perimeter for 2d or surface area and volume for 3d. Is this possible or is creating the shape types within the dedicated menu and then having dedicated display methods the only way out?
While the other answer "works" it's not the approach I'd take here. Basically you want to execute different code depending on the dynamic type of an instance: that's what virtual functions are for.
So just add a (possibly pure) virtual display member function to your Shape class and implement it accordingly in the deriving classes.
Contrary to the dynamic_cast approach this doesn't break when you add more deriving classes or classes that are derived even "further".
Finally:
~Shape() {
delete this;
}
This destructor is the C++ equivalent of taking a shot gun and shooting yourself into the face. With a stack or static allocated instance this will lead to a bogus free (as the instance was never allocated from the heap), with a heap allocated it will lead to a double free (since the destructor is called just before freeing the occupied memory of the instance).
What you must do in your case is make the destructor virtual. Otherwise, having only Shape * it's impossible to correctly destruct the pointed to instance!
This is how such "display" functionality is "commonly" implemented, at least AFAIK:
struct Shape {
virtual void write_to(ostream &) const = 0;
virtual ~Shape() {}
};
struct Shape2D : public Shape {
void write_to(ostream & stream) const {
stream << "<2D, whooo>";
}
};
struct Shape3D : public Shape {
void write_to(ostream & stream) const {
stream << "<I got depth, man!>";
}
};
ostream & operator<<(ostream & stream, Shape const & shape) {
shape.write_to(stream);
return stream;
}
Now one can write any Shape (when using a pointer, dereference it) to any ostream, C++ "style":
std::unique_ptr<Shape> awesomeShape = std::make_unique<Shape2D>();
std::cout << "Awesome is: " << *awesomeShape << std::endl;
Here, first operator<<(ostream &, Shape &) is called (which it would for any Shape-like thing) which calls the virtual member function write_to, which is implemented in different ways for each derived class (though there could be a generic implementation in Shape, too!). See also this.
A possible issue with the dynamic_cast approach occurs when you deepen your hierarchy:
struct ThickShape2D : public Shape2D {
// whatever
};
An instance with dynamic type ThickShape2D can also be dynamic_cast to a Shape2D, thus you'd need to keep an careful eye on the order of these if clauses.
But, to quote Jarra McIntyre:
I think it is worth mentioning that the design trade offs between using virtual functions and the above approach (and any other approaches) are complex. The above approach allows runtime dispatch on multiple types, and simplifies things such as (going back to the above) having multiple draw functions.
I completely second that. There's the visitor pattern (and also it's acyclic variant), probably the command pattern and a a lot of other things one can start looking at if one needs further information. For an extensive discussion about the uses of (raw) RTTI see this question and its answers.
As a final note: I don't know exactly what you're trying to model, but consider that inheritance is most often not the best approach available. When possible, prefer composition over inheritance. Entity component systems are a nice thing to look at.
(The above paragraph contains 6 links, just so that noone misses something.)
What you want to do is runtime type dispatch. One method is to use RTTI. This allows you to do something like this:
Shape *s = ...;
if(Shape3D *s3d = dynamic_cast<Shape3D*>(s)) {
// s3d is now a pointer to a 3d shape
} else if(Shape2D *s2d = dynamic_cast<Shape2D*>(s)) {
// s2d is now a pointer to a 2d shape
} else {
// s is neither a Shape2D or Shape3D
}
This works because dynamic_cast(s) evaluates to a nullptr if s cannot be cast to Type*. Therefore the if statement condition only evaluates to true if s can be cast to the specified type.

C++ array of base class which has instances of derived classes stored in the elements of the array

I am creating an application that allows a user to define dimensions for different shapes and returns the area to the user using the dimensions they specified.
My base class is Shape. Derived classes are Triangle, Circle, Square and Rectangle.
I have created an array of Shape in the hope of creating and storing instances of any of the derived classes in the array during runtime.
Shape** shape = new Shape*[TOTAL_SHAPES];
shape[i] = new Circle(radius);
I have managed this, however I am unable to access the instantiated classes methods. Sorry if this is a stupid question I am fairly new to C++.
Let's assume your types had the following definition
class Shape {
public:
void Method1() { ... }
};
class Circle : public Shape {
void Method2() { ... }
}
With this definition you could access methods on Shape by doing the following
shape[i]->Method1();
In this context though it wouldn't be possible to access Method2 though because the compiler only knows about Shape, not Circle.
shape[i]->Method2(); // Error!
You have three options:
Make Shape an abstract base class and call virtual methods that are members of Shape
Use static_cast to cast from a Shape* to a Circle*, and call methods through that.
Use dynamic_cast to cast from a Shape* to a Circle*, and call methods through that.
The first option is likely best in many cases. Among other reasons, you almost surely need to have a virtual destructor (which can be a by-product of making Shape an ABC), and you may prefer to not have to know what type of object is being pointed to, rather you'd like to simply call methods on whatever it may be. If you can use this idiom, use it.
The second option is dangerous. You must absolutely know that the object being pointed to is a Circle (or whatever) in order to use static_cast, else you will get Undefined Behavior.
The third option is only possible if your class is polymorphic, which means Shape must have at least one virtual method. You surely should have a virtual destructor, and this would serve that purpose.
How about that:
shape[i]->aMethod();
For starters, I highly recommend using a smart pointer wrapper instead of using raw pointers (especially if you are new to the language).
std::vector<std::shared_ptr<Shape>> shapes(TOTAL_SHAPES);
That will define a vector with an initial size of TOTAL_SHAPES.
To the root of your problem, any method you wish to call using a Shape* must be valid for Shape, or you must do a risky downcast to the appropriate type. For example:
class Shape
{
public:
// constructors and other methods go here
virtual ~Shape() { } // virtual destructor
virtual void Draw() { } // virtual function to be used by derived classes
};
class Circle
{
public:
// ...
virtual ~Circle() { }
virtual void Draw() { } // override the virtual function
};
Then, in your application code,
std::vector<std::shared_ptr<Shape>> shapes(TOTAL_SHAPES);
shapes[0] = std::make_shared(new Circle);
shapes[0]->Draw(); // calls Circle::Draw
Note that depending on your usage, std::unique_ptr may replace std::shared_ptr.

Calling a function which belongs to another class

I'm just wondering if there is a way to call a function from another class which is not a derived class.
For example...
If I have class Square which has a function colour, if I have another class Triangle, totally unrealated to Square, can I somehow call the colour funciton of Square on a Triangle object?
I'm wondering if friend can be used here, but from what I have read, it can't, unless I've misunderstood what I've read.
What is the best way to implement this without creating an inheritance relationship?
If what your seeking to do is something like this:
Square s;
Triangle t;
t.colour(); // invoke Square::colour() on a Triangle
I'm sorry but you can't, unless you declare a function in Triangle which simply mimics what Square::colour does.
A wise option if you really need that function to be shared is to declare it as a standalone templated function like this:
template<typename Shape>
void colour(Shape s){
//Do stuff
}
then in order to allow this access to the inner guts of Triangle and Square, make void colour<Triangle>() and void colour<Square>() friends of the appropriate classes.
The answer is no, your request is not possible. The colour method is encapsulated within square and will not apply to an unrelated object of a difference class. Either inherit (from shape - I know you said no inheritance), or re-implement the colour method for square as well.
No, sorry to bum you out. But i would recommend using a base class 'shape', and derive shapes from this class.
class Abc //Abstract base class
{
public:
virtual ~Abc(); //destructor
virtual double Color();
virtual double Area() const = 0; //pure virtual, MUST be overridden
private:
//specific variables that apply to all shapes
};
class Square : public Abc //derived class from pure virtual class
{
public:
Square();
virtual double Color();
virtual double Area() const; //redefine color here
~Square(){}
private:
//square vars here
};

C++ class extension (different size of array in inheriting classes)

I am new to C++, i would like to get an advice.
I am writing two classes that contain both an array of the same object but with different size. Both of the classes has the same methods to deal with the array, but each has it's own unique behavior. Because of that, i would like to create a new class to represent the array and the operations on it, and to make these two classes extend it.
For example:
Class classA{
Person* persons[5];
string className;
...
}
Class classB{
Person* persons[15];
int integerForClassB;
string className;
...
}
What is the best (most suggested) way to define the class parentClass such that it will deal only with the pesrons array and that classA will extend parentClass (with array of size 5) and classB will extend parentClass (with array of size 15)?
Does something like this help? Using an STL vector of type Person, you can make the base class take a count for the number of persons. Then each derived class calls the base class constructor with a different size for the m_persons vector. The vector in each case will then be filled to the requested size with default-initialised instances of Person.
include
class Person
{
};
class ParentClass
{
public:
// Relies on Person having a default constructor
ParentClass( int personCount ) : m_persons( personCount )
{
}
private:
std::vector<Person> m_persons;
};
class ClassA : public ParentClass
{
public:
ClassA() : ParentClass(5)
{
}
};
class ClassB : public ParentClass
{
public:
ClassB() : ParentClass(15)
{
}
};
Do you need to extend the array handling class? Maybe it is better to just use that class from ClassA and ClassB. Prefer composition over inheritance
Do you need an array? As others have said a std::vector could be better.
In case you need the array, have you thought on using templates? A class template can have integer arguments like
template <int npersons> class PersonHandler {
Person* persons[npersons]
}
so you can inherit ClassA from PersonHandler<5> and ClassB from PersonHandler<15>. But note that the PersonClass is a different class for ClassA and ClassB.
Based on the question, my thought is that the best way is to not use inheritance. Use public inheritance to define a class hierarchy. Be very cautious when using it as a means of code reuse, as more often than not, composition is the superior option.
As suggested in the comments, consider a std::vector.
If std::vector does not have all of the desired operations, check if <algorithms> fulfills your needs.
If your needs are still not fulfilled, consider writing collection operations as free functions instead of member functions. With proper decoupling, these operations can work on std::vector<Person> or arrays of Person.
If you must have a collection of Persons with very specific behavior, then use composition. The question description implies composition is correct: "two classes that contain both an array..."
With regards to inheritance, if classA is-a collection-ofPersons and classB is-a collection-ofPersons, then consider public inheritance, if the set of common methods, that different in behavior, can uphold a common set of pre-conditions and post-conditions. For example, consider an Ellipse and Circle:
class Ellipse
{
// Set the width of the shape.
virtual void width( unsigned int );
// Set the height of the shape.
virtual void height( unsigned int );
};
class Circle
{
// Set the width of the shape. If height is not the same as width, then
// set height to be equal to width.
virtual void width( unsigned int );
// Set the height of the shape. If width is not the same as height, then
// set width to be equal to height.
virtual void height( unsigned int );
};
It is very tempting to have Circle derive from Ellipse:
Outside of programming, one could argue that Circle is a special kind of Ellipse, just like a Square is a special kind of Rectangle.
They even have the same member functions: width() and height().
However, do not do it! Ellipse can do things a Circle cannot do, such as having a different width and height; therefore Circle should not be a kind of Ellipse.