抽象类和多态

时间:2014-04-30 09:36:45

标签: c++ polymorphism clone virtual

我正在研究抽象类的东西。

#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;
};

以下是派生类之一:

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();
    }
};

我将所有形状存储在一个容器中(基本上是一个形状指针的矢量。

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;
    }

};

我想知道是否可以在容器中添加元素而不将它们作为指针传递。 目前它的工作原理如下:

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

我想以这种方式使用它:

C.add(Circle(10));

解决方案是什么?

4 个答案:

答案 0 :(得分:5)

不要按值存储多态对象。这可能会导致object slicing

在您的情况下,甚至不可能按值存储Shape类型的对象,因为该类具有纯虚方法。

如果您想要更好的资源管理,例如自动拨打delete,您可以使用shared_ptrunique_ptr

答案 1 :(得分:0)

如果要统一使用容器并在同一容器中保存任何类型的Shape(圆形,矩形..),则不能。例如,目前您可以使用基类指针添加任何形状。但是如果要添加对象而不是指针,则必须为每种类型声明一个容器。您将无法统一处理这些对象。

答案 2 :(得分:0)

您需要将新对象的创建移动到Container::add,以便仅在对象不在容器中时才创建对象。实现它的一种方法是在Clone中声明纯虚拟Shape函数,然后在Circle中定义它:

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

然后您可以按价值将对象传递给add,它会调用Clone

v.push_back(shape.Clone());

答案 3 :(得分:0)

与克隆方法类似, 您可以通过类似(在C ++ 11中)的方式修改方法add

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;
}

然后使用它:

c.add<Circle>(10);