2009-04-08 5 views
2

회원에 대한 포인터는별로 사용되지 않지만 실제로 강력합니다. 어떻게 사용 했습니까? 그리고 가장 멋진 점은 무엇입니까?멤버 및 멤버 함수에 대한 포인터를 사용하면 무엇이 가장 좋습니까?

편집 :부스트 :: 바인드향상을 나열 예를 들어 가능한 것들을 나열 너무 많이하지 :: 기능이 잘되지 않습니다. 대신 그 (것)들을 가진 차가운 사용법 대신에? 나는 그들 자신이 매우 차갑다는 것을 압니다. 그러나 이것은 그것이 무엇에 관한 것이 아닙니다.

답변

5

큐에있는 모든 기준의 목록을 저장할 수있는 순수한 구조로 기준 데이터를 사용하려면 한 번 필요했습니다. 그리고 구조를 GUI와 기타 필터 요소 등으로 바인딩해야했습니다. 그래서 멤버 함수에 대한 포인터는 물론 멤버에 대한 포인터가 사용되는 솔루션을 생각해 냈습니다.

당신이 기준 필드를 감싸고

class Field 
{ 
public: 
    Field(const std::string& name, 
      Criteria::DataRefType ref): 
     name_(name), 
     ref_(ref) 
    {} 
    std::string getData(const Criteria& criteria) 
    { 
     return criteria.*ref_; 
    } 
    std::string name_; 
private: 
    Criteria::DataRefType ref_; 
}; 

와 필드의 문자열 표현과 결합 할 수있는 것보다 이제 그럼 당신은 당신이 때마다를 사용하는 모든 필드를 등록 할 수 있습니다 당신은

struct Criteria 
{ 
    typedef std::string Criteria::* DataRefType; 
    std::string firstname; 
    std::string lastname; 
    std::string website; 
}; 

있다고 가정 해 봅시다 원하는 : GUI, 직렬화, 필드 이름에 의한 비교 등.예를 fields.forEach(serialization); 또는

GuiWindow(Criteria& criteria): 
    criteria_(criteria) 
{ 
    fields_.forEach(std::bind1st( 
         std::mem_fun(&GuiWindow::bindWithGui), 
         this)); 
} 
void bindWithGui(Field field) 
{ 
    std::cout << "name " << field.name_ 
       << " value " << field.getData(criteria_) << std::endl; 
}; 
1

그럼 표준 함수를 사용하여 멤버 함수에 대한 포인터를 정기적으로 사용합니다. 내가 아는 한 그들에 관해서 특별한 것이 없다. 멤버 함수에

3

포인터 당신은 부스트 ​​: : 바인드에 사용 된 멤버 변수와 함수를 결합 평소 펑를 얻을 수의 for_each

vector<SomeClass*> v = getAVector(); 
for_each(v.begin(), v.end(), mem_fun(&SomeClass::print)); 
+0

을, 예컨대 그것을 사용하려면 그렇게하지 이중에 대한 Serialisers을했다? – dirkgently

+0

@dirkgently 나는 여기서 mem_fun이 더 적절하다고 생각했습니다. 확인 중 ... – JaredPar

+0

@JaredPar : SomeClass가 포인터가 아닌 경우 mem_fun이 작동하지 않습니다 –

1

를 사이비의 람 바어 식을 만들기위한 중대하다. 그들과 함께
다음 작업은 일반적인 기능의 사용에 좋아하는 것 :

  • 콜백 또는 신호 함수로 전달;
  • 표준 알고리즘을 사용합니다.
  • std :: map/set에서 비교로 사용;
  • 데이터 접근 자로 사용;
0

예를 들어 이전 버전과 마찬가지로 콜백 기능으로 사용할 수 있습니다.

3

나는 그들과 함께했던 가장 시원한 일을 오래 전했습니다. 오늘은 더 나은 방법이있을 것입니다.

네트워크 관리 도구 용으로 자체 생성 명령 줄 구문 분석기를 만들었습니다. 관리 대상 객체를 나타내는 클래스는 하위 클래스 (이름, 포인터에 대한 팩토리 구성원), 인스턴스 (ID, 목록의 인스턴스에 대한 포인터) 및 명령 (name, 멤버 함수에 대한 포인터)). 이 파서가 같은 것들을 처리 할 수 ​​:

SET NETWORK ROUTE 192.168.0.0 HOPS 1 

또는

QUERY NETWORK NAMESERVER servername 

경로 또는 이름 서버에 대해 아무것도 모른 채.

0

나는 내가 쓴이 거대한 응용 프로그램에 대한 "DomainEditor"수업 시간에 그것을했다 요구함으로써

class Fields 
{ 
public: 
    Fields() 
    { 
     fields_.push_back(Field("First Name", &Criteria::firstname)); 
     fields_.push_back(Field("Last Name", &Criteria::lastname)); 
     fields_.push_back(Field("Website", &Criteria::website)); 
    } 
    template < typename TFunction > 
    void forEach(TFunction function) 
    { 
     std::for_each(fields_.begin(), fields_.end(), 
         function); 
    } 
private: 
    std::vector<Field> fields_; 
}; 

. 데이터베이스의 모든 유형 (도메인) 테이블은 프로그램 관리자가 편집 할 수 있으며 클라이언트가 다른 유형과 다른 이름으로 일부 유형을 호출 했으므로 편집 할 수있는 대화 상자를 만들었습니다. 글쎄, 나는 15 개 이상의 도메인 유형에 대한 편집기를 만들고 싶지 않았기 때문에 각 클래스를 캐스팅 할 수있는 수퍼 클래스를 작성하고 각 도메인 테이블에 간단한 호출을 할 수있는 포인터를 사용했다. 각각은 모두 동일한 속성, 설명 (이름), ID, 비활성 플래그 및 필수 플래그를 지원합니다. , 매크로 호출의 많은 그런

#define DomainList(Class, Description, First, Next, Item, UpdateItem, DeleteItem, IsItemRequired, MaxLength) { \ 
    CWFLHandler *handler = new CWFLHandler; \ 
    handler->pWFL = new Class;\ 
    handler->LoadFirstType = (LoadFirst)&Class::First;\ 
    handler->LoadNextType = (LoadNext)&Class::Next;\ 
    handler->LoadType  = (Load)&Class::Item;\ 
    handler->UpdateType = (Update)&Class::UpdateItem;\ 
    handler->DeleteType = (Delete)&Class::DeleteItem;\ 
    handler->IsRequiredType= (IsRequired)&Class::IsItemRequired; \ 
    handler->MAX_LENGTH = MaxLength;\ 
    PopulateListBox(m_Domain, Description, (long)handler); }\ 

: 그래서, 코드가 내 전화 설치에 매크로 시작 (여기에 단지 하나의 하나입니다)

DomainList(CConfigWFL, "Application Parameter Types",  LoadFirstParameterType,     LoadNextParameterType,     LoadParameterTypeByTypeId,          UpdateParameterType,    DeleteParameterType,    IsParameterTypeRequired,   LEN_APPL_PARAMETER_DESC); 

그런 다음 호출 편집 데이터는 모두 공통적이었고 모든 코드를 복제 할 필요가 없었습니다 ...

예를 들어 DropDownList (매크로로 채워짐)에서 선택한 항목으로 목록을 채우려면 코드가 이렇게 :

if((pWFLPtr->pWFL->*pWFLPtr->LoadFirstType)(true)) 
    { 
    do 
    { 
     m_Grid.AddGridRow(); 
     m_Grid.SetCheck(COLUMN_SYSTEM,   (pWFLPtr->pWFL->*pWFLPtr->IsRequiredType)(pWFLPtr->pWFL->TypeId)); 
     m_Grid.SetCheck(COLUMN_STATUS,  pWFLPtr->pWFL->InactiveIndc == false); 
     m_Grid.AddTextToGrid(COLUMN_NAME, pWFLPtr->pWFL->TypeDesc); 
     m_Grid.AddTextToGrid(COLUMN_DEBUG, pWFLPtr->pWFL->TypeId); 
     m_Grid.AddTextToGrid(COLUMN_ID,  pWFLPtr->pWFL->TypeId); 
    } 
    while((pWFLPtr->pWFL->*pWFLPtr->LoadNextType)()); 

물론 이것은 대화 상자의 일부인 클래스에 저장되었습니다. 그리고 간단히 클래스의 새 인스턴스를 만들어 ListBox의 ItemData 멤버에 저장했습니다. 그래서 대화 상자가 닫히면 모든 것을 정리해야했습니다. 그러나이 메시지에서이 코드를 제외했습니다.

typedef bool (CMyWFL::*LoadFirst)(bool); 
    typedef bool (CMyWFL::*LoadNext)(); 
    typedef bool (CMyWFL::*Load)(long); 
    typedef bool (CMyWFL::*Update)(long, const char*, bool); 
    typedef bool (CMyWFL::*Delete)(long); 
    typedef bool (CMyWFL::*IsRequired)(long); 

    class CWFLHandler { 
    public: 
     CWFLHandler() {}; 
     ~CWFLHandler() { if(pWFL) delete pWFL; } 

     CMyWFL *pWFL; 
     LoadFirst LoadFirstType; 
     LoadNext LoadNextType; 
     Load  LoadType; 
     Update  UpdateType; 
     Delete  DeleteType; 
     IsRequired IsRequiredType; 
     int   MAX_LENGTH; 
    }; 
    CWFLHandler *pWFLPtr; 

이 모든 일이 도메인에 추가 할 아주 약간의 작업으로 응용 프로그램에 새 도메인을 추가 할 수있는 것이 정말 좋은했다 :

이 모든 물건을 저장하는 클래스는 다음과 같이 정의 하였다 편집장 ... 더 좋은 방법이 있었을지 모르겠다. 하지만 이것은 제가가는 방식입니다. IMHO는 매우 창의적이었습니다. :)

0

저는 이것을 StructSerlialiser의 일부로 사용하여 SAX Parser 이벤트에서 C++ POD 구조를 채 웁니다. 즉 XML을 C++ 데이터 모델에 매핑하는 것입니다.

template<class STRUCT, typename FIELDTYPE> 
struct FieldBinderImpl : public FieldBinder<STRUCT> 
{ 
    typedef FIELDTYPE (STRUCT::*MemberPtr); 

    FieldBinderImpl (const std::string& tag, MemberPtr memberPtr) 
     : FieldBinder (tag) 
     , memberPtr_ (memberPtr) 
    { 
    } 

    virtual SerialiserBase* createSerialiser (STRUCT& data) const 
    { 
     return new Serialiser<FIELDTYPE> (&(data.*memberPtr_)); 
    } 

private: 
    MemberPtr memberPtr_; 
}; 

template<class T> 
class StructSerialiser : public SerialiserData<T> 
{ 
public: 
    typedef std::vector<FieldBinder<T>*> FieldBinderList; 

private: 
    static FieldBinderList fieldBinderList_; 

protected: 
    template<typename FIELDTYPE> 
    static void bind (const std::string& tag, FIELDTYPE (T::* member)) 
    { 
     fieldBinderList_.push_back (new FieldBinderImpl<T, FIELDTYPE> (tag, member)); 
     if (tag.empty()) 
      fieldBinderList_.back()->tags_ = Serialiser<FIELDTYPE>::getTags(); 
    } 

    // ... 
} 

// ... 

또한, 스트링, 벡터 등 :, 당신은 단지 이름에 구조체 멤버를 결합하는 것입니다 당신은 mem_fun_ref을 의미

class Index 
{ 
public: 
    std::string   currency; 
    std::string   name; 
}; 

template<> 
class Serialiser<Index> : public StructSerialiser<Index> 
{ 
public: 
    Serialiser (Index* data) : StructSerialiser<Index> (data) {} 

    static void initialise() 
    { 
     bind ("currency", &Index::currency); 
     bind ("name", &Index::name); 
    } 
}; 
관련 문제