2013-05-27 3 views
1

Работа с консольным приложением, и я пытаюсь выяснить способ, который позволяет пользователям вводить свойство объекта вместе со значением. НапримерДинамическое изменение свойства класса в C++

class Box{ 
    public: 
    int height; 
    int width; 
    int length; 
}; 

int main(){ 
    string memberName,value 
    cin>>memberName>>value; 
} 

Если высота входов пользователя, а затем с помощью MemberName и значения, как я могу изменить значение высоты, чтобы любой пользовательский ввод. Я хочу сделать эту работу так, чтобы можно было добавить еще один класс и получить ту же функциональность.

Я рассматриваю использование карт, но не совсем уверен, как я буду продолжать это делать.

ответ

0

Использование карты действительно способ сделать это. отредактирует вскоре с примером кода

#include "stdafx.h" 
#include <iostream> 
#include <map> 
#include <string> 





int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::map<std::string,std::string> mapData; 


    std::string name,value; 
    std::cout << "Enter Name:\n"; 
    std::cin >> name; 
    std::cout << "\n\nEnter Data\n"; 
    std::cin >> value; 

    mapData[name] = value; 

    return 0; 
} 

или вы можете иметь класс оберточной карту, если вам нужно сделать различные другие операции по карте или в промежутках между (например, подтвердить ввод или выполнять другие операции с вводом до вы храните его на карте).

// example of class wrapping a map 
class MapContainer { 
private: 
    map<string,string> _map; 

public: 
    void addValue(const string& name, const string& value) { 
     _map[name] = value; 
    } 

    string getValue(const string& name) { 
     return _map[name]; 
    } 


} 
+0

Я все еще немного потерян. Как это изменит стоимость объекта? – user2424954

+1

@ user2424954, представьте, что это хэш, вы можете получить доступ к своим свойствам из строки. – Lefsler

+0

Итак, в моем случае я бы сделал что-то вроде Box a; MapData [имя] = значение; a.mapData [имя] = значение? Извините за конкретные вопросы. Я довольно новичок в C++ – user2424954

4

Вот сложный способ сделать это, но это именно то, что вы пытались сделать в первую очередь (легко применить его к любой структуре):

#include <iostream> 
#include <string> 
#include <map> 

///////////////////////////////////////// 
// HELPERS 
template<class T> 
class MemberPtrBase 
{ 
public: 
    virtual std::istream& Read(std::istream& is, T& object) = 0; 
    virtual ~MemberPtrBase() {} 
}; 
template<class T, class V> 
class MemberPtr : public MemberPtrBase<T> 
{ 
    V T::*member; 
public: 
    MemberPtr(V T::*ptr) 
     : member(ptr) 
    {} 
    std::istream& Read(std::istream& is, T& object) 
    { 
     return is >> (object.*member); 
    } 
}; 
template<class T> 
class MemberMap 
{ 
    typedef std::map<std::string, MemberPtrBase<T>*> MapType; 
    MapType members; 
public: 
    MemberMap() {} 
    ~MemberMap() 
    { 
     for (MapType::iterator it = members.begin(); it != members.end(); ++it) 
      delete it->second; 
    } 

    template<class V> 
    void Register(std::string const& name, V T::*ptr) 
    { 
     members[name] = new MemberPtr<T, V>(ptr); 
    } 

    std::istream& ReadValue(std::istream& is, T& object) 
    { 
     std::string name; 
     is >> name; 
     if (members.find(name) == members.end()) 
     { 
      std::cerr << "Unknown member: " << name << std::endl; 
      return is; 
     } 
     return members[name]->Read(is, object); 
    } 
}; 
/////////////////////////////////////////// 

class Box 
{ 
public: 
    int width; 
    int height; 
    int length; 

    static MemberMap<Box> members; 
}; 
MemberMap<Box> Box::members; 

class Circle 
{ 
public: 
    int x; 
    int y; 
    int radius; 

    static MemberMap<Circle> members; 
}; 
MemberMap<Circle> Circle::members; 

int main() 
{ 
    Box::members.Register("width", &Box::width); 
    Box::members.Register("height", &Box::height); 
    Box::members.Register("length", &Box::length); 
    Circle::members.Register("x", &Circle::x); 
    Circle::members.Register("y", &Circle::y); 
    Circle::members.Register("radius", &Circle::radius); 

    Box box; 
    Box::members.ReadValue(std::cin, box); 

    return 0; 
} 
0

Просто, вы можете» это сделать в общем виде; нет возможности получить доступ к переменным-членам на основе их имени из среды выполнения.

Это, как правило, решается путем создания, если-иначе цепь (или переключатель), который позволяет конвертировать данные в информации:

char type; 
float height; 
int age; 

cin >> type; 
switch(type) { 
    case 'h': cin >> height; break; 
    case 'a': cin >> age; break; 
} 

Это негибкий, но так ваша структура класса, правильно? Если вы хотите сделать его динамичным, создание привязок, как в ответе @ riv, имеет мало смысла; любое изменение в классе потребует правильной оговорки. Было бы лучше, чтобы просто решить, что некоторые поля динамически хранятся на карте:

class C { 
    int iAlwaysHaveThat; 
    map<variant<int,float,string>> dynamicValues; 
}; 

Таким образом, вы можете анализировать файлы конфигурации, такие как:

Obj [ 
    a = 5, 
    b = 3.14, 
    name = "some string value" 
] 

А затем получить к ним доступ (в зависимости от фактических потребностей) функция, возвращающая optional:

optional<variant<...>> getDynamicValue(string const& name) { ... } 

которые также могут заполнить значения по умолчанию, основываясь на какой-либо другой объект, например:

{ 
    // ... 
    auto v = dynamicValues.find(name); 
    if (v == dynamicValues.end()) 
     return defaultValuesProvider.getDefault(name); 
    // ... 
} 

Это решение, которое может быть действительно полезным для некоторых целей, однако я бы, вероятно, ввел язык сценария в любом случае.

Смежные вопросы