31

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.

MintyAnt
  • 2,978
  • 7
  • 25
  • 37
  • 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. – David Rodríguez - dribeas Jan 31 '13 at 17:45
  • @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? – MintyAnt Jan 31 '13 at 18:03

3 Answers3

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.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • 6
    Quick question - why does `~ShapeF` need to be implemented when it is declared as `pure virtual`? – Matt Kline Jan 31 '13 at 18:01
  • Thanks, this works perfectly. Any idea why this works? A pure virtual can't be defined, I thought. – MintyAnt Jan 31 '13 at 18:01
  • 9
    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. – Fred Larson Jan 31 '13 at 18:02
  • 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. – Serge Rogatch Aug 01 '17 at 18:05
  • 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. – offlinemark Jul 30 '20 at 18:39
  • 1
    This is the pedantic solution because `std::is_abstract_v` agrees. Protected constructor solution will not provide this. – Thomas Eding Jan 15 '22 at 04:53
28

Try using a protected constructor

Aditya Sihag
  • 5,057
  • 4
  • 32
  • 43
  • +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) – David Rodríguez - dribeas Jan 31 '13 at 17:44
  • @DavidRodríguez-dribeas Why should the destructor be protected? If it's protected, you can't delete the object. – James Kanze Jan 31 '13 at 17:48
  • 1
    @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) – David Rodríguez - dribeas Jan 31 '13 at 17:50
  • 1
    I like Herb Sutter's advice about making base class destructors either protected and non-virtual or public and virtual. See [Virtuality](http://www.gotw.ca/publications/mill18.htm), guideline 4. The difference is whether you want to allow polymorphic deletion. – Fred Larson Jan 31 '13 at 17:56
  • @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. – James Kanze Jan 31 '13 at 18:06
  • @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*). – David Rodríguez - dribeas Jan 31 '13 at 18:19
  • @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. – James Kanze Jan 31 '13 at 18:38
-3

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.

Andrew
  • 101
  • 1
  • 8