C++ динамический класс (динамический взлом)

Есть ли способ добавить поле в класс во время выполнения (поле, которого раньше не было)? Что-то вроде этого фрагмента:

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 {
};

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

Спасибо !

Отредактировал ваш вопрос, чтобы содержимое отображалось правильно ... :-) ...

paercebal 25.10.2008 02:44
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
1
6 353
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Невозможно сделать это так, как вы описали, поскольку компилятор должен разрешить ссылку во время компиляции - он сгенерирует ошибку.

Но см. Универсальный шаблон дизайна.

Нет - 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++. Моя очень похожа на решение, втиснутое в класс, потому что это то, что есть ...

dmckee --- ex-moderator kitten 25.10.2008 20:43

Вы не можете заставить этот синтаксис работать (из-за статической проверки во время компиляции), но если вы хотите изменить синтаксис, вы можете довольно легко добиться того же эффекта. Было бы довольно легко иметь член словаря с сопоставлением строка-> blob и иметь такие функции-члены, как:

template< typename T > T get_member( string name );
template< typename T > void set_member( string name, T value );

Вы можете сделать синтаксис более компактным / сложным, если хотите (например, используя переопределение оператора '->'). Есть также некоторые уловки, специфичные для компилятора, которые вы могли бы использовать (например, MSVC поддерживает __declspec (свойство), которое позволяет вам сопоставлять ссылки на переменную-член с методами определенного формата). В конце концов, однако, вы не сможете сделать то, что компилятор не принимает на языке, и заставить его скомпилировать.

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

user677656 16.12.2011 20:42

@ G24l: я предполагаю, что это класс, обертывающий карту вариантов, и в этом случае он компилируется нормально

Mooing Duck 16.12.2011 21:01
Ответ принят как подходящий

Используйте карту и вариант.

Например, с помощью 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! Можно ли было перегрузить -> чтобы добиться того эффекта, о котором я говорил?

Vhaerun 25.10.2008 13:11

Нет, извините, потому что добавляемое вами "newField" не было скомпилировано, только создано во время выполнения, и, следовательно, его нельзя использовать в кодовых символах, только в строках (там, несмотря на некоторые недостатки, оператор [] блестящий синтаксический сахар).

paercebal 25.10.2008 14:08

@vhaerun, что бы вы набрали после ->? Если вы знаете ответ на этот вопрос, вам не нужно добавлять переменные во время выполнения!

Mooing Duck 16.12.2011 21:00

@paercebal: Я не понимаю, почему вы думаете, что последний теряет безопасность типов. Это не менее безопасно, чем использовать вариант для начала, не так ли?

Mooing Duck 16.12.2011 21:02

@Mooing Duck: Когда я писал «вы несколько теряете безопасность типов C++», я действительно имел в виду: «[используя варианты] вы несколько теряете безопасность типов C++»

paercebal 17.12.2011 23:34

Я смотрел на это и немного поискал, этот фрагмент кода получен из: Блог Майкла Хаммера кажется хорошим способом сделать это, используя 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++ - это язык строгой проверки типов, и поэтому те, кто нарушает правила, находятся в пределах досягаемости.

Другие вопросы по теме