2017-02-02 1 views
0

main()이 MyApp 개체를 인스턴스화 한 다음 C++ 응용 프로그램에서 개체를 ReadConfig 함수로 전달합니다.함수 포인터를 통해 다른 서명으로 C++ 함수를 호출하는 방법

ReadConfig는 텍스트 기반 파일을 열고 구문 분석 한 다음 적절한 MyApp 메서드를 호출하여 구성합니다.

class MyApp 
{ 
private: 

public: 
    void SetRate(uint16_t); 
    void EnableLogging(bool); 
    void SetAddress(uint32_t); 
}; 

새로운 공개 메소드가 MyApp에 추가되면서 테이블을 업데이트하는 것처럼 간단 할 수 있도록 ReadConfig를 유지 관리하기 쉽도록하려고합니다. 나는 다음 해결책을 생각해 냈지만 나는 그것을 좋아하지 않는다. 정확한 위치에 0을 넣어야하기 때문에 유지하기가 어렵습니다.

다음은 내가 해결할 수 있었던 예입니다. 이 점을 개선하기위한 조언을 주시면 감사하겠습니다. 우리가 사용하는 C++ 컴파일러는 C++을 지원하지 않으므로 임베디드에서 작동합니다. 14 & 부스트가 없습니다. 그리고 나 자신을 그렇게하는 메커니즘을 이해하기 위해 STL 라이브러리를 사용하는 것을 피하고 싶습니다. 내가 함수 포인터를 통해 실제 MyApp를 함수를 호출 처리 함수를 호출, 내가 설정 파일을 읽을 때 다음

enum ARGTYPE {TBOOL, TUINT16, TUINT32}; 

template<typename TOBJ, typename TARG> 
struct TSetting 
{ 
    void (TOBJ::*FSet)(TARG); 
}; 

template<typename obj> 
struct SETTINGFN 
{ 
    const char      *setting_name; 
    ARGTYPE       Targ; 
    TSetting<obj,bool>    HBool; 
    TSetting<obj,uint16_t>   HUint16; 
    TSetting<obj,uint32_t>   HUint32; 
}; 

SETTINGFN<MyApp> MyAppSettings[] = 
{ 
    "logging" ,TBOOL,  &MyApp::EnableLogging, 0,0,0 
    ,"maxrate" ,TUINT16,  0,0,0,&MyApp::SetRate 
    ,"address" ,TUINT32,  0, &MyApp::SetAddress, 0,0 

}; 
unsigned int MyAppSettings_Count = sizeof(MyAppSettings)/sizeof(SETTINGFN<MyApp>); 

하고 분석 : 여기

내가 가진 것입니다. 당신의 디자인

bool AppSetting(MyApp &E, TObjnode &node) 
{ 
    bool rval = false; 

    for(unsigned int i=0; i<MyAppSettings_Count && !rval; i++) 
    { 
    if(node.GetName() == MyAppSettings[i].setting_name) 
    { 
     rval = true; 

     switch(MyAppSettings[i].Targ) 
     { 
     case TBOOL: 
      (E.*MyAppSettings[i].HBool.FSet)(node.GetValue().AsBool()); 
     break; 

     case TUINT16: 
      (E.*MyAppSettings[i].HUint16.FSet)(node.GetValue().Value()); 
     break; 

     case TUINT32: 
      (E.*MyAppSettings[i].HUint32.FSet)(node.GetValue().Value()); 
     break; 
     } 
    } 
    } 

    return(rval); 
} 
+0

고려 각 세터에 문자열을 전달하고이 유형 특정 재사용 가능한 구문 분석 코드를 불러올 수 있습니다? 그런 다음 모든 설정자는 동일한 유형이 될 수 있습니다. 문자열을 받아들이고 구문 분석 함수와 형식 안전 setter를 호출하는 트램 폴린이 더 좋을 수도 있습니다. –

+1

그래서 ... 새 속성/설정자가 추가 될 때마다 구성 발송 루틴에 함수 호출을 추가하지 않아도되도록하려면 새 속성/설정자가 추가 될 때마다 독점 데이터 구조를 업데이트하고 싶습니까? 각각 자신의 생각에 ... –

+0

나는 이것들을 생각했지만 현재 함수 서명을 변경하거나 새로운 것을 추가하는 것을 피하기를 희망했다. – Eric

답변

2

가시 덤불은 서로 다른 매개 변수 유형입니다 다음과 같이 그 기능입니다.

매개 변수가 구조로 추상화되면 함수를 하나의 고정 된 서명으로 단순화 할 수 있습니다.

기본 구조를 사용하여

, 서명 등 일반 수 :

struct Arguments_Base 
{ 
}; 

void SetRate(Arguments_Base& ab); 
void EnableLogging(Arguments_Base& ab); 
void SetAddress(Arguments_Base& ab); 

균일 서명을 가짐으로써이 함수 포인터 또는 함수 쉽게 검색하기, 표 또는 맵에 이용 될 수있는 개체. 검색 엔진은 일반적인 것일 수 있어야하며 데이터 크기에만 의존해야 검색 엔진이 아닌 데이터 (예 : 표) 만 변경하면됩니다.

각 인수 집합 유형은 Arguments_Base 클래스에서 파생되어야합니다. 그런 다음 함수는 기본 클래스 참조 dynamic_cast 수 있습니다.

은 참조 : 공장 디자인 패턴, 방문자 디자인 패턴을 두 번 파견을

+0

믿거 나 말거나, 나는 이것에 대해 생각했지만 현재의 함수 서명을 변경하거나 새로운 함수 서명을 추가하지 않기를 바랬다. 그러나 이것은 우아하다. – Eric

+0

헉. dynamic_cast. 설정 파일 읽기에도. – rubenvb

+0

@rubenvb 기본 클래스가 파생 클래스가 오버로드 할 수있는 메서드를 제공하는 경우 동적 캐스트는 필요하지 않습니다. NVI 디자인 패턴을 생각하십시오. Ben Boigt가 제안한 것처럼 Arguments_Base가 값 (ints, bool 등 ...)을 반환 할 수있는 String 클래스 인 경우 기본 클래스는 단순히 변환을 수행 할 수 있습니다. – Eric

관련 문제