2017-05-16 3 views
0

스토어 오브젝트 봉사 인터페이스, 나는 CSound에 집에서 만든 클래스 다루는 자신이 CSound에를 만들 수 CSoundEngine, 그것의 인스턴스를 처리하고있어 (내 CSoundEngine에 저장되어) 포인터를 반환합니다.OOP - 나는 현재 C++ 프로젝트에서 일하고 있어요

사실 디자인 목적으로 인터페이스에 대한 포인터를 반환하고 싶습니다. 예를 들어 실제 객체를 벡터에 저장하고 C++ (또는 Java)의 인터페이스를 통해 제공 할 수 있습니까?

대답이 "예"이면 벡터를 확장하여 자식 클래스에 따라 특정 인터페이스를 반환 할 수있는 일반 객체를 저장할 수 있습니까?

감사합니다. 내가 제대로 이해하면

+0

왜 두 가지 다른 언어를 묻는 중입니까? 그것은 당신의 질문을 너무 넓게 만듭니다. 가장 관심이 적은 질문을 삭제하십시오. –

+0

질문의 두 번째 부분을 이해하지 못합니다. 명확히하십시오. –

+0

이 질문은 위험한 것처럼 보입니다 ... 추상적 기본 클래스가 사용되는 것에 대해 묻고 있습니까? 만약 당신이 어떤 코드를 작성하고 당신이 의미심장 한 예에서 무엇을하려고하는지 보여주는 것이 더 좋을 것입니다. – luk32

답변

0

그래서, 당신은 같은 것을 가지고

class CSound { 
    // Whatever 
}; 

class CSoundEngine { 
    // A lot of stuff 
    CSound* createSound(/* ... */); 
}; 

을 그리고 당신은 CSound에 반환 할 싶지는 않지만 인터페이스는, 그것이 내부적와 벡터에 저장되어 있지만 특정 유형의 ?

당신의 인터페이스를 만들고 그들로부터 파생 : - 인터페이스 - 그럼 첫 번째 문제

는 해결하기 쉽습니다. 당신이 괜찮 ISound에서 파생 만 CSound에 사용하려는 경우

class ISound { 
    public: 
     ISound(const ISound&)    = delete; 
     ISound(ISound&&)     = delete; 
     ISound& operator =(const ISound&) = delete; 
     ISound& operator =(ISound&&)  = delete; 

     virtual ~ISound() = default; 

     // Your ISound public API here as pure virtual methods, e.g.: 
     virtual const std::string name() const = 0; 
    protected: 
     ISound() = default; 
}; 

class ILoopable { 
    public: 
     ILoopable(const ILoopable&)    = delete; 
     ILoopable(ILoopable&&)     = delete; 
     ILoopable& operator =(const ILoopable&) = delete; 
     ILoopable& operator =(ILoopable&&)  = delete; 

     virtual ~ILoopable() = default; 

     // Your ILoopable public API here as pure virtual methods, e.g.: 
     virtual const bool isLoopingActive()  const = 0; 
     virtual  bool setLoopingActive(bool)  = 0; 
    protected: 
     ILoopable() = default; 
}; 

class CDefaultSound 
    : public ISound { 
    public: 
     CDefaultSound() = default; 

     // ISound implementation 
     inline const std::string name() const { return mName; } 

    private: 
     std::string mName; 
}; 


class CLoopableSound 
    : public ISound, 
     public ILoopable { 
    public: 
     CLoopableSound() 
      : ISound(), 
       ILoopable(), 
       mLoopingActive(true), 
       mName("") 
     { 
     } 


     // ISound implementation 
     inline const std::string name() const { return (mName + "(Loopable)"); } 

     // ILoopable implementation 
     inline const bool isLoopingActive() const { return mLoopingActive; } 
     inline bool setLoopingActive(bool active) { mLoopingActive = active; } 

    private: 
     bool  mLoopingActive; 
     std::string mName; 
}; 

int main() 
{ 
    // Now you can do something like this, for example, using polymorphism 
    // in your CSoundEngine (see below)... 
    ISound *pDef  = new CDefaultSound(); 
    ISound *pLoopable = new CLoopableSound(); 
} 

, 당신은 여러 클래스를 필요로하지 않지만, 그때 인터페이스를 사용하는 점을 이해하지 않습니다. 중요 : 순수 가상 인터페이스 메서드로 인해 인터페이스 클래스를 설치할 수 없으므로 shared_ptr 또는 unique_ptr과 같은 포인터 또는 RAII 포인터를 사용해야합니다 (RAII 권장 사항 ...)

두 번째 문제 - 특정 유형을 벡터에 저장하는 것 - 단일 벡터 foreach 허용 유형이 필요 했으므로 훨씬 더 어렵습니다. 또는! 인터페이스 인스턴스를 저장하고 인터페이스 메소드 만 사용하십시오!

class DefaultSoundCreator { 
    static ISound* createSound(/* Criteria */) { ... } 
}; 

template <typename TSoundCreator> 
class CSoundEngine { 
    public: 
     CSoundEngine() 
      : mSoundCreator() { 
     } 

     std::shared_ptr<ISound> createSound(/* some criteria */); 

    private: 
     std::vector<std::shared_ptr<ISound>> mSounds; 
}; 

// cpp 
std::shared_ptr<ISound> CSoundEngine::createSound(/* some criteria */) { 
    // Use criteria to create specific sound classes and store them in the mSOunds vector. 
    ISound *pSound = TSoundCreator::createSound(/* forward criteria for creation */); 
    std::shared_ptr<ISound> pSoundPtr = std::shared_ptr<ISound>(pSound); 

    mSounds.push_back(pSoundPtr); 

    return pSoundPtr; 
} 

int main() { 
    std::unique_ptr<CSoundEngine<DefaultSoundCreator>> pEngine = std::make_shared<CSoundEngine<DefaultSoundCreator>>(); 

    std::shared_ptr<ISound> pSound = pEngine->createSound(/* Criteria */); 
} 

당신이 ISound에서 제공하는 기능에 의존 수있는이 방법하지만 창조주 클래스를 지정하여, 당신은 일반적인 사운드 엔진 사운드 생성을 제어 할 수있다.

이제 인터페이스 기반 클래스를 사용하여 실제로 유형을 지우는 문제 : 인덱스 2에 CLoopableSound를 저장했지만 사운드 엔진의 createSound() 메소드 인 std :: shared_ptr로 인해 ISound-Interfacemethods 만 사용할 수 있다는 사실을 알고있었습니다. ;

ILoopable- 비헤이비어에 어떻게 액세스합니까?

그리고이 그것을 철학적가되는 지점입니다 ... 내가 추천 읽기 :

https://akrzemi1.wordpress.com/2013/11/18/type-erasure-part-i/ Type erasure techniques https://aherrmann.github.io/programming/2014/10/19/type-erasure-with-merged-concepts/

하나 개의 기술 제가 사용하려면 : 마지막으로

class CLoopableSound 
    : public ISound { 
    // All the above declarations and definitions 
    // AND: 
    static std::shared_ptr<CLoopableSound> fromISound(const std::shared_ptr<ISound>& other, bool *pSuccess = nullptr) { 
     std::shared_ptr<CLoopableSound> p = std::static_pointer_cast<CLoopableSound>(other); 
     if(pSuccess) 
      *pSuccess = p.operator bool(); 

     return p; 
    } 
}; 

// Use like 
std::shared_ptr<CLoopableSound> pLoopable = CLoopableSound::fromISound(pSoundEngine->getSound(...)); 
if(pLoopable) { 
    // Use 
} 

, 물론 FromISound 함수를 템플릿으로 만들고 캐스트를 사용하여 CLoopableSound 대신 ILoopable에만 액세스 할 수 있습니다.

관련 문제