2013-10-24 27 views
3

有沒有方法將字符串或字符轉換爲類成員/成員函數來動態訪問它們?在C++中將字符串/字符轉換爲類成員/方法

for ex。這個特定的代碼,

#include <iostream> 
#include <map> 

using namespace std; 

class agnt { 
public: 
int x, y; 
agnt(int a=0, int b=0) : x(a), y(b) {} 
}; 


int main() { 
     map<int,agnt> agntID; 
     agnt temp; 
     temp.x=1; 
     temp.y=5; 

     agntID[1]=temp; 

     for(char tmp='x'; tmp<'z'; tmp++) { 
     cout<<agntID[1].tmp<<'\n';  //Here I get the following error: tmp is 
     }        //not a member of class agnt 
} 

有沒有一種方法來轉換字符'tmp',使它被識別爲一個類成員?任何提示或解決方案將不勝感激。

回答

1

用C你不能做到這一點++,因爲它是一個靜態類型語言。獲得這種行爲的一種方式是提供訪問包裝:

template <char c> 
struct getter { 
}; 


template <> 
struct getter<'x'> { 
    static int get(const agnt &theAgnt) { 
     return theAgnt.x; 
    } 
}; 


template <> 
struct getter<'y'> { 
    static int get(const agnt &theAgnt) { 
     return theAgnt.y; 
    } 
}; 

template <char c> 
int get(const agnt &theAgnt) { 
    return getter<c>::get(theAgnt); 
} 

,要求把這樣的:

agnt temp; 
//... set members 
std::cout << get<'x'>(temp) << std::endl; 

然而,for循環將無法正常工作,你所期望的方式,因爲模板參數需要在編譯時確定。另外,除非您在非專有getter中定義了一個get函數,它將返回某種空指示符,如INT_MIN,您不能只請求任何舊函數。

然而,這一切真的一個黑客得到的東西隱約類似的動態語言。但是這與temp.x的參考沒有什麼不同。相反,你應該嘗試遵循C++約定,並享受靜態類型!

2

C++沒有任何introspection所以沒有這是不可能的。

但是,可以通過具有其他std::map包含名稱作爲關鍵字「砍」它,並將其值是對變量的引用:

agnt temp; 

std::unordered_map<char, int&> variable_map = { 
    { 'x', temp.x }, 
    { 'y', temp.y } 
}; 

variable_map['x'] = 123; 
std::cout << variable_map['y'] << '\n'; 

它一般不值得的,因爲它更工作。特別是如果你想爲多個變量做這個(因爲每個結構變量都需要它自己的映射)。

1

C++沒有內省和反射能力。您必須自己編寫這種動態訪問。

在某些情況下,使用外部模式文件來描述您的C++類,然後自動生成這些類以及內省和反射代碼,可以替代手動編碼。你不能使用模板來完成這個工作,因爲C++的元編程能力在這個領域完全不存在。

由於C++語法的複雜程度,通過直接解析.h來生成代碼通常會困難得多(即使對於編譯器製造商來說,也需要花費相當多的時間才能就適當的C++代碼以及什麼不是)。

您可以使用模板來簡化發佈,但仍然做手工:

template<typename T, typename C> 
std::map<std::string, T C::*>& attribute_map() { 
    static std::map<std::string, T C::*> m; 
    return m; 
} 

template<typename C> 
struct Published { 
    template<typename T> 
    T& attribute(const std::string& name) { 
     std::map<std::string, T C::*>& m = attribute_map<T, C>(); 
     typename std::map<std::string, T C::*>::const_iterator i=m.find(name); 
     if (i == m.end()) { 
      throw std::runtime_error("Attribute not present"); 
     } else { 
      return static_cast<C *>(this)->*i->second; 
     } 
    } 
}; 

對於每個屬性,你需要明確的「發佈」它

template<typename T, typename C> 
void publish(const std::string& name, T C::*mp) { 
    attribute_map<T, C>()[name] = mp; 
} 

鑑於上述樣板代碼然後您可以創建一個課程並通過從Published<Class>派生出版一些成員:

struct MyClass : Published<MyClass> { 
    int a; 
    double b; 
    std::string c; 

    MyClass(int a, double b, const std::string& c) 
     : a(a), b(b), c(c) 
    { 
    } 
}; 

然後,你將需要在程序開始只是一次調用publish功能,能夠動態地訪問屬性:

int main(int argc, const char *argv[]) { 
    publish("a", &MyClass::a); 
    publish("b", &MyClass::b); 
    publish("c", &MyClass::c); 

    MyClass m1(3, 4.5, "This is a test"); 
    MyClass m2(6, 7.8, "This is another test"); 

    std::cout << m1.attribute<int>("a") << "\n"; 
    std::cout << m2.attribute<std::string>("c") << "\n"; 
    return 0; 
} 
1

雖然每個回答「否」的人都是正確的......這並不能說明整個故事。 語言中沒有任何東西允許您這樣做,但這並不意味着環境不會允許它。

例如,在vxworks上,您可以調用symFindByName()來查找函數,變量或任何其他符號,然後可以通過它提供的指針調用該函數。但是這依賴於OS API,可能是vxworks鏈接程序工作的副作用。

其他操作系統可能具有相似的功能。