2012-02-22 1 views
2

내 첫 번째 C++ 입문은 오디오 합성 라이브러리 (EZPlug)를 제작하는 것입니다.가상 템플릿 기능을 사용하지 못하게하려면 어떻게해야합니까?

라이브러리는 상호 연결된 오디오 생성기 및 프로세서 개체의 그래프를 쉽게 설정할 수 있도록 설계되었습니다. 우리는 EZPlugGenerators를 호출 할 수 있습니다.

모든 프로세서 유닛은 입력으로 하나 이상의 EZPlugGenerators를 허용 할 수 있습니다.

중요한 점은이 EZPlugGenerator의 모든 구성 방법이 체인 가능하다는 것입니다. 다시 말해, 합성 그래프를 설정하는 데 사용되는 메소드는 항상 부모 객체에 대한 포인터를 반환해야합니다.

  mixer.addGenerator(
      a(new Panner()) 
      ->setVolume(0.1) 
      ->setSource(
       a(new TriggererPeriodic()) 
       ->setFrequency(
        v(new FixedValue(1), "envTriggerFreq") 
       ) 
       ->setTriggerable(
        a(new Enveloper()) 
        ->setAllTimes(v(0.0001), v(0.05), v(0.0f, "envSustain"), v(0.01)) 
        ->setAudioSource(
         a(new SineWaveMod()) 
         ->setFrequency(
          a(new Adder()) 
          ->addGenerator(a(new Adder())) 
          ->addGenerator(v(5000, "sineFreq")) 
          ->addGenerator(
           a(new Multiplier()) 
           ->addVal(v("sineFreq")) 
           ->addVal(
            a(new TriggererPeriodic()) 
            ->setFrequency(v("envTriggerFreq")) 
            ->setTriggerable(
             a(new Enveloper()) 
             ->setAllTimes(0.1, 0.1, 0, 0.0001) 
             ->setAudioSource(v(1, "envAmount")) 
            ) 
           ) 
          ) 
         ) 
        ) 
       ) 

      ) 
     ); 

위의 코드 저장소의 "A"와 "V"기능과 객체에 대한 참조를 반환하고 처리 : 그것은 나에게 매우 친절이 같은 객체 관계의 중첩 된 성격을 보여주는 구문을 사용할 수 있습니다 그들을 검색하고 그들을 파괴.

나는 C++에 대한 나의 접근 방식이 좀 이상하다고 생각하지만 언어가 내가 실제로 프로그램하고 싶은 방식을 실제로 수용 할 수 있다는 것을 알고있다. 내 질문에

이제

내가로부터 상속 입력을 수용 할 수있는 모든 EZPlugGenerators에 대한 공통의 슈퍼 클래스를 생성하고 싶습니다. 이 슈퍼 클래스에는 각 서브 클래스에 의해 오버라이드 (override)되는 메소드 "addInput"가 있습니다. 문제는 "addInput"이 수퍼 클래스가 아닌 서브 클래스의 인스턴스에 대한 포인터를 반환하도록하려는 경우에 발생합니다.

이 허용되지 않습니다 :

EZPlugProcessor* addInput(EZPlugGenerator* generator) 

그 슈퍼 클래스가 아닌 내가 너무 행복 해요 chainability을 파괴 sublass의 인스턴스에 대한 포인터를 반환하기 때문에.

나는이 시도 :

template<typename T> virtual T* addInput(EZPlugGenerator* obj){ 

을하지만 컴파일러는 내가 가상 템플릿 함수를 만들 수 없습니다 알려줍니다.

여기에서 상속을 사용하지 않아도됩니다. 입력을받을 수있는 모든 단일 EZPlugGenerator에 'addInput'을 구현할 수 있습니다. 단일 부모 클래스로 모든 것을 모으는 것만으로도 공통점이 있다는 것을 분명히 알 수 있으며 addInput이 한 객체를 다른 객체에 연결할 수있는 적절한 방법이라는 사실을 입증하는 데 도움이됩니다.

따라서 상속을 사용하여 클래스 그룹의 모든 구성원이 'addInput'메서드를 구현해야하며 해당 메서드가 자식 클래스의 인스턴스에 대한 포인터를 반환하도록 허용 할 수있는 방법이 있습니까?

+5

너무. 많은. '새로운'. 내 눈! – Xeo

+0

오 대장 ... –

+0

죄송합니다. 나는 그것을 가능한 한 간단하게 유지하려고 노력했다. – morgancodes

답변

4

가상 기능에 의해 (당신이 다음

struct MyProcessor : EZPlugProcessor { 
    virtual MyProcessor *addinput(EZPlugGenerator* generator) { 
     ... 
     return this; 
    } 
}; 

만큼 호출자가 알고있는대로 기본 클래스에

virtual EZPlugProcessor *addInput(EZPlugGenerator* generator) = 0; 

을 정의 할 수 있습니다 즉, 공변 반환 형식을 가질 수 있습니다 그들이 사용하는 타입)은 객체가 MyProcessor이고, MyProcessor과 관련된 다른 함수와 함께 addInput을 연결할 수 있습니다.

귀하의 상속 계층 구조가 더 수준이있는 경우, 불행히도 당신은 때때로 자신이 작성 확인할 수있는 것들 :

struct MySpecificProcessor : MyProcessor { 
    virtual MySpecificProcessor *addinput(EZPlugGenerator* generator) { 
     return static_cast<MySpecificProcessor*>(MyProcessor::addInput(generator)); 
    } 
}; 

addInput의 반환 형식은 most-에 "포인터입니다 EZPlugProcessor에서 지정 할 수있는 방법이 없기 때문에 파생 된 유형의 개체 ". 파생 된 각 클래스는 자체에 대한 공분산을 "활성화"해야합니다.

+0

+1 당신이 내가 쓰던 대답을 썼습니다. : - / –

1

예, C++은 이미 공변 반환 유형을 제공합니다. 당신이 C++로 체인 LISP 작성하는 것보다 구성을 설정하는 다른 방법이있는 경우 고려할 수 있습니다, 그래서 아무도 당신의 코드를 읽을 수 없습니다 한편

class Base 
{ 
public: 
    virtual Base* add() = 0 { return <some base ptr>; } 
}; 

class Child : public Base 
{ 
public: 
    virtual Child* add() { return <some child ptr>; } 
}; 

.C++에서

+0

고마워요. B. 정확히 무엇을 찾고 있어요. 내 코드의 읽을 수 없음에 관해서는 ... 이상하게 생각되며, 대부분의 경우 잘못된 접근입니다. 나는 너와 거기에 동의한다. 그러나 저는이 방식을 좀 더 "정상적인"방법으로하고 그 책이 너무 느리고 역설적으로 읽기가 힘들어서 씨름 한 후에 왔습니다. 순수한 C++에서 객체 트리를 빌드하고 구성하는 다른 방법에 대한 아이디어가 있으면 빠른 스캔에서 전체 구조의 요지를 얻을 수있는 구문을 사용하여 공유하십시오! – morgancodes

+0

@morgancodes : 하나의 옵션은 도메인 간 언어를 정의하여 구성 요소 간의 관계를 설명하는 것입니다. 아마 XML/YAML/JSON 형식 일 것입니다. 아마도 처음부터 새로 발명 한 형식 일 것입니다. 그런 다음 문자열 리터럴을 코드에 (또는 런타임에로드하여) 구문 분석하고 그에 따라 객체 트리를 작성하십시오.분명히 성능을 지불하지만 (비용은 설정에만 있습니다), 특히 구문 분석기를 작성하는 경우에는 더 많은 코드를 작성하여 지원해야 할 수도 있습니다. 그 이점은 정의가 * 정확히 * 당신이 원하는대로 C++ 구문과 타협하지 않는다는 것입니다. –

+0

@SteveJessop 확실히 확실한 접근법이며 오디오 합성 시스템에서 매우 일반적입니다. 그러나이 프로젝트의 목표는 최대한 단순하게 유지하고 C++로 모두 유지하는 것입니다. – morgancodes

관련 문제