12

Is it possible to make a class abstract in C++ without declaring any abstract methods? Currently, I have a Sprite class with a StaticSprite and DynamicSprite subclass. I would like to make the Sprite class abstract.

The problem is that there aren't any methods they share. Well, both StaticSprite and DynamicSprite might share a draw()-method, but the parameters of this method are different so this isn't an option.

Thank you!

EDIT: Here is the code to demonstrate what I'm trying to do:

Sprite:

class Sprite
{
    public:
        Sprite(HINSTANCE hAppInst, int imageID, int maskID);
        ~Sprite();

    protected:
        HINSTANCE hAppInst;
        HBITMAP hImage;
        HBITMAP hMask;
        BITMAP imageBM;
        BITMAP maskBM;
        HDC hSpriteDC;
};

Staticsprite:

class StaticSprite : public Sprite
{
    public:
        StaticSprite(HINSTANCE hAppInst, int imageID, int maskID);
        ~StaticSprite();

        void draw(Position* pos, HDC hBackbufferDC);
};

Dynamicsprite:

class DynamicSprite : public Sprite
{
    public:
        DynamicSprite(HINSTANCE hAppInst, int imageID, int maskID);
        ~DynamicSprite();

        void draw(HDC hBackbufferDC);
};

As you see, it's useless to create a Sprite-object, so I would like to make that class abstract. But I can't make draw() abstract as it uses different parameters.

Bv202
  • 3,924
  • 13
  • 46
  • 80

9 Answers9

19

You can declare your destructor as pure virtual, since all classes have one.

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

However, you will need to define this destructor elsewhere.

AbstractClass::~AbstractClass() {}
Tugrul Ates
  • 9,451
  • 2
  • 33
  • 59
  • The problem is that the class has some members which should get deleted in the destructor, so making it abstract would cause memory leaks... – Bv202 Mar 07 '11 at 21:42
  • 1
    Since the base class destructor is virtual, destructor for your derived class destructor will be called when and where needed. There shouldn't be any problems. – Tugrul Ates Mar 07 '11 at 21:43
  • 2
    @Bv202 - you also provide an implementation of the destructor, so you can cleanup there. – fizzer Mar 07 '11 at 21:44
  • 2
    @Bv202 You can still implement a pure virtual destructor to clean up the memory. – Mark B Mar 07 '11 at 21:44
  • 2
    Well, that may or may not be what the OP wants -- it does add overhead to the class and changes semantics. – Simon Richter Mar 07 '11 at 21:44
  • 5
    If it contains data management, it isn't very abstract, is it? Another option is to make the destructor protected. That forces you do derive from it, as it cannot be destroyed alone. – Bo Persson Mar 07 '11 at 21:46
15

If the class does nothing and provides nothing, and only exists as a marker, there's no reason to worry about whether or not it's abstract. This is essentially a non-issue.

If you absolutely wish to ensure that one is never instantiated except in the context of inheritance, use protected constructors.

Please avoid making a pure virtual destructor. That way madness lies.

Community
  • 1
  • 1
Randolpho
  • 55,384
  • 17
  • 145
  • 179
3

The best approach is to protect the class constructors, this way the class cannot be instantiated directly and therefore it's essentially abstract:

class SomeBaseClass 
{
protected:
    SomeBaseClass() {}
    SomeBaseClass(const SomeBaseClass &) {}
    SomeBaseClass &operator=(const SomeBaseClass&) {}
public:
    virtual ~SomeBaseClass() {}
    ...
};

Or, newer style:

class SomeBaseClass 
{
protected:
    SomeBaseClass() = default;
    SomeBaseClass(const SomeBaseClass &) = delete;
    SomeBaseClass &operator=(const SomeBaseClass&) = delete;
public:
    virtual ~SomeBaseClass() = default;
    ...
};

Destructor is generally better to keep public because you might want to delete an object by its base class pointer.

Sergey Galin
  • 426
  • 6
  • 8
3

No there isn't.

You could use this of course:

class Sprite
{
};

but of course the compiler isn't going to complain when you try to create an instance of it.

You may add a pure virtual destructor:

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

or you may make the constructor protected, stopping the instantiation:

class Sprite
{
protected:
    Sprite ();
};
Cthutu
  • 8,713
  • 7
  • 33
  • 49
3

For the specific circumstances of your post, consider private inheritance. That way you get to lazily use the implementation of the base, without advertising a spurious IS-A relationship to the world.

fizzer
  • 13,551
  • 9
  • 39
  • 61
2

The traditional way of doing this is to make a pure virtual destructor, then implement it.

// .h
struct Foo {
  virtual ~Foo() = 0;
};

// .cpp
Foo::~Foo() {
}
Erik
  • 88,732
  • 13
  • 198
  • 189
  • 1
    You can't implement a pure virtual. – Cthutu Mar 07 '11 at 21:44
  • 5
    @Cthutu Actually you *can* implement pure virtual methods. It just means the child has to implement it again. – Mark B Mar 07 '11 at 21:46
  • 2
    And in the destructor case, you must. – fizzer Mar 07 '11 at 21:49
  • 1
    Yes you can, see e.g. 10.4/2: "A pure virtual function need be defined only if explicitly called with the qualified-id syntax (5.1)." and 12.4/7: "A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly- declared) is virtual." – Erik Mar 07 '11 at 21:50
2

The problem is that there aren't any methods they share.

Well there's your problem right there. You shouldn't be using inheritance here! If you aren't intending to substitute one class for the other they just shouldn't be in a parent-child relationship.

Depending on the needs they should be totally unrelated, templates, or use composition.

EDIT: Based on the code sample, you're inheriting to reuse and I would suggest using composition instead. Sprite could be a struct that is owned by both DynamicSprite and StaticSprite. You can put as much/little helper logic into Sprite as appropriate.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • I have added the code in my first post. How should you solve it? – Bv202 Mar 07 '11 at 21:54
  • -1 because you can't possibly know if inheritance should be used or not. Review Alexandrescu's visitor framework for an excellent counter-point to your statement. – Edward Strange Mar 07 '11 at 22:00
0

To make a purely abstract class that cannot be instantiated without deriving from it - you must define at least one abstract method.

eg.

 virtual void blah() const = 0;

Otherwise you can use any class as an abstract class

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
-1

If you really must use inheritance, consider using the non-virtual interface (NVI) idiom (see http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.3)

Essentially the base class will define an overloaded, non-virtual set of methods, which call protected pure virtual functions from the derived classes.

What you definately don't want to do is overload a virtual function (which it looks like you really want to do).

J T
  • 4,946
  • 5
  • 28
  • 38