2011-03-07 8 views
8

추상 메서드를 선언하지 않고 C++에서 클래스 추상을 만들 수 있습니까? 현재 StaticSprite 및 DynamicSprite 하위 클래스가있는 Sprite 클래스가 있습니다. 스프라이트 클래스를 추상적으로 만들고 싶습니다.추상 메서드가없는 추상 클래스

문제는 공유하는 방법이 없다는 것입니다. 음, StaticSprite와 DynamicSprite는 모두 draw() - 메서드를 공유하지만이 메서드의 매개 변수가 다르므로이 옵션이 아닙니다.

감사합니다. 편집

:

스프라이트 :

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() 추상화를 만들 수 없습니다.

+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

@ 랜돌 포 - 질문이 변경되었습니다. 왜 추상적 인 클래스를 가지는지, 아니면 메소드가 없다면 추상화하는 이유는 무엇입니까? –

+0

예, 질문이 변경되었습니다. 나는 그것이 일어날 때가 싫다. :) – Randolpho

2

이 일을하는 전통적인 방법은 순수 가상 소멸자를 확인하는 것입니다 어떠한 클래스를 사용할 수 있습니다.

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

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

순수 가상을 구현할 수 없습니다. – Cthutu

+5

@Cthutu 실제로 당신은 순수 가상 메서드를 구현할 수 있습니다. 그것은 단지 아이가 다시 그것을 구현해야한다는 것을 의미합니다. –

+2

소멸자의 경우 반드시해야합니다. – fizzer

11

클래스가 아무것도 제공하지 않고 마커로만 존재하는 경우 추상인지 여부는 걱정할 필요가 없습니다. 이것은 본질적으로 문제가 아닙니다.

상속의 경우를 제외하고 결코 인스턴스화되지 않도록하려면 protected constructors을 사용하십시오.

순수 가상 소멸자를 만들지 마십시오. 그런 식으로 광기가있다.

2

문제는 그들이 공유하는 메쏘드가 없다는 것입니다.

글쎄 거기에 문제가 있습니다. 여기에 상속을해서는 안됩니다! 한 클래스를 다른 클래스로 대체하려고하지 않는다면 부모와 자식 관계에 있지 않아야합니다.

필요에 따라 완전히 관련이 없거나 템플릿이거나 구성을 사용해야합니다.

편집 : 코드 샘플을 기반으로, 당신은 재사용을 상속하고 대신 컴포지션을 사용하는 것이 좋습니다. SpriteDynamicSpriteStaticSprite이 모두 소유 한 struct 일 수 있습니다. 적절한만큼 많은/작은 도우미 논리를 Sprite에 넣을 수 있습니다.

+0

첫 번째 게시물에 코드를 추가했습니다. 어떻게 해결해야합니까? – Bv202

+0

-1 상속을 사용해야하는지 여부를 알 수 없으므로 -1입니다. Alexandrescu의 방문자 틀을 검토하여 진술에 대한 훌륭한 대항점을 찾으십시오. –

3

게시물의 특정 상황에 대해서는 개인 상속을 고려하십시오. 그렇게하면 가짜 IS-A 관계를 세상에 광고하지 않고도 기반 구축을 지연적으로 사용할 수 있습니다.

-1

당신이 정말로 상속을 사용해야하는 경우, 기본적으로 기본 클래스는 순수한 보호 호출 방법의 오버로드가 아닌 가상 세트를 정의합니다

을 (http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.3 참조)이 아닌 가상 인터페이스 (NVI) 관용구의 사용을 고려 파생 클래스의 가상 함수

정말로 원하지 않는 것은 가상 기능을 오버로드하는 것입니다 (실제로는 원하는 것처럼 보입니다).

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

소멸자는 일반적으로 그것의 기본 클래스 포인터에 의해 객체를 삭제하기를 원하기 때문에 public으로 유지하는 것이 좋습니다.