2011-03-07 2 views
8

Можно ли сделать абстрактное представление класса в C++ без объявления абстрактных методов? В настоящее время у меня есть класс Sprite с подклассом StaticSprite и DynamicSprite. Я хотел бы сделать класс класса Sprite абстрактным.Аннотация класс без абстрактных методов

Проблема в том, что нет никаких методов, которыми они делят. Ну, как StaticSprite, так и DynamicSprite могут совместно использовать метод draw(), но параметры этого метода различны, поэтому это не вариант.

Спасибо!

EDIT: Вот код, чтобы показать, что я пытаюсь сделать:

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

Как вы видите, бесполезно создавать объект Sprite, поэтому я хотел бы сделать этот абстрактный класс. Но я не могу сделать draw() abstract, поскольку он использует разные параметры.

+2

Почему он должен быть абстрактным без абстрактных методов? –

+1

Они, вероятно, не хотят, чтобы он был создан. – Erix

+1

Какой смысл иметь базовый класс, который не имеет методов для наследования? – Rob

ответ

15

Вы можете объявить ваш деструктор, как чисто виртуальные, так как все классы Имеется.

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

Однако вам необходимо определить этот деструктор в другом месте.

AbstractClass::~AbstractClass() {} 
+0

Проблема в том, что класс имеет некоторые элементы, которые должны быть удалены в деструкторе, поэтому сделать его абстрактным приведет к утечкам памяти ... – Bv202

+0

Поскольку деструктор базового класса является виртуальным, деструктор для деструктора производного класса будет вызываться, когда и где это необходимо. Не должно быть никаких проблем. –

+2

@ Bv202 - вы также обеспечиваете реализацию деструктора, поэтому вы можете его очистить. – fizzer

2

Нет, нет.

Вы можете использовать это, конечно:

class Sprite 
{ 
}; 

но, конечно, компилятор не будет жаловаться, когда вы пытаетесь создать экземпляр.

Вы можете добавить чистый виртуальный деструктор:

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

или вы можете сделать защищенный конструктор, останавливая экземпляра:

class Sprite 
{ 
protected: 
    Sprite(); 
}; 
0

Чтобы сделать чисто абстрактный класс, который не может быть создан без его получения, вы должны определить хотя бы один абстрактный метод.

например.

virtual void blah() const = 0; 

В противном случае вы можете использовать любой класс как абстрактный класс

+0

В конечном счете, вопрос «зачем беспокоиться»? – Randolpho

+0

@ Randolpho - вопрос изменился. Вы имеете в виду, почему существует абстрактный класс или почему он делает абстрактным, если у него нет методов? –

+0

Да, вопрос изменился. Я ненавижу, когда это происходит. :) – Randolpho

2

Традиционный способ сделать это, чтобы сделать чисто виртуальный деструктор, а затем реализовать его.

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

// .cpp 
Foo::~Foo() { 
} 
+1

Вы не можете реализовать чистый виртуальный. – Cthutu

+5

@Cthutu На самом деле вы * можете * реализовывать чистые виртуальные методы. Это просто означает, что ребенок должен реализовать его снова. –

+2

И в случае деструктора вы должны. – fizzer

11

Если класс не делает ничего, и ничего не дает, и существует только в качестве маркеров, нет никаких оснований беспокоиться о том или нет, это его абстрактного. Это по существу не проблема.

Если вы абсолютно уверены, что вы никогда не создавались, кроме как в контексте наследования, используйте protected constructors.

Пожалуйста, избегайте создания виртуального деструктора. Таким образом безумие.

2

Проблема в том, что не существует методов, которыми они делятся.

У вас там проблемы. Вы не должны использовать наследование здесь! Если вы не собираетесь заменять один класс другим, они просто не должны быть в отношениях между родителем и ребенком.

В зависимости от потребностей они должны быть полностью несвязаны, шаблоны или использовать композицию.

EDIT: На основе образца кода вы наследуетесь для повторного использования, и я бы предложил использовать композицию вместо этого. Sprite может быть struct, который принадлежит как DynamicSprite, так и StaticSprite. Вы можете поместить как можно больше/немного вспомогательной логики в Sprite.

+0

Я добавил код в свой первый пост. Как его решить? – Bv202

+0

-1, потому что вы не можете знать, следует ли использовать наследование или нет. Просмотрите рамки для посетителей Alexandrescu за отличную контр-точку для вашего заявления. –

3

Для конкретных обстоятельств вашего сообщения рассмотрите личное наследование. Таким образом, вы можете лениво использовать реализацию базы, не рекламируя ложное отношение IS-A к миру.

-1

Если вы действительно должны использовать наследование, рассмотреть возможность использования без виртуального интерфейса (NVI) идиом (см http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.3)

По существу базовый класс будет определять перегруженный, невиртуальный набор методов, которые называют защищенному чистыми виртуальные функции из производных классов.

То, что вы определенно не хотите делать, это перегрузка виртуальной функции (что похоже на то, что вы действительно хотите сделать).

1

Наилучший подход заключается в защите класса конструкторов, таким образом, класс не может быть реализован напрямую, и поэтому по существу аннотация:

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

Или, новый стиль:

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

деструктор, как правило, лучше публиковать, потому что вы можете захотеть удалить объект указателем базового класса.

Смежные вопросы