Как бы вы реализовали базовое отражение в C ++? - PullRequest
7 голосов
/ 12 февраля 2010

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

Я думал о синтаксическом анализе существующих исходных файлов, получении списка объявленных полей и методов и переписывании каждого исходного файла, добавляя такую ​​информацию в каждый класс.

Что вы думаете об этом подходе? Я хотел бы сделать все с нуля, так как считаю, что это отличная возможность учиться. Не могли бы вы предложить другие способы сделать это?

// OFFTOPIC: это как Qt это делает?

Ответы [ 9 ]

3 голосов
/ 12 февраля 2010

Я бы форк gcc.

3 голосов
/ 12 февраля 2010

Проверьте библиотеку Boost.Mirror . Он еще не был принят в Boost, поэтому вам придется загрузить его из Boost Vault.

Библиотека все еще находится в стадии разработки, и документации недостаточно, но, изучив предоставленных примеров , вы сможете достичь желаемого.

РЕДАКТИРОВАТЬ: если вы действительно хотите проанализировать свой собственный код C ++, то, возможно, вам следует рассмотреть clang

2 голосов
/ 12 февраля 2010

Да, вот как это делает Qt - за исключением того, что он не добавляет информацию к самому классу, он создает новый класс, называемый метаклассом, который содержит статические данные о классе. Это лучше по понятным причинам.

Никакой подход на чистом C ++ не обеспечит полностью автоматического отражения - язык этого не позволяет. Есть много попыток, в том числе Boost.Mirror и Boost.Reflection , но все они требуют добавления шаблонов к вашему источнику.

1 голос
/ 20 августа 2011

Следуйте десятому закону Гринспуна, и все готово: просто внедрите специальную, неофициально заданную, подверженную ошибкам, медленную реализацию половины Common Lisp. Выберите половину, которая поддерживает реализацию отражения. :)

Или вот идея:

Включите файлы карт (и, возможно, генерацию сборок) в вашей сборке. Реализуйте приложение, которое генерирует код для создания динамической библиотеки. Вы должны иметь возможность получать всю статическую информацию (имена методов, параметры, типы и т. Д.) О классах либо из источника, либо из одного из артефактов сборки. Используя карту или сборку, вы сможете найти адреса функций, смещения указателей виртуальных функций, адреса глобальных переменных, смещения переменных, информацию о стеке и регистре распределенных переменных и т. Д. И т. Д. Из этой информации создайте библиотеку, содержащую вызовы для получения всей этой информации путем передачи имен типов, указателей, имен функций и т. Д.

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

Наконец, напишите компоновщик отражения пост-пост сборки. Я предлагаю "kniltsoPostlink", но это зависит от вас. На этом шаге ищите ваши уникальные идентификаторы (я упомянул, чтобы упростить, вы, вероятно, должны сделать идентификаторы GUID, чтобы вы могли искать их в двоичном файле?) И, где идентификатор помечает вызов отражения функции или определение класса и т. д., поместите туда достаточно данных (в формате, который вы можете легко определить точно в срок при написании библиотеки отражателей), а затем в идентификаторе перед вызовом библиотеки отражателей перепишите вызов так, чтобы он извлекает необходимые параметры из этих битов данных или просто помещает биты данных туда, где это применимо, я не могу знать заранее, но по мере того, как вы пишете это, эти маленькие детали просто всплывают у вас.

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

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

;)

1 голос
/ 13 февраля 2010

C ++ не поддерживает отражение. Усилия от boost и RTTI довольно ограничены и наполовину испечены. Я бы не рекомендовал их.

Вы упомянули, что можете начать со скэтча. Ну, вы можете написать лексер C ++, используя lex / yacc или ANTLR . Довольно много работы, но вы многому научитесь.

Если написание парсера является сложной задачей для вас, есть несколько других вариантов получения метаданных класса. Microsoft имеет DIA SDK, который предоставляет символьную информацию. Doxygen может генерировать файлы XML, которые вы можете анализировать, чтобы получить имена полей, имена методов класса. У меня был некоторый успех при разборе файлов doxygen XML.

Если вы работаете только с платформой Microsoft, жизнеспособным решением является использование библиотеки типов (TLB). Это требует, чтобы вы преобразовали класс в интерфейс в MS IDL. MIDL компилирует IDL в .tlb, и ваше приложение может загрузить файл .tlb во время выполнения. Ваше приложение может получить почти всю информацию о классе через интерфейс, свойства и методы ITypeInfo.

1 голос
/ 13 февраля 2010

Измените компилятор для создания статического метода GetClass, возвращающего указатель на объект Class, описывающий класс, для каждого определенного класса.

Измените компилятор / компоновщик так, чтобы он извлекал необходимые метаданные и помещал их в специальные разделы / символы конечного исполняемого изображения - очень похоже на добавление символов отладки.

GetClass будет использовать (чтение / загрузка / кэш?) Вышеуказанные метаданные.

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

1 голос
/ 13 февраля 2010

Вы можете найти gccxml достойным внимания. Это (например) преобразует это в это , что означает, что вам просто нужно проанализировать XML вместо C ++.

Есть интересная статья SP & E , в которой описывается использование gccxml в сочетании с модифицированным компоновщиком для «обеспечения функциональности, подобной Java-отражению, для приложений C ++ чистым и ненавязчивым способом».

1 голос
/ 12 февраля 2010

Если вы не хотите модифицировать компилятор C ++ или зависеть от расширений поставщика, вам понадобится куча макросов CPP, которые создают структуры данных.

0 голосов
/ 13 февраля 2010

Может быть, вы можете использовать библиотеку typeinfo, теперь вы можете использовать класс объекта во время выполнения. Пример:

#include<iostream>

#include<typeinfo>
class A{};

int main()
{
A a;

std::cout<<typeid(a).name();

}

Вы можете увидеть больше в: http://www.cplusplus.com/reference/std/typeinfo/

[] `s

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