Подтвердить что ты не робот

Отражение в С++

Я много лет работаю с Java. За эти годы я сделал обширное (или, может быть, простое) использование рефлексии, и нашел его полезным и приятным. Но 8 месяцев назад я сменил свою работу, и теперь Java - это просто память, и я получаю доступ к С++. Итак, теперь мне интересно, есть ли какой-либо механизм отражения в С++. Я читал о RTTI, но я чувствую, что это далеко не сила Java (или других языков) reflecion. Я начинаю думать, что нет способа сделать это на С++. Я не прав?

4b9b3361

Ответ 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. Это нелегко - нам потребовалось несколько месяцев, чтобы добиться достойной реализации, но он будет делать все, что говорят языки, поддерживающие рефлексию.