抽象类和多态性

abstract class and polymorphism

本文关键字:多态性 抽象类      更新时间:2023-10-16

我正在用抽象类做一些事情。

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

解决方案是什么?

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

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

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

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

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

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

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

v.push_back(shape.Clone());

类似于克隆方法,您可以通过以下方式修改方法add(在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;
}

然后像这样使用:

c.add<Circle>(10);