C++ abstract class without pure virtual functions?
Asked Answered
S

3

32

I have a base class

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

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

protected:
    Vector2 mPosition;
}

Obviously with some ommitied code, but you get the point. I use this as a template, and with some fun (ommited) enums, a way to determine what kind of shape i'm using

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

ShapeF does its job with the positioning, and an enum that defines what the type is. It has accessors and mutators, but no methods.

Can I make ShapeF an abstract class, to ensure nobody tries and instantiate an object of type ShapeF?

Normally, this is doable by having a pure virtual function within ShapeF

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

However, I am currently dealing with collisions in a seperate class. I can move everything over, but i'm wondering if there is a way to make a class abstract.. without the pure virtual functions.

Suttle answered 31/1, 2013 at 17:32 Comment(2)
You are trying to reimplement dynamic dispatch with tagging (enum) and casting... that will become a pain soon in the future. I would reconsider the design.Helyn
@DavidRodríguez-dribeas I figured this was the easiest approach, static_casting everything. If I wanted to re-design, I would remove ShapeF() altogether, with it all polymorphism, and have each shape be it's own person. Unless you had a different suggestion?Suttle
E
56

You could declare, and implement, a pure virtual destructor:

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

ShapeF::~ShapeF() {}

It's a tiny step from what you already have, and will prevent ShapeF from being instantiated directly. The derived classes won't need to change.

Epicardium answered 31/1, 2013 at 17:33 Comment(6)
Quick question - why does ~ShapeF need to be implemented when it is declared as pure virtual?Introrse
Thanks, this works perfectly. Any idea why this works? A pure virtual can't be defined, I thought.Suttle
It has to be defined, or the derived classes can't destroy their base class. Any pure virtual function can be defined, which allows derived classes to delegate to them.Quartermaster
If I declare a destructor virtual, and then define a body for it, do I have then to call the base destructor explicitly from destructors of each derived class? This would require a lot of dumb code: I would have to define empty destructors in each derived class, just to call the destructor of base class.Bart
Note that this solution incurs storage overhead- ShapeF's size will increase by at least a pointer size because of the (unused) vtable pointer. The protected constructor solution below does not suffer this.Pansie
This is the pedantic solution because std::is_abstract_v<ShapeF> agrees. Protected constructor solution will not provide this.Edacity
G
30

Try using a protected constructor

Gullett answered 31/1, 2013 at 17:36 Comment(7)
+1, the destructor should be protected and non-virtual. There is a corner case where this does not solve the problem, if ShapeF is new-ed and never delete-d (but that is a bug in itself)Helyn
@DavidRodríguez-dribeas Why should the destructor be protected? If it's protected, you can't delete the object.Moriah
@JamesKanze: I guess should is a bit of a strong word. I have the feeling that the only reason that the destructor is virtual is to follow the recommendation of always making the destructor virtual if the type is meant to be derived. Making the destructor protected solves the same underlying issue and provides a solution to the problem of not instantiating (at least in the stack, and in the heap unless you are happy with memory leaks :) At any rate my feel is that the whole design should be revisited (as I mentioned in the comment to the question)Helyn
I like Herb Sutter's advice about making base class destructors either protected and non-virtual or public and virtual. See Virtuality, guideline 4. The difference is whether you want to allow polymorphic deletion.Quartermaster
@DavidRodríguez-dribeas I'm assuming that if the class has virtual functions, and he wants it to be abstract, the goal is that everything will be done through pointers to it, and not to the derived class. This is, after all, the most usual case. And if its destructor is protected, that means that you won't be able to delete it.Moriah
@JamesKanze: "It has accessors and mutators, but no methods" is what lead me to think the only virtual member function is the destructor (which is also what gave me a funny smell).Helyn
@DavidRodríguez-dribeas It's true that the design does seem a bit suspect, so it's hard to know exactly what he's trying to do.Moriah
C
-2

If your compiler is Visual C++ then there is also an "abstract" keyword:

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

Though AFAIK it will not compile on other compilers, it's one of Microsoft custom keywords.

Coif answered 20/11, 2019 at 18:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.