【问题标题】:abstract class and polymorphism抽象类和多态
【发布时间】:2014-04-30 09:36:45
【问题描述】:

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

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

解决办法是什么?

【问题讨论】:

  • 顺便说一句,缺少虚拟析构函数。
  • 需要虚拟析构函数吗?
  • @bandara:添加它几乎是免费的,并且它避免了 memleak(一旦你在子类中有析构函数)......

标签: c++ polymorphism clone virtual


【解决方案1】:

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

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

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

.

【讨论】:

  • 但问题不建议按值存储,仅按值传递给add
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

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

    v.push_back(shape.Clone());
    

    【讨论】:

    • 这仍将调用new,涉及对复制构造函数的额外调用,并且您需要为每个派生类提供一个方法Clone。有什么好处?
    • 这样做的好处是解决了拥有一个指向多态对象的指针容器的问题,并且只有当它不在容器中时才添加一个对象。您还有其他想法如何解决吗?请注意,我的解决方案可以轻松扩展为使用智能指针并避免在容器析构函数中手动删除。
    【解决方案4】:

    类似于克隆方法, 您可以修改您的方法 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);
    

    【讨论】:

      猜你喜欢
      • 2017-02-26
      • 1970-01-01
      • 2014-08-23
      • 2013-08-13
      • 1970-01-01
      • 1970-01-01
      • 2016-03-12
      • 2017-01-30
      • 1970-01-01
      相关资源
      最近更新 更多