UML-представление для указателей на функции C / C ++

Что было бы лучшим представлением указателя на функцию C / C ++ (fp) в структурной диаграмме UML?

Я думаю об использовании элемента интерфейса, может быть, даже если «вырожден» с ограничением на то, чтобы было объявлено не более одной операции.

Я нашел несколько предложений в этом документе: Руководство пользователя по синхронизации C и UML, раздел 5.7.4. Но это звучит довольно громоздко и не очень полезно на практике. Даже если прав с очень низкого уровня семантического взгляда. Вот диаграмма, показывающая их концепцию вкратце:
введите описание изображения здесь

IMHO в C и C ++ указатели на функции используются как суженное представление интерфейса, который предоставляет только одну функцию и ее сигнатуру. В C fp будет также использоваться для реализации более сложных интерфейсов, объявляющих структуру, содержащую набор указателей на функции.

Я думаю, что мне даже удастся заставить мой конкретный инструмент UML (Enterprise Architect) генерировать правильный код и синхронизироваться с изменениями кода без вреда.

Мои вопросы:

  1. Будет ли объявление fp как части элементов интерфейса в UML обеспечивать правильное семантическое представление?
  2. Какой тип стереотипа следует использовать для объявления одного фп? По крайней мере, мне нужно предоставить typedef в коде так что это был бы мой мужественный выбор.(Я обнаружил, что этот стереотип является собственностью Enterprise Architect), и мне нужно определить соответствующий стереотип, чтобы адаптировать генерацию кода. На самом деле я выбрал стереотип «делегат», имеет ли это какие-либо последствия или семантические коллизии?
  3. Что касается C ++, достаточно ли было бы вложения элемента интерфейса с делегатами в элемент класса, чтобы правильно выразить указатель на функцию-член класса?

Вот примерная схема моих мыслей о представлении языка C:
Реализация интерфейса языка C и указателя на функцию

Это код C, который должен быть сгенерирован из приведенной выше модели:

struct Interface1;

typedef int (*CallbackFunc)(struct Interface1*);

typedef struct Interface1
{
typedef void (*func1Ptr)(struct Interface1*, int, char*);
typedef int (*func2Ptr)(struct Interface1*, char*);
typedef int (*func3Ptr)(struct Interface1*, CallbackFunc);

func1Ptr func1;
func2Ptr func2;
func3Ptr func3;

void* instance;
};

/* The following extern declarations are only dummies to satisfy code
* reverse engineering, and never should be called.
*/
extern void func1(struct Interface1* self, int p1, char* p2) = 0;
extern int func2(struct Interface1* self, char*) = 0;
extern int func3(struct Interface1* self, CallbackFunc p1) = 0;

РЕДАКТИРОВАТЬ:
Вся проблема сводится к тому, что было бы наилучшим образом с имеющимся инструментом UML и его специфическими возможностями разработки кода. Таким образом, я добавил тег.

17

Решение

В справочном файле EA есть следующее, что можно сказать о предметных указателях:

При импорте исходного кода C ++ Enterprise Architect игнорирует объявления указателей на функции. Чтобы импортировать их в вашу модель, вы можете создать typedef для определения типа указателя на функцию, а затем объявить указатели на функции, используя этот тип. Объявленные таким образом указатели на функции импортируются как атрибуты типа указателя на функцию.

Обратите внимание, «мог». Это из раздела C ++, раздел C вообще не упоминает указатели функций. Так что они не очень хорошо поддерживаются, что, в свою очередь, связано с разрывом между сообществами моделирования и программирования: нетривиальные концепции языка просто не поддерживаются в UML, поэтому любое решение по необходимости будет зависеть от конкретного инструмента.

Мое предложение немного сложное и немного хакерское, но я думаю, что оно должно работать довольно хорошо.

Поскольку операции UML не являются первоклассными и не могут использоваться в качестве типов данных, мой ответ заключается в создании для них первоклассных сущностей, другими словами, определяя типы указателей на функции как классы.

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

0) Вы можете настроить технологию ЦРТ для шагов 1-4.

1) Определите теговое значение типа «retval» с подробным описанием «Type = RefGUID; Values ​​= Class;»

2) Определите дополнительный набор типов теговых значений с той же деталью с именами «par1», «par2» и так далее.

3) Определите профиль с помощью стереотипа класса «funptr», содержащего теговое значение «retval» (но без тегов «par»).

4) Измените объявление и параметр атрибутов сценариев генерации кода, чтобы получить «retval» (всегда) и «par1» — «parN» (где это определено) и создать для них правильный синтаксис. Это будет немного сложнее, и я на самом деле не сделал этого. Я думаю, что это можно сделать без особых усилий, но вам придется это попробовать. Также следует убедиться, что для определений классов «funptr» не генерируется код, поскольку они представляют анонимные типы, а не typedefs.

5) В вашем целевом проекте определите набор классов для представления примитивных типов Си.

При этом вы можете определить тип указателя на функцию как «funptr» класс с именем типа «long (*) (char)» для функции, которая принимает char и возвращает long.

В теге «retval» выберите «длинный» класс, определенный вами на шаге 4.

Добавьте тег «par1» вручную и выберите класс «char», как указано выше.

Теперь вы можете использовать этот класс в качестве типа атрибута или параметра или в любом другом месте, где EA допускает ссылку на класс (например, в теге «par1» другого класса «funptr»; это позволяет вам легко создавать типы указателей для функции, где один из параметров сам по себе имеет тип указателя на функцию).

Самый хакерский бит здесь — это пронумерованные теги «par1» — «parN». Хотя в EA можно определить несколько тегов с одним и тем же именем (возможно, вам придется изменить параметры окна значений тегов, чтобы увидеть их), я не думаю, что вы можете получить различные значения в скрипте генерации кода (и даже если вы могли бы не думать, что порядок обязательно будет сохранен, а порядок параметров важен в C). Поэтому вам нужно заранее определить максимальное количество параметров. Не огромная проблема на практике; Настройка скажем, 20 параметров должно быть много.

Этот метод не помогает реверс-инжинирингу, поскольку EA 9 не позволяет настраивать процесс обратного инжиниринга. Тем не менее, предстоящий EA 10 (в настоящее время в RC 1) позволит это, хотя я сам не смотрел на него, поэтому я не знаю, какую форму это примет.

введите описание изображения здесь

8

Другие решения

Определение указателей на функции выходит за рамки спецификации UML. Более того, это особенность языка, которая не поддерживается многими программами моделирования UML. Поэтому я думаю, что общий ответ на ваш первый вопрос предлагает избегать этой функции. Предоставленные вами приемы относятся только к Enterprise Architect и не совместимы с другими инструментами моделирования UML. Вот как указатели функций поддерживаются в некоторых других программах UML:

MagicDraw UML использует <<C++FunctionPtr>> стереотипы для членов класса FP и <<C++FunctionSignature>> для функции прототипа.

Образец кода (взят из официальный сайт — см. «Моделирование typedef и указатель на функцию для генерации кода C ++»:

class Pointer
{
void (f*) ( int i );
}

Соответствующая модель UML:

Указатели на функции в MagicDraw UML

Objecteering определяет атрибуты FP с соответствующей заметкой C ++ TypeExpr.

Rational Software Architect от IBM не поддерживает функциональные указатели. Пользователь может добавить их в сгенерированный код в определенных пользователем разделах, которые остаются нетронутыми во время выполнения кода.>UML и UML->преобразования кода.

2

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

1

Я думаю, что вы могли бы фактически обернуть указатель функции с классом. Я думаю, что UML не должен быть уровнем разработки кода, документирование концепции более важно.

1

Мне кажется, что вы хотите отобразить интерфейсы UML на идиому struct-with-function-pointers.

Interface1 является важным элементом вашей модели. Объявление типов указателей на функции повсеместно сделает ваши диаграммы неразборчивыми.

Enterprise Architect позволяет вам указать ваши собственные генераторы кода. Ищите Структура шаблона кода. Вы должны быть в состоянии изменить существующий генератор кода для C с помощью нового стереотипа или двух.

1

Как и в первом примере, я бы использовал классификатор, но скрыл его в профиле. Я думаю, что они включили это для ясности объяснения понятия; но на практике вся идея стереотипов состоит в том, чтобы абстрагировать детали в профили, чтобы избежать проблемы «шума». EA довольно хорош для работы с профилями.

В чем я отличаюсь от вашего первого примера, я бы классифицировал Примитивный тип Стереотип не тот Тип данных стереотип. Тип данных — это объект области действия Домена, а Примитивный тип — это элементарный элемент с семантикой, определенной вне области действия UML. Это не означает, что вы не можете добавлять заметки, особенно в профиль, или дать ему очень четкое название стереотипа, например, functionPointer.

0

Мне удалось получить что-то вроде работы с Enterprise Architect. Это немного хакерское решение, но оно отвечает моим потребностям. Что я сделал:

  1. Создайте новый стереотип класса с именем FuncPtr. Я следовал за руководством здесь: http://www.sparxsystems.com/enterprise_architect_user_guide/10/extending_uml_models/addingelementsandmetaclass.html
    Когда я сделал это, я сделал новый вид для профиля. Так что я могу хранить его вне моего основного проекта.

  2. Изменены шаблоны кода класса. В основном, выбираем язык C и начинаем с шаблона класса, нажимаем «Добавить новое переопределение стереотипа» и добавляем FuncPtr в качестве нового переопределения.

  3. Добавьте следующий код в этот новый шаблон:

%PI="\n"%
%ClassNotes%
typedef %classTag:"returnType"% (*%className%)(
%list="Attribute" @separator=",\n" @indent="    "%
);
  1. Изменен шаблон кода объявления атрибута. Так же, как и раньше, добавив новый стереотип

  2. Добавьте следующий код в новый шаблон:

% PI = «»%% attConst == «T»? «const»: «»%

% AttType%

% attContainment == «По ссылке»? «*»: «»%

% AttName%

Это все, что мне нужно было сделать, чтобы получить указатели функций в Enterprise Architect. Когда я хочу определить указатель на функцию, я просто:

  1. Создать регулярный класс
  2. Добавьте в теге returnType тип возврата, который я хочу
  3. Добавьте атрибуты для параметров.

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

Так что это немного странно, используя специальные стереотипные классы в качестве typedef для работы с указателями.

0
По вопросам рекламы [email protected]