2009-03-10 27 views
8

Tôi muốn ánh xạ chuỗi thành một hàm thành viên thể hiện và lưu trữ từng ánh xạ trong bản đồ.Con trỏ của cửa hàng vào chức năng thành viên trong bản đồ

Cách làm sạch sẽ như thế nào?

class MyClass 
{ 
    //........ 
    virtual double GetX(); 
    virtual double GetSomethingElse(); 
    virtual double GetT(); 
    virtual double GetRR(); 
    //........ 
}; 


class Processor 
{ 
private: 
     typedef double (MyClass::*MemFuncGetter)(); 
     static map<std::string, MemFuncGetter> descrToFuncMap; 

public: 
     static void Initialize(); 
     void Process(Myclass m, string); 
}; 

void Processor::Initialize() 
{ 

    descrToFuncMap["X"]=&MyClass::GetX; 
    descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse; 
    descrToFuncMap["RR"]=&MyClass::GetRR; 
    descrToFuncMap["T"]=&MyClass::GetT; 
}; 
void Processor::Process(MyClass ms, const std::string& key) 
{ 
    map<std::string, Getter>::iterator found=descrToFuncMap.find(key); 
    if(found!=descrToFuncMap.end()) 
    { 
     MemFuncGetter memFunc=found->second; 
     double dResult=(ms).*memFunc();  
     std::cout<<"Command="<<key<<", and result="<<result<<std::end;  
     } 
} 

cho tôi biết nếu bạn thấy vấn đề với cách tiếp cận này và thành ngữ phổ biến cho điều đó là gì?

Có lẽ, tôi nên sử dụng if-else-nếu chuỗi tuyên bố, cho rằng tôi có một số hạn chế về chức năng thành viên, thay vì một bản đồ khó hiểu của con trỏ func

BTW, tôi thấy một số hữu ích Thông tin ở đây c++-faq-lite

+0

Thực ra tôi nghĩ bản đồ đẹp hơn một chuỗi nếu khác. Nó cung cấp cho bạn một móc tốt để lưu trữ các siêu thông tin khác sau này nếu cần phát sinh - chỉ cần mở rộng kiểu giá trị từ con trỏ hàm tới một cấu trúc chứa con trỏ hàm cộng với bất kỳ thông tin nào khác bạn cần. –

+0

Tôi đồng ý, có vẻ tốt hơn, mặc dù khó hiểu hơn đối với nhà phát triển ít kinh nghiệm hơn. –

Trả lời

6

Có vẻ ổn với tôi, nhưng thực tế là descrToFuncMap cần được khai báo static nếu bạn định khởi chạy từ bên trong hàm tĩnh Initialize().

Nếu bạn muốn đảm bảo rằng Initialize() được gọi và được gọi một lần, bạn có thể sử dụng mẫu Singleton. Về cơ bản, nếu bạn không làm đa luồng, điều đó chỉ có nghĩa là gói descrToFuncMap bên trong lớp riêng của nó (được gọi là FuncMap) với một hàm tạo riêng tư gọi số Initialize(). Sau đó, bạn thêm một biến số địa phương static loại FuncMap đến Processor::Process() - vì biến là static, biến này vẫn tồn tại và chỉ được khởi tạo một lần.

Ví dụ mã (bây giờ tôi nhận ra rằng friend là không thực sự cần thiết ở đây):

class Processor { 
private: 
    typedef double (MyClass::*MemFuncGetter)(); 

    class FuncMap { 
    public: 
     FuncMap() { 
      descrToFuncMap["X"]=&MyClass::GetX; 
      descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse; 
      descrToFuncMap["RR"]=&MyClass::GetRR; 
      descrToFuncMap["T"]=&MyClass::GetT; 
     } 

     // Of course you could encapsulate this, but its hardly worth 
     // the bother since the whole class is private anyway. 
     map<std::string, MemFuncGetter> descrToFuncMap; 
    }; 

public: 
    void Process(Myclass m, string); 
}; 

void Processor::Process(MyClass ms, const std::string& key) { 
    static FuncMap fm;  // Only gets initialised on first call 
    map<std::string, Getter>::iterator found=fm.descrToFuncMap.find(key); 
    if(found!=fm.descrToFuncMap.end()) { 
     MemFuncGetter memFunc=found->second; 
     double dResult=(ms).*memFunc();  
     std::cout<<"Command="<<key<<", and result="<<result<<std::end;  
    } 
} 

Đây không phải là "true" Singleton pattern như các chức năng khác nhau có thể tạo riêng, trường hợp riêng biệt của họ về FuncMap, nhưng nó đủ cho những gì bạn cần. Đối với Singleton "true", bạn sẽ khai báo private constructor của FuncMap và thêm một phương thức tĩnh, nói getInstance(), xác định cá thể một và chỉ như một biến số static và trả về một tham chiếu đến đó. Processor::Process() sau đó sẽ sử dụng điều này với

FuncMap& fm = FuncMap::getInstance(); 
+0

yea nó là tĩnh (cố định nó). Tôi thích ý tưởng của một lớp bạn bè riêng. Bạn sẽ chứng minh nó với một ví dụ? Cảm ơn –

0

tôi muốn thay đổi

void Processor::Process(MyClass ms, std::string key) 

để

void Processor::Process(const MyClass& ms, const std::string& key) 

Hiện không thấy bất kỳ tác dụng phụ xấu nào. Có lẽ với boost :: function như một giá trị map nó sẽ dễ dàng hơn trong tương lai.

+0

cũng yea, rõ ràng tôi sẽ vượt qua chuỗi như một const để tham khảo. Câu hỏi của tôi có lẽ là, tôi nên sử dụng chuỗi tuyên bố nếu tôi có một số lượng hạn chế các hàm thành viên thay vì một bản đồ khó hiểu của các con trỏ func –

+0

Các bản đồ là ok cho tôi. –

0

Tránh sử dụng 'ảo' nếu bạn đang sử dụng bản đồ con trỏ hàm. Trong ngữ cảnh này, việc sử dụng từ khóa 'ảo' sẽ không giúp được gì nhiều. Ví dụ

descrToFuncMap["X"]=&MyClass::GetX; 

sẽ luôn luôn gọi là 'MyClass :: GetX' chức năng ngay cả khi GetX được ghi đè bởi các lớp có nguồn gốc của MyClass.

Thông thường bạn sẽ không có số lượng lớn các hàm trong lớp, thay vì sử dụng bản đồ, bạn có thể tạo mảng cấu trúc đơn giản và sử dụng vòng lặp for.Nếu số lượng các chức năng là nhỏ, sẽ không có bất kỳ sự khác biệt hiệu suất lớn trong bản đồ và mảng. Nội dung tương tự như mã bên dưới sẽ hoạt động

class MyClass 
{ 
    //........ 
    double GetX(); 
    double GetSomethingElse(); 
    double GetT(); 
    double GetRR(); 
    //........ 
}; 

typedef double (MyClass::*MemFuncGetter)(); 

struct FuncTable 
{ 
    const char* m_pFuncName; 
    MemFuncGetter m_pFuncPtr; 
}; 

class Processor 
{   
public: 
     void Process(Myclass& m, string); 
}; 

static FuncTable descrToFuncMap[] 
{ 
    { "X", &MyClass::GetX}, 
    { "SomethingElse", &MyClass::GetSomethingElse }, 
    { "RR", &MyClass::GetRR}, 
    { "T", &MyClass::GetT} 
}; 

void Processor::Process(MyClass& ms, const std::string& key) 
{ 
    int functablesize = sizeof(descrToFuncMap)/sizeof(descrToFuncMap[0]) 

    for(int i=0; i< functablesize; ++i) 
    { 
     if(strcmp(key.c_str(), descrToFuncMap[i].m_pFuncName)==0) 
     { 
      MemFuncGetter memFunc=descrToFuncMap[i].m_pFuncPtr; 
      double dResult=(ms).*memFunc();  
      std::cout<<"Command="<<key<<"result="<<result<<std::end; 
      break; 
     } 
    }  
} 
+0

Tại sao nó không gọi một chức năng overriden? –

Các vấn đề liên quan