Container with unique pointer to an abstract class - c++

I've been trying to create a factory method which allocates subclasses entities from a given abstract class, which I'll name Shape for simplicity. It looks something like this:
Shape* makeChild(Type type) const
{
switch(type)
{
case QUAD:
return new Quad();
case RECTANGLE:
return new Rectangle();
case TRIANGLE:
return new Triangle();
default:
return new Rectangle();
}
}
Now I'm trying to keep these entities inside a structure, and I understand I need to allocate Shape* entities, but I would like for the objects to be automatically managed by using std::unique_ptr<Shape> instead.
My ShapeTree struct looks something like this:
struct ShapeTree {
int index_;
std::vector<std::unique_ptr<Shape>> shapes_;
void add(Shape* shape) {shapes_.push_back(std::make_unique<Shape>(shape));}
void removeLast(){shapes_.pop_back();}
ShapeTree(const int index) : index_{index}{}
ShapeTree(const int index, std::vector<std::unique_ptr<Shape>>& shapes) : index_{index}, shapes_{std::move(shapes)}{}};
Compiler complains about having Shape default copy constructor being marked as deleted, I understand this is the case since I have a unique pointer and I can't copy it, but deleting the copy constructor and assignment and using the default move constructor and assignment won't work either. It also complains that no instances of Shape can be created as it is abstract, even thought I am only returning subclasses.
A different version of the same structure works completely fine when using raw pointers. E.g.
struct ShapeTree {
int index_;
std::vector<Shape*> shapes_;
void add(Shape* shape) {shapes_.push_back(shape);}
void removeLast(){shapes_.pop_back();}
ShapeTree(const int index) : index_{index}{}
ShapeTree(const int index, std::vector<Shape*>& shapes) : index_{index}, shapes_{std::move(shapes)}{}};
What am I doing wrong? How can i achieve the same result using unique_ptr?

The immediate cause of your error is this line:
void add(Shape* shape) {shapes_.push_back(std::make_unique<Shape>(shape));}
std::make_unique is used to create a new object to be managed by the unique_ptr.
In your case you already allocated your object with new, and therefore you should simply use the std::unique_ptr constructor.
An immediate solution would be:
//----------------------------------------vvvvvvvvvvvvvvv-----------------
void add(Shape* shape) {shapes_.push_back(std::unique_ptr<Shape>(shape));}
However:
A better solution will avoid using new altogether.
makeChild can return a std::unique_ptr which can be moved into the vector:
#include <vector>
#include <memory>
struct Shape {};
struct Rectangle : public Shape {};
// ... all the derived Shapes
std::unique_ptr<Shape> makeChild()
{
// Here you can create a std::unique_ptr to any derive from Shape based on a `Type` parameter you can add:
return std::make_unique<Rectangle>();
}
struct ShapeTree {
int index_;
std::vector<std::unique_ptr<Shape>> shapes_;
//---------------------------------------------------------vvvvvvvvv------
void add(std::unique_ptr<Shape> shape) { shapes_.push_back(std::move(shape)); }
void removeLast() { shapes_.pop_back(); }
// ...
};
int main()
{
ShapeTree st{ 333 };
st.add(makeChild());
}

Related

How should I write the constructor for my class

I have a container class to which i can send a Geometry object as constructor argument.
Geometry is a polymorphic class as interface for other geometric types like Sphere and Rectangle.
My question is that in Container class the constructor with arguments "Container(std::string str, Geometry* geometry)" can i code this in more flexible manner.
Whenever i will add a new SubClass to Geometry than i would need to write another IF condtion in Container class Constructor.
include "pch.h"
#include <iostream>
#include<fstream>
#include "Container.h"
#include "Geometry.h"
#include "Sphere.h"
#include "Rectangle.h"
#include "Container.h"
int main()
{
const char* fileName = "saved.txt";
Sphere sph;
Rectangle rect;
Container contSphere("ABC", &sph);
Container contRectangle("DEF", &rect);
Sphere* s = (Sphere*)contSphere.getGeomtry();
s->PrintGeom();
Rectangle* r = (Rectangle*)contRectangle.getGeomtry();
r->PrintGeom();
do
{
std::cout << '\n' << "Press a key to continue...";
} while (std::cin.get() != '\n');
}
///////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <string>
class Geometry
{
private:
std::string stdstringGeom;
std::string stdstrType;
public:
Geometry() : stdstringGeom("GeometyrString"), stdstrType("Geometry") {}
virtual ~Geometry() {}
virtual std::string getType()
{
return stdstrType;
}
virtual void PrintGeom()
{
std::cout << "geometry virtual function";
}
};
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "Geometry.h"
class Sphere : public Geometry
{
private:
std::string stdstrSphere;
std::string stdstrType;
public:
Sphere() : Geometry() , stdstrSphere( "DefaultSphere") , stdstrType("Sphere") {}
Sphere( std::string str) : Geometry() , stdstrSphere(str) , stdstrType("Sphere"){}
void PrintGeom()
{
std::cout << "Sphere Virtual Function" << std::endl;
}
std::string getType()
{
return stdstrType;
}
};
///////////////// Defination for Constructor class////////////////////
#include "Geometry.h"
#include "Sphere.h"
#include "Rectangle.h"
class Container
{
private:
std::string stdstrCont;
Geometry* geom;
public:
Container() : stdstrCont("NoName") { geom = new Geometry; }
Container(std::string str, Geometry* geometry) : stdstrCont(str)
{
// I am doing this to avoid slicing and i want to do a deep copy.
if (geometry->getType() == "Sphere")
{
Sphere* sph = (Sphere*)geometry;
geom = new Sphere(*sph);
}
else if (geometry->getType() == "Rectangle")
{
Rectangle* rec = (Rectangle*)geometry;
geom = new Rectangle(*rec);
}
}
~Container()
{
if (geom != nullptr)
delete geom;
}
Geometry* getGeomtry()
{
return geom;
}
void PrintContainer()
{
std::cout << stdstrCont;
}
};
Your design is all backward, and a consequence is that you are making the Container responsible for working out the type of all Geometry objects passed to it, in order to copy them. That will make your Container a maintenance nightmare - if someone creates another class derived from Geometry, they can forget to modify Container accordingly.
You've also omitted code that is relevant to your question (like virtual destructors) and included code that is irrelevant to the question (declaration of std::string members, and initialisation of them in constructors, and other virtual functions).
Instead, it would be better to make the class Geometry, and its derived classes, responsible for copying themselves.
At heart would be the Geometry class itself
#include <memory> // for std::unique_ptr
class Geometry
{
public:
Geometry() {};
virtual ~Geometry() = default;
virtual std::unique_ptr<Geometry> Clone() const = 0;
};
(I've omitted the std::string members for convenience). The derived classes then override the Clone() function, viz;
class Sphere: public Geometry
{
public:
Sphere() : Geometry() {};
~Sphere() = default;
std::unique_ptr<Geometry> Clone() const {return std::unique_ptr<Geometry>(new Sphere(*this));};
};
// similarly for other shapes
The Clone() function is pure virtual in Geometry, so the derived classes cannot be instantiated unless you remember to override it.
The responsibility for cloning rests with Geometry and its derived classes - and the compiler will helpfully diagnose an error if a class is derived from Geometry that does not override the Clone() function.
Then, all a Container needs to do is have a member std::unique_ptr<Geometry> or (if you intend to have a set of them) a std::vector<std::unique_ptr<Geometry> >.
For the case where the Container only needs a single Geometry, the definition of Container might be
class Container
{
public:
Container() : geom() {};
Container(Geometry *p) : geom(p->Clone()) {};
Container(const Container &c) : geom(c.geom->Clone()) {};
Container &operator=(const Container &c)
{
geom = c.geom->Clone(); // this will release the existing c.geom
return *this;
};
~Container() = default;
private:
std::unique_ptr<Geometry> geom;
};
The reason I've used std::unique_ptr<Geometry> in the above (instead of Geometry * as in your code) is that std::unique_ptr<> avoids the need to explicitly decide when to destroy a Geometry object.
The no-argument constructor of Container initialises to containing a null Geometry (i.e. a null pointer).
The constructor of Container that accepts a Geometry * clones the passed object, and does not assume ownership of it. This means the caller is responsible for the lifetime of the object it passes. This is consistent with your main(), which constructs objects of automatic storage duration.
Note that I'm following the "rule of three" - if a non-default version of a copy constructor, copy assignment, or destructor is defined, then the other two should also be defined. The operator=() in the above works in a manner consistent with the copy constructor (i.e. it clones objects in the Container, rather than causing Geometry objects to be shared between Containers). The destructor is explicitly defined as the default, since the Container is not explicitly managing lifetime of its members (the destructor of std::unique_ptr does the work).

How to create a dynamic array that can hold different objects all derived from the same base class in C++

I have an assignment that doesn't allow me to use the vector class. I have a base class called Shape and different derived class such as Rectangle and Circle and i have to create my own vector class that has a dynamic array which can hold all these different shapes. I have used the following method that seems to work well
int **shape=new int*[capacity];
My problem comes with the "add_shape" function. I know how to add a shape individually using for example:
shape[0]=new Rectangle();
shape[1]=new Circle();
But how would one go about creating a universal function for adding a shape that could either be a rectangle or circle for instance.
Just wanted to elaborate on Nicky C's comment.
#include <memory>
using namespace std;
class Shape {};
class Rectangle : public Shape {};
class Circle : public Shape {};
template <class Type> class MyVector {}; // implement (with push method, etc.)
int main()
{
MyVector<unique_ptr<Shape>> v;
v.push(unique_ptr<Shape>(new Rectangle()));
v.push(unique_ptr<Shape>(new Circle()));
return 0;
}
The vector contains elements of type unique_ptr<Shape> which is the base class. Each element of the vector can be unique_ptr<Rectangle> or unique_ptr<Circle> as well. However, if the vector were of type unique_ptr<Rectangle>, each element would have to be of type unique_ptr<Rectangle> (i.e. it could not be of type unique_ptr<Circle>).
Since you are allocating memory on the heap, using unique_ptr just makes sure that you don't need to call delete yourself.
One of the strengths of inheritance/polymorphism is that you can use a derived class wherever a base class is needed. It is an important key concept. For instance, as in your code above, you can do:
Shape *s = new Shape();
s = new Rectangle();
s = new Circle();
This also applies to function parameters:
class DynamicArray
{
private:
Shape **_shapes[];
...
public:
void add_shape(Shape *s)
{
// Add the shape to _shapes;
}
...
};
void main()
{
DynamicArray array;
array.add_shape(new Shape()):
array.add_shape(new Rectangle()):
array.add_shape(new Circle()):
}

Manage abstract classes in std container

After a lot of research I still don't understand how to deal with an abstract class collection with smart pointers.
Here are the errors I got:
error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Shape; _Dp = std::default_delete<Shape>]'
base_ptr s = shapes.front();
error: no matching function for call to 'std::unique_ptr<Shape>::unique_ptr(Shape&)'
shapes.push(base_ptr(b));
By compiling the minimal code to replicate the error (code online avaiable).
#include <queue>
#include <memory>
class Shape {
public:
virtual int getPerimeter() =0;
};
typedef std::unique_ptr<Shape> base_ptr;
class Circle : public Shape {
public:
virtual int getPerimeter() { return 1; };
};
class Square : public Shape {
public:
virtual int getPerimeter() { return 0; };
};
class ShapeManager {
public:
ShapeManager();
void useShape() {
if(shapes.empty())
throw "Work stack is empty.";
base_ptr s = shapes.front();
s->getPerimeter();
shapes.pop();
}
void submitShape(Shape &b) {
shapes.push(base_ptr(b));
}
private:
std::queue<base_ptr> shapes;
};
int main(int argc, char **argv) {
ShapeManager s();
Circle c;
s.submitShape(c);
s.useShape();
return 1;
}
It works if I declare the queue as queue<Shape*> but I don't want to deal with pointers -meaning *.
EDIT, this code compiles. Thanks everyone. This article suggested by Guillaume Racicot helps seeing clearer the situation.
#include <queue>
#include <memory>
class Shape {
public:
virtual int getPerimeter() =0;
};
typedef std::unique_ptr<Shape> base_ptr;
class Circle : public Shape {
public:
Circle() {};
virtual int getPerimeter() { return 1; };
};
class Square : public Shape {
public:
virtual int getPerimeter() { return 0; };
};
class ShapeManager {
public:
ShapeManager();
void useShape() {
if(shapes.empty())
throw "Work stack is empty.";
base_ptr s = std::move(shapes.front());
s->getPerimeter();
shapes.pop();
}
void submitShape(base_ptr b) {
shapes.push(std::move(b));
}
private:
std::queue<base_ptr> shapes;
};
int main(int argc, char **argv) {
ShapeManager s;
base_ptr c = std::make_unique<Circle>();
s.submitShape(std::move(c));
s.useShape();
return 1;
}
The container is a distraction. The problem is that unique_ptr is not copyable; if it were, it wouldn't be unique. So you probably need to add a call to std::move:
base_ptr s = std::move(shapes.front());
This means something different from what the original code might have been intended to do; it removes the object from the container. If that's not what you wanted, then std::move isn't the right answer and, probably, unique_ptr is not the right mechanism.
There are many problems in your example, not just misuse of smart pointers. First, the most obvious once is your declaration of s:
ShapeManager s();
This declares a function named s that returns a ShapeManager and takes no parameter.
Maybe you meant to declare an object of type ShapeManager?
ShapeManager s{};
// Or
ShapeManager s;
Secondly, you are misusing smart pointer. You have a queue of unique pointer. A unique pointer is a RAII wrapper around a free store allocated object. That means that it's a wrapper that is constructed with an object allocated with new. In your example, you're not doing that. You are constructing unique pointer with an object that has automatic storage.
A smart pointer that points to a automatic storage allocated object is the observer pointer: is must not own, delete or try to manage anything about that object. In fact, observer pointer is a language feature instead of a library one. It's commonly called a pointer.
This is your code with usage of observer pointers:
template<typename T>
using observer_ptr = T*;
struct ShapeManager {
void useShape() {
if(shapes.empty())
throw "Work stack is empty.";
auto s = shapes.front();
s->getPerimeter();
shapes.pop();
}
void submitShape(Shape &b) {
shapes.push(&b);
}
private:
std::queue<base_ptr> shapes;
};
int main() {
ShapeManager s;
Circle c; // Automatic storage
Rectangle r; // Automatic storage too.
s.submitShape(c);
s.submitShape(r);
s.useShape();
}
However, you might not want to hold them using automatic storage. My guess is you want to use std::unique_ptr everywhere instead. This allow the object submitted to the shape manager to outlive it's scope. For that you'll need to allocate objects on the free store. The most common way is to use std::make_unique:
struct ShapeManager {
void useShape() {
if(shapes.empty())
throw "Work stack is empty.";
// We must create a reference,
// Using simply auto would require copy,
// Which is prohibited by unique pointers
auto&& s = shapes.front();
s->getPerimeter();
shapes.pop();
}
void submitShape(base_ptr b) {
shapes.push(std::move(b));
}
private:
std::queue<base_ptr> shapes;
};
int main() {
ShapeManager s;
// Allocated on the free store,
// The lifetime of c and r are managed by
// The unique pointer.
auto c = std::make_unique<Circle>();
auto r = std::make_unique<Rectangle>();
s.submitShape(std::move(c));
s.submitShape(std::move(r));
s.useShape();
}

Whether using dynamic cast for providing input for derived class virtual function is recommended?

I read some of the answers in What is the proper use case for dynamic_cast.
The line which best matched my situation here is
#include<iostream>
class Shape
{
public:
virtual void draw()=0;
virtual ~Shape(){};
};
class Rectangle : public Shape
{
public:
int length;
int breath;
void draw()
{
std::cout<<"RECTANGE"<<std::endl;
}
};
class Circle : public Shape
{
public:
int diameter;
void draw()
{
std::cout<<"CIRCLE"<<std::endl;
}
};
/*Abstract Factory*/
Shape* getShapeObj(int type)
{
switch(type)
{
case 1:
return new Rectangle;
case 2:
return new Circle;
/* many types will be added here in future. */
}
return NULL;
};
void drawShapes(Shape *p_shape[],int len)
{
for(int i=0;i<len;i++)
p_shape[i]->draw();
}
int main()
{
Shape *l_shape[2];
l_shape[0]=getShapeObj(1);
l_shape[1]=getShapeObj(2);
Rectangle *l_rec=dynamic_cast<Rectangle*>(l_shape[0]);
if(l_rec)
{
l_rec->length=10;
l_rec->breath=20;
}
Circle *l_circle=dynamic_cast<Circle*>(l_shape[1]);
if(l_circle)
l_circle->diameter=25;
drawShapes(l_shape,2);
}
Essentially, virtual functions only work in some cases, not all of them.
My problem is to pass the input for the virtual function and inputs will vary from type to type. Whether using dynamic cast is recommended here?
The solution is perfect forwarding of function parameters, introduced in c++11.
template<typename ...CtorArgs>
Shape* getShapeObj(int type, CtorArgs&& ctor_args...)
{
switch(type)
{
case 1:
return new Rectangle(std::forward<CtorArgs>(ctor_args)...);
// many types will be added here in future.
}
return NULL;
}
Obviously making the function a template, defeats the purpose of hiding the hierarchy (as well as forcing rather strict requirements on the number of parameters to the constructors). But if the base contains a map of functions that do the construction, which each derived class updates with a pointer to function that constructs it, you can still have information hiding.
I have recently written an answer about storing type erased function pointers in a map, with some static type checking forwarded to run time.
In this particular case, looks like your main function is taking too much responsibility. What if you have Circle, Hexagon, MyFancyFigure types? All of them should be initialized in main in different branches?
It would be much better to move that "initialization" logic to a separate virtual function init in your classes (or even to the constructor). The code would look like this:
class Shape
{
public:
virtual void draw()=0;
virtual void init()=0;
virtual ~Shape(){};
};
class Rectangle : public Shape
{
public:
int length;
int breath;
void draw()
{
//Draw Rectangle
}
void init()
{
length = 10;
breath = 20;
}
};
int main()
{
Shape *l_shape=getShapeObj(1);
// Calls different code of "init" method depending on the actual object type
l_shape->init();
l_shape->draw();
delete l_shape;
}
Also, please note that this initialization logic may be place in some other place, like constructor of the class or the factory method. But main is definitely the wrong place.

How to store templated objects of different type in container?

Assuming I have a vector (or list or whatever container might be more suitable here) that I would like to store multiple objects (or pointers) of a templated type in:
std::vector<MyClass<double>> v;
// std::vector<MyClass<double> *> v;
Unfortunately, I want to store different templated objects in this container (and I need to access them ideally at constant time).
My first intuition was to create some sort of WrapperClass around MyClass that would internally manage any MyClass as a member variable, but it's not clear to me how I could pass along the appropriate type through to MyClass:
#include <iostream>
#include <string>
#include <stdlib.h>
#include <vector>
using namespace std;
template<typename T>
class MyClass
{
public:
MyClass() {}
~MyClass() {}
};
// templating this of course works, but it doesn't solve my problem
template<typename T>
class WrapperClass
{
public:
WrapperClass()
{
m_object = MyClass<T>();
}
~WrapperClass() { }
private:
MyClass<T> m_object;
};
int main()
{
WrapperClass<bool> tmp = WrapperClass<bool>();
std::vector<WrapperClass<bool> *> v;
return 0;
}
So is there (A) a different container than vector that I could be using for this problem or (B) a way to select the type of MyClass in WrapperClass inside the constructor? I was thinking of something along the lines of:
class WrapperClass2
{
public:
WrapperClass2(unsigned int typeId)
{
switch (typeId)
{
case 0: m_object = new MyClass<bool>();
case 1: m_object = new MyClass<int>();
case 2: m_object = new MyClass<float>();
default: m_object = new MyClass<double>();
}
}
~WrapperClass2()
{
delete m_object;
}
private:
MyClass * m_object;
};
Another idea may be to have some parent AbstractType that I would be using in the vector, but I'm not sure how that would help with the templated type problem.
Different instantiations of a class template are completely unrelated types, so you cannot have a container that directly stores them.
You have a few options:
Keep a collection of pointers to some base class that your class template inherits from:
class Base
{
virtual ~Base {}
virtual void someMethod() const = 0;
};
template <typename T>
class MyClass : public Base
{
void someMethod() const
{
// stuff
}
};
int main()
{
std::vector<std::unique_ptr<Base>> objs;
objs.push_back(std::make_unique<MyClass<int>>());
objs.push_back(std::make_unique<MyClass<std::string>>());
for (auto& i : objs) {
i->someMethod();
}
}
This is a fairly simple approach, but it incurs a bit of runtime overhead with dynamic allocation and RTTI. Note also that someMethod can't return T, since it's a method on a parent class that doesn't know what T is.
Use some sort of type-erased wrapper like boost::any (or the forthcoming std::any in C++17).
#include <any>
#include <string>
#include <vector>
template <typename T>
class MyClass {
public:
T someMethod() const {
// stuff
return {};
}
};
void someFunctionThatTakesInt(int i) {}
void someFunctionThatTakesString(std::string s) {}
int main() {
std::vector<std::any> objs;
objs.push_back(MyClass<int>());
objs.push_back(MyClass<std::string>());
for (const auto& i : objs) {
if (i.type() == typeid(MyClass<int>)) {
auto& mc = std::any_cast<const MyClass<int>&>(i);
someFunctionThatTakesInt(mc.someMethod());
} else if (i.type() == typeid(MyClass<std::string>)) {
auto& mc = std::any_cast<const MyClass<std::string>&>(i);
someFunctionThatTakesString(mc.someMethod());
}
}
}
This approach means that you can have someMethod return T, but makes it much harder to handle retrieving objects from the vector because you have to figure out what type they are before you can do anything with them (you're essentially rolling your own RTTI).
Don't.
Rethink why you need this in the first place. Maybe another approach could work better. Maybe something with callbacks or visitors. I don't know your objective here, so I can't really say what's appropriate.
Can you do a base class and have all other classes inherit from the base class.
And you can make a list that holds a list of base class elements.
Now this is more of a pseudo example, but I hope this way would solve your problem.
Example:
class Base:
{
}
class whatever:Base
{
}
class whatever2:Base
int main()
{
list<whatever> object1;
list<whatever2> object2;
list<list<Base>> mainObj;
mainObj.push_back(object1);
mainObj.push_back(object2);
}
Now if the problem is to just have different datatypes than abstract datatypes in some container. Can't you have a Singly Link List, and have your Node generic.
Example:
template<typenameT>
struct Node
{
T data;
Node* next;
}
class LinkList
{
//Your code:
}