【问题标题】:C++ abstract class without pure virtual functions?没有纯虚函数的 C++ 抽象类?
【发布时间】:2013-01-15 21:40:01
【问题描述】:

我有一个基类

class ShapeF
{
public:
    ShapeF();
    virtual ~ShapeF();

    inline void SetPosition(const Vector2& inPosition) { mPosition.Set(inPosition); }

protected:
    Vector2 mPosition;
}

显然有一些省略的代码,但你明白了。 我将其用作模板,并带有一些有趣(省略)的枚举,这是一种确定我正在使用哪种形状的方法

class RotatedRectangleF : public ShapeF
{
public:
    RotatedRectangleF();
    virtual ~RotatedRectangleF();
protected:
    float mWidth;
    float mHeight;
    float mRotation;
}

ShapeF 通过定位和定义类型的枚举来完成其工作。 它有访问器和修改器,但没有方法。

我可以让 ShapeF 成为一个抽象类,以确保没有人尝试实例化 ShapeF 类型的对象吗?

通常,这可以通过在 ShapeF 中使用纯虚函数来实现

//ShapeF.h
virtual void Collides(const ShapeF& inShape) = 0;

但是,我目前正在一个单独的班级中处理碰撞。 我可以把所有东西都移过来,但我想知道是否有办法让一个类抽象......没有纯虚函数。

【问题讨论】:

  • 您正在尝试使用标记(枚举)和强制转换重新实现动态调度......这将在未来很快成为一个痛苦。我会重新考虑设计。
  • @DavidRodríguez-dribeas 我认为这是最简单的方法,static_casting 一切。如果我想重新设计,我会完全删除 ShapeF() ,其中包含所有多态性,并让每个形状都是它自己的人。除非你有不同的建议?

标签: c++ polymorphism abstract-class pure-virtual


【解决方案1】:

如果您的编译器是 Visual C++,那么还有一个“抽象”关键字:

class MyClass abstract
{
    // whatever...
};

虽然 AFAIK 无法在其他编译器上编译,但它是 Microsoft 自定义关键字之一。

【讨论】:

    【解决方案2】:

    你可以声明,并实现,一个纯虚析构函数:

    class ShapeF
    {
    public:
        virtual ~ShapeF() = 0;
        ...
    };
    
    ShapeF::~ShapeF() {}
    

    与您已有的相比,这只是一小步,并且会阻止 ShapeF 被直接实例化。派生类不需要更改。

    【讨论】:

    • 快速提问——为什么~ShapeF声明为pure virtual时需要实现?
    • 谢谢,这很好用。知道为什么会这样吗?我想,无法定义纯虚拟。
    • 它必须被定义,否则派生类不能破坏它们的基类。可以定义任何纯虚函数,允许派生类委托给它们。
    • 如果我声明一个虚拟的析构函数,然后为它定义一个主体,那么我是否必须从每个派生类的析构函数中显式调用基析构函数?这将需要大量愚蠢的代码:我必须在每个派生类中定义空析构函数,只是为了调用基类的析构函数。
    • 请注意,此解决方案会产生存储开销 - 由于(未使用的)vtable 指针,ShapeF 的大小将至少增加一个指针大小。下面的受保护构造函数解决方案不会受到这种影响。
    【解决方案3】:

    尝试使用受保护的构造函数

    【讨论】:

    • +1,析构函数应该是protected并且是非虚拟的。如果ShapeFnew-ed 而不是delete-d (但这本身就是一个错误),则存在一个极端情况,这并不能解决问题。
    • @DavidRodríguez-dribeas 为什么要保护析构函数?如果它受到保护,则无法删除该对象。
    • @JamesKanze:我想 should 是一个有点强硬的词。我觉得析构函数是virtual 的唯一原因是遵循总是 如果要派生类型,则将析构函数设为虚拟的建议。使析构函数protected 解决了相同的基本问题,并为不实例化的问题提供了解决方案(至少在堆栈和堆中,除非您对内存泄漏感到满意:) 无论如何,我的感觉是整个应该重新审视设计(正如我在对问题的评论中提到的那样)
    • 我喜欢 Herb Sutter 关于使基类析构函数受保护且非虚拟或公共且虚拟的建议。请参阅Virtuality,准则 4。不同之处在于您是否要允许多态删除。
    • @DavidRodríguez-dribeas 我假设如果该类具有虚函数,并且他希望它是抽象的,那么目标是一切都将通过指向它的指针而不是派生的指针来完成班级。毕竟,这是最常见的情况。如果它的析构函数受到保护,则意味着您将无法删除它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    • 1970-01-01
    • 2019-04-20
    • 1970-01-01
    • 1970-01-01
    • 2011-03-21
    • 2019-12-08
    相关资源
    最近更新 更多