bandera
bandera

Reputation: 49

abstract class and polymorphism

I am working on something with abstract class.

#include <iostream>
#include <vector>

using namespace std;

class Shape
{
protected:
    int m_size;
public:
    int getSize() { return m_size; }

    virtual bool isEqual(Shape *rhs) = 0;
};

Here is one of the derived class:

class Circle : public Shape
{
public:
    Circle(int size) { m_size = size; }

    bool isEqual(Shape *rhs)
    {
        Circle* circle = dynamic_cast<Circle*>(rhs);

        if(circle == 0)
            return false; // not a Circle

        return m_size == circle->getSize();
    }
};

And I store all shapes in a container (basically a vector of pointer of shape.

class Container
{
private:
    vector<Shape*> v;
public:   
    ~Container()
    {
        for(int i = 0; i < v.size(); i++) {
            cout << "Removind element Nr. " << i << endl;
            delete v[i];
        }
        v.erase(v.begin(), v.end());
    }

    bool add(Shape *shape) 
    {
        for(int i = 0; i < v.size(); i++) {

            if( v[i] == shape ) { 
                return false;
            }

            if( v[i]->isEqual(shape) ) {
                return false;
            }

        }
        v.push_back(shape);
        return true;
    }

};

I would like to know if it is possible to add element in the container without passing them as pointer. Currently it works like that:

Container c;
c.add(new Circle(10));

And I would like to use it in this way:

C.add(Circle(10));

What would be the solution?

Upvotes: 1

Views: 142

Answers (4)

Jarod42
Jarod42

Reputation: 217145

Similar to the clone method, You can modify your method add by something like (in C++11):

template<typename T, typename...Ts>
bool Container::add(Ts&&... args)
{
    std::unique_ptr<T> newShape(new T(std::forward<Ts>(args)...));
    for (const Shape* shape : v) {
        const auto* shapeT = dynamyc_cast<const T*>(shape);

        if (shapeT != nullptr && shapeT->isEqual(newShape) ) {
            return false;
        }

    }
    v.push_back(newShape.release()); // better to have std::vector<std::unique_ptr<Shape>>...
    return true;
}

And then use it like:

c.add<Circle>(10);

Upvotes: 0

Wojtek Surowka
Wojtek Surowka

Reputation: 20993

You need to move creation of the new object to the Container::add so the object is created only if it is not in the container. One way to achieve it is to declare the pure virtual Clone function in Shape and then define it in Circle:

virtual Shape* Clone()
{
    return new Circle(*this);
}

Then you can pass the object by value to add, and it will call Clone:

v.push_back(shape.Clone());

Upvotes: 0

Rakib
Rakib

Reputation: 7625

You can not if you want to use the container uniformly and save any type of Shape (circle,rectangle ..) in the same container. For example, currently you can add any shape by using the base class pointer. But if you want to add object, not pointer, you have to declare one container for each type. You will not be able to handle the objects uniformly.

Upvotes: 0

Danvil
Danvil

Reputation: 22981

Don't store polymorphic objects by value. This may result in object slicing.

In your case it is not even possibly to store objects of type Shape by value because the class has pure virtual methods.

If you want better resource management, e.g. automatically calling delete, you can use shared_ptr or unique_ptr.

.

Upvotes: 5

Related Questions