Я много лет работаю с Java. За эти годы я сделал обширное (или, может быть, простое) использование рефлексии, и нашел его полезным и приятным. Но 8 месяцев назад я сменил свою работу, и теперь Java - это просто память, и я получаю доступ к С++. Итак, теперь мне интересно, есть ли какой-либо механизм отражения в С++. Я читал о RTTI, но я чувствую, что это далеко не сила Java (или других языков) reflecion. Я начинаю думать, что нет способа сделать это на С++. Я не прав?
Отражение в С++
Ответ 1
Если вы ищете полностью общий способ манипулирования объектами во время выполнения, когда вы не знаете их типы во время компиляции на С++, вам по существу необходимо:
- Определите интерфейс (абстрактный базовый класс со всеми чистыми виртуальными методами и без членов) для каждой возможности, которую может поддерживать класс.
- Каждый класс должен наследоваться практически из всех интерфейсов, которые он хочет реализовать (возможно, среди других классов).
Теперь предположим, что pFoo
содержит указатель интерфейса типа IFoo*
к некоторому объекту x
(вам не нужно знать конкретный тип x
). Вы можете видеть, поддерживает ли этот объект интерфейс IBar
, говоря:
if (IBar* pBar = dynamic_cast<IBar*>(pFoo)) {
// Do stuff using pBar here
pBar->endWorldHunger();
} else {
// Object doesn't support the interface: degrade gracefully
pFoo->grinStupidly();
}
Этот подход предполагает, что вы знаете все соответствующие интерфейсы во время компиляции. Если вы этого не сделаете, вы не сможете использовать обычный синтаксис С++ для методов вызова в любом случае. Но трудно представить себе ситуацию, когда вызывающая программа не знает, какие интерфейсы ей нужны - о единственном случае, о котором я могу думать, было бы, если бы вы захотели открыть объекты С++ через интерактивный интерпретатор. Даже тогда вы можете разработать (уродливый, поддерживающий интенсивность) способ обуздания этого в приведенную выше парадигму, чтобы методы можно было вызвать, указав их имена и аргументы как строки.
Другой аспект, который нужно рассмотреть, - создание объекта. Чтобы достичь этого, не зная конкретных типов, вам понадобится функция factory, а также уникальные идентификаторы для классов, чтобы указать, какой именно класс вы хотите. Возможно, чтобы классы регистрировались с глобальным factory при запуске, как описано здесь экспертом С++ Herb Sutter - это позволяет избежать гигантское выражение switch
, значительно облегчающее обслуживание. Можно использовать единственный factory, хотя это означает, что существует один интерфейс, который должен реализовать каждый объект в вашей системе (factory вернет указатель или ссылку на этот тип интерфейса).
В конце дня то, что вы заканчиваете, в основном (изоморфно) COM - dynamic_cast<IFoo*>
делает то же самое, что и QueryInterface(IID_IFoo)
, а базовый интерфейс, реализованный всеми объектами, эквивалентен IUnknown
.
Ответ 2
Так как стандарт С++ не охватывает такую концепцию, как "метаданные", там нет переносимого (по разным компиляторам и платформам, если на то пошло) метода отражения во время выполнения, отличного от RTTI, о котором вы уже упоминали.
В С++ существует также возможность отражения во времени компиляции (думаю boost::type_traits
и boost::type_of
), но она также ограничена, например, Nemerle или LISP.
Большинство основных фреймворков (MFC, Qt и т.д.) позволяют извлекать метаинформацию во время выполнения, но для этого требуются всевозможные специальные аннотации (см. RUNTIME_CLASS и др.).
Ответ 3
Посмотрите мой ответ на аналогичный вопрос. Оба предложенных решения (XRTTI и OpenС++) основаны на внешних инструментах, которые генерируют метаданные отражения для вас во время процесса сборки.
Ответ 4
Вам нужно использовать шаблон посетителя. Любой класс, который может быть отражен, должен был наследовать базовый класс, который дал ему функцию-член Reflect
, которая приняла бы класс посетителей. Затем функция Reflect
будет передавать информацию или возможности другим участникам посетителю.
Многие популярные библиотеки используют этот шаблон для конкретных случаев, например, функция Serialize
в MFC делает это, но специально для сериализации.
Возможно, вы могли бы создать систему таким образом, чтобы посетитель мог делать динамические вызовы для функций-членов, получать или устанавливать значения элементов данных и т.д. Но каждый класс должен был поддерживать Reflect
, написанная вручную, что будет повторением структуры класса.
Ответ 5
RTTI - это решение (какая часть в Java, по вашему мнению, не в RTTI?), в противном случае вы можете реализовать свою собственную инфраструктуру объектов - пусть каждый ваш собственный объект С++ наследует некоторый интерфейс отражения, а затем он должен работать.
Ответ 6
Отражение - это процесс, посредством которого компьютерная программа может наблюдать и изменять свою собственную структуру и поведение. Я не вижу, как вы можете делать отражение на С++. RTTI полезен только для типа данных объекта в памяти во время выполнения.
Ответ 7
если все, что вы используете для него, - это инъекция зависимостей (реализация некоторого интерфейса ^ H ^ H ^ H ^ H ^ H ^ чистого абстрактного класса), вы можете попробовать динамическую загрузку .dll или .so файлов, которые содержат Вне зависимости от того, что такое plug-in-in-day.
Вероятно, просто хватайтесь за соломинку, так как это не будет хорошо работать для нескольких реализаций вещей одновременно.
Ответ 8
Что вам нужно делать на С++ и на какой платформе вы работаете? Я знаю один способ получить полные определения классов и вызывать функции с использованием этих данных, он работает в Windows, но я не знаю о других платформах. Идея состоит в том, чтобы принимать данные из таблицы экспорта DLL или exe. Это нелегко - нам потребовалось несколько месяцев, чтобы добиться достойной реализации, но он будет делать все, что говорят языки, поддерживающие рефлексию.