2

문자열 키와 연관된 멤버 변수 포인터의 맵을 구현하려고합니다. 모든 변수의 범위는 기본 클래스 "BaseA" 맵에서 변수에 액세스 할 때는 원래 클래스 유형 (getDesc()가 샘플에서만 사용됨) 만 있으면 원래 유형을 검색 할 필요가 없습니다.다형 멤버 변수 포인터의 std :: map

이 코드는 GNU g ++ 6.2.1에서 컴파일되고 실행되지만, 내가 읽은 바에 따르면 reinterpret_cast는 이식성이 없으므로 다른 컴파일러에서 작동하지 않을 수 있습니다. 이것이 맞습니까? 아니면이 코드가 C++ 표준을 준수합니까? reinterpret_cast를 사용하지 않고이 작업을 수행 할 수있는 다른 방법이 있습니까? "Vars"는 기본 copy-contructor 및 copy-assignment 구현으로 복사 할 수 있어야합니다.

샘플 코드 :

#include <iostream> 
#include <sstream> 
#include <map> 
#include <typeinfo> 

using namespace std; 

struct BaseA 
{ 
    virtual string getDesc() = 0; 
}; 

struct A1 : BaseA 
{ 
    string getDesc() override { return "This is A1"; } 
}; 

struct A2 : BaseA 
{ 
    string getDesc() override { return "This is A2"; } 
}; 

struct Vars 
{ 
    A1 a1; 
    A2 a2; 

    map< string, BaseA Vars::* > vars; 

    Vars() 
    { 
     vars["A1_KEY"] = reinterpret_cast<BaseA Vars::*>(&Vars::a1); 
     vars["A2_KEY"] = reinterpret_cast<BaseA Vars::*>(&Vars::a2); 
    } 

    BaseA& get(const string& key) 
    { 
     auto it = vars.find(key); 
     if (it != vars.end()) 
     { 
      return this->*(it->second); 
     } 
     throw std::out_of_range("Invalid variable key:[" + key + "]"); 
    } 
};         

int main() 
{ 
    Vars v; 

    cout << "a1 description :" << v.get("A1_KEY").getDesc() << endl; 
    cout << "a2 description :" << v.get("A2_KEY").getDesc() << endl; 

    return 0; 
} 
+1

종류의 무관하지만 나는'std :: string'을'std :: map'을위한 키로 사용하는 것을 추천합니다. 가능한 경우 (대부분의 경우)'enum '을 사용하십시오. – DeiDei

+0

감사합니다 DeiDei. 가능한 경우 열거 형을 사용합니다. 그러나이 경우 아이디어는 키가 사용자가 명령 줄로 입력한다는 것이므로 문자열을 더 잘 이해할 수 있습니다 – SNJ

답변

2

예, reinterpret_cast이 어떤 작업을 수행하는지에 대한 very few guarantees이 있고, 그런 다음 원래의 형태로 다시 캐스팅하지 않는 한 다른 회원에게 하나의 포인터로 캐스팅하는 것은 (그 중 하나가 아닌, 정말 도움이되지 않습니다).

std::function를 사용하는이 하나를 수행 할 수있는 안전하고 쉬운 방법 : 변경하기 위해 vars 사전을 필요가 없습니다 경우

struct Vars 
{ 
    A1 a1; 
    A2 a2; 

    map< string, std::function<BaseA&(Vars&)> > vars; 

    Vars() 
    { 
     vars["A1_KEY"] = &Vars::a1; 
     vars["A2_KEY"] = &Vars::a2; 
    } 

    BaseA& get(const string& key) 
    { 
     auto it = vars.find(key); 
     if (it != vars.end()) 
     { 
      return it->second(*this); 
     } 
     throw std::out_of_range("Invalid variable key:[" + key + "]"); 
    } 
}; 

주, 당신은 static const 회원으로 바꿀 수 있습니다. (이것은 당신이 정의하고 소스 파일의 클래스 밖에서 그것을 초기화해야 의미 할 것이다.)

+0

어떻게 작동하는지 조금 설명해 주시겠습니까? & Vars :: a1' 함수로 변환 할 수 있습니까? – Phil1970

+0

@ Phil1970 표준은 정확히 어떻게 말하지 않는가, 단지 포인터가 유효한 ['Callable'] (http://en.cppreference.com/w/cpp/concept/Callable)이고 호출하는 것이 'arg * * ptm' 또는'(* arg). * ptm' 중 하나는'arg'의 타입에 따라 다릅니다. 그래서'[ptm] (Vars & v) -> BaseA & {return v. * ptm; }'(컴파일러 관련 라이브러리 *는'reinterpret_cast' 트릭과 같은 것을 안전하게 사용할 수 있기 때문에 더 효율적일 수 있습니다.) – aschepler

+0

감사합니다 aschepler !!! 이게 내가 찾고있는거야 !! – SNJ