Есть ли способ добавить поле в класс во время выполнения (поле, которого раньше не было)? Что-то вроде этого фрагмента:
Myobject *ob; // create an object
ob->addField("newField",44); // we add the field to the class and we assign an initial value to it
printf("%d",ob->newField); // now we can access that field
Мне все равно, как это будет сделано, мне все равно, уродливый это взлом или нет, я хотел бы знать, можно ли это сделать, и небольшой пример, если возможно.
Другой пример: говорит, что у меня есть XML-файл, описывающий этот класс:
<class name = "MyClass">
<member name = "field1" />
<member name = "field2" />
</class>
и я хочу «добавить» поля «field1» и «field2» к классу (при условии, что класс уже существует). Допустим, это код класса:
class MyClass {
};
Я не хочу создавать класс во время выполнения, я просто хочу добавить элементы / поля к существующему.
Спасибо !





Невозможно сделать это так, как вы описали, поскольку компилятор должен разрешить ссылку во время компиляции - он сгенерирует ошибку.
Но см. Универсальный шаблон дизайна.
Нет - C++ не поддерживает подобные манипуляции с системой типов. Даже языки с некоторой степенью отражения времени выполнения (например, .NET) не будут поддерживать именно эту парадигму. Для этого вам понадобится гораздо более динамичный язык.
Укороченная версия: Не могу. Для этого нет встроенной поддержки, C++ статически типизирован, и компилятор должен знать структуру каждого объекта, которым нужно управлять.
Рекомендация: Используйте встроенный интерпертер. И не пишите свой собственный (см. Ниже), возьмите тот, который уже работает и отлажен.
Что ты можешь сделать: Реализуйте столько прерывателя, сколько вам нужно.
Было бы достаточно просто настроить класс с элементом данных, например
std::vector<void*> extra_data;
к которому вы можете прикреплять произвольные данные во время выполнения. Цена этого заключается в том, что вам придется управлять этими данными вручную с помощью таких методов, как:
size_t add_data_link(void *p); // points to existing data, returns index
size_t add_data_copy(void *p, size_t s) // copies data (dispose at
// destruction time!), returns
// index
void* get_data(size_t i); //...
Но это не предел, с немного большей осторожностью вы можете связать произвольные данные с именем, и вы можете продолжать разрабатывать эту схему, насколько хотите (добавить информацию о типе и т. д.), Но что это происходит Вниз до реализует интерпретатор, чтобы позаботиться о вашей гибкости во время выполнения.
Ответ paercebal в том же духе и использует больше идиомы C++. Моя очень похожа на решение, втиснутое в класс, потому что это то, что есть ...
Вы не можете заставить этот синтаксис работать (из-за статической проверки во время компиляции), но если вы хотите изменить синтаксис, вы можете довольно легко добиться того же эффекта. Было бы довольно легко иметь член словаря с сопоставлением строка-> blob и иметь такие функции-члены, как:
template< typename T > T get_member( string name );
template< typename T > void set_member( string name, T value );
Вы можете сделать синтаксис более компактным / сложным, если хотите (например, используя переопределение оператора '->'). Есть также некоторые уловки, специфичные для компилятора, которые вы могли бы использовать (например, MSVC поддерживает __declspec (свойство), которое позволяет вам сопоставлять ссылки на переменную-член с методами определенного формата). В конце концов, однако, вы не сможете сделать то, что компилятор не принимает на языке, и заставить его скомпилировать.
Я думал, что шаблоны готовы после компиляции. Таким образом, я не понимаю, как этот фрагмент кода может генерировать члены среды выполнения в классе, например. учитывая ввод, добавьте в класс переменную. Это не то, что можно сделать с помощью шаблонов. Возможно, я не понял ваших решений, поэтому я не голосую против. Мне просто интересно, что вы имели в виду.
@ G24l: я предполагаю, что это класс, обертывающий карту вариантов, и в этом случае он компилируется нормально
Например, с помощью boost :: variant. См. http://www.boost.org/doc/libs/1_36_0/doc/html/variant.html
(Но, конечно, вы можете создавать свои собственные, чтобы соответствовать типам ваших XML-атрибутов.)
#include <map>
#include <boost/variant.hpp>
typedef boost::variant< int, std::string > MyValue ;
typedef std::map<std::string, MyValue> MyValueMap ;
Добавляя MyValueMap в качестве члена вашего класса, вы можете добавлять свойства в соответствии с их именами. Что означает код:
oMyValueMap.insert(std::make_pair("newField", 44)) ;
oMyValueMap.insert(std::make_pair("newField2", "Hello World")) ;
std::cout << oMyValueMap["newField"] ;
std::cout << oMyValueMap["newField2"] ;
Инкапсулируя его в класс MyObject и добавляя правильные перегруженные средства доступа в этот класс MyObject, приведенный выше код становится несколько более ясным:
oMyObject.addField("newField", 44) ;
oMyObject.addField("newField2", "Hello World") ;
std::cout << oMyObject["newField"] ;
std::cout << oMyObject["newField2"] ;
Но при этом вы несколько теряете типобезопасность C++. Но для XML это, я думаю, неизбежно.
Спасибо, paercebal! Можно ли было перегрузить -> чтобы добиться того эффекта, о котором я говорил?
Нет, извините, потому что добавляемое вами "newField" не было скомпилировано, только создано во время выполнения, и, следовательно, его нельзя использовать в кодовых символах, только в строках (там, несмотря на некоторые недостатки, оператор [] блестящий синтаксический сахар).
@vhaerun, что бы вы набрали после ->? Если вы знаете ответ на этот вопрос, вам не нужно добавлять переменные во время выполнения!
@paercebal: Я не понимаю, почему вы думаете, что последний теряет безопасность типов. Это не менее безопасно, чем использовать вариант для начала, не так ли?
@Mooing Duck: Когда я писал «вы несколько теряете безопасность типов C++», я действительно имел в виду: «[используя варианты] вы несколько теряете безопасность типов C++»
Я смотрел на это и немного поискал, этот фрагмент кода получен из: Блог Майкла Хаммера кажется хорошим способом сделать это, используя boost :: any
Сначала вы определяете структуру, которая определяет std :: map, содержащую ключ (то есть имя переменной) и значение. Функция определяется для объявления пары и устанавливает ее вместе с функцией для получения значения. Довольно просто, если вы спросите меня, но это хороший способ начать, прежде чем делать более сложные вещи.
struct AnyMap {
void addAnyPair( const std::string& key , boost::any& value );
template<typename T>
T& get( const std::string key ) {
return( boost::any_cast<T&>(map_[key]) );
}
std::map<const std::string, boost::any> map_;
};
void AnyMap::addAnyPair( const std::string& key , boost::any& value ) {
map_.insert( std::make_pair( key, value ) );
}
Суть в том, что это взлом, поскольку C++ - это язык строгой проверки типов, и поэтому те, кто нарушает правила, находятся в пределах досягаемости.
Отредактировал ваш вопрос, чтобы содержимое отображалось правильно ... :-) ...