Отражение в C ++ - PullRequest
       19

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

12 голосов
/ 12 мая 2009

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

Ответы [ 8 ]

15 голосов
/ 12 мая 2009

Поскольку стандарт C ++ не охватывает такое понятие, как «метаданные», нет никакого переносимого (в данном случае, для разных компиляторов и платформ) метода отражения во время выполнения, кроме RTTI, о котором вы уже упоминали.

В C ++ также есть возможность отражения во время компиляции (например, boost::type_traits и boost::type_of), но оно также ограничено по сравнению, скажем, с Nemerle или LISP.

Большинство основных сред (MFC, Qt и т. Д.) Позволяют извлекать метаинформацию во время выполнения, но для ее работы требуются все виды специальных аннотаций (см. RUNTIME_CLASS и др. В качестве примера). ).

5 голосов
/ 12 мая 2009

Если вы ищете полностью общий способ манипулирования объектами во время выполнения, когда вы не знаете их типы во время компиляции в C ++, вам, по сути, необходимо:

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

Теперь предположим, что 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();
}

Этот подход предполагает, что вы знаете все соответствующие интерфейсы во время компиляции - если вы этого не сделаете, вы все равно не сможете использовать обычный синтаксис C ++ для вызова методов. Но трудно представить себе ситуацию, когда вызывающая программа не знает, какие интерфейсы ей нужны - о единственном случае, о котором я могу подумать, это о том, если вы хотите представить объекты C ++ через интерактивный интерпретатор. Даже в этом случае вы можете придумать (уродливый, требующий больших затрат на обслуживание) способ вставить это в вышеприведенную парадигму, чтобы методы можно было вызывать, указав их имена и аргументы в виде строк.

Другим аспектом, который следует учитывать, является создание объекта . Чтобы выполнить это, не зная конкретных типов, вам понадобится функция фабрики плюс уникальные идентификаторы для классов, чтобы указать, какой конкретный класс вы хотите. Можно организовать, чтобы классы регистрировались в глобальной фабрике при запуске , как описано здесь экспертом по C ++ Хербом Саттером - это позволяет избежать поддержки гигантского оператора switch, что значительно упрощает обслуживание. Можно использовать одну фабрику, хотя это подразумевает, что существует один интерфейс, который должен реализовывать каждый объект в вашей системе (фабрика будет возвращать указатель или ссылку на этот тип интерфейса).

В конце концов, то, что вы получите, в основном (изоморфно) COM - dynamic_cast<IFoo*> выполняет ту же работу, что и QueryInterface(IID_IFoo), а базовый интерфейс реализован всеми объектами эквивалентно IUnknown.

4 голосов
/ 12 мая 2009

Посмотрите на мой ответ на аналогичный вопрос . Оба предложенных решения (XRTTI и OpenC ++) основаны на внешних инструментах, которые генерируют метаданные отражения для вас в процессе сборки.

3 голосов
/ 12 мая 2009

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

Многие популярные библиотеки используют этот шаблон для особых случаев, например, функция Serialize в MFC делает это, но специально для сериализации.

Вероятно, вы могли бы спроектировать систему таким образом, чтобы посетитель мог выполнять динамические вызовы функций-членов, получать или устанавливать значения элементов данных и т. Д. Но каждый класс должен был бы поддерживать Reflect функция, написанная от руки, которая будет повторением структуры класса.

1 голос
/ 12 мая 2009

Отражение - это процесс, с помощью которого компьютерная программа может наблюдать и изменять свою собственную структуру и поведение. Я не понимаю, как вы можете сделать отражение в C ++. RTTI полезен только для типа данных объекта в памяти во время выполнения.

1 голос
/ 12 мая 2009

RTTI - это решение (какая часть Java, по вашему мнению, отсутствует в RTTI?), В противном случае вы можете реализовать собственную объектную среду - пусть каждый ваш собственный объект C ++ наследует некоторый интерфейс отражения, и тогда он должен работать. *

0 голосов
/ 19 августа 2009

Что вам нужно делать в C ++ и с какой платформой вы работаете? Я знаю один способ получить полные определения классов и вызвать функции с использованием этих данных, он работает в Windows, но я не знаю о других платформах. Идея состоит в том, чтобы взять данные из DLL или из таблицы экспорта exe. Это непросто - нам потребовалось несколько месяцев, чтобы найти достойную реализацию, но она сделает все, что делают языки, поддерживающие рефлексию.

0 голосов
/ 12 мая 2009

если все, что вы используете, это внедрение зависимостей (реализация некоторого интерфейса ^ H ^ H ^ H ^ H ^ H ^ чистый абстрактный класс), вы можете попробовать динамическую загрузку файлов .dll или .so, которые содержат реализация дня для любого подключаемого модуля.

Возможно, просто хвататься за соломинку, поскольку это не сработает для нескольких реализаций вещей одновременно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...