Как ограничить определенные функции определенными структурами в C? - PullRequest
1 голос
/ 07 апреля 2020

У меня есть структура, настроенная следующим образом:

typedef struct Graph_
{
    Point2D position;
    double Size_X;
    double Size_Y;
    char* Label;
    NVGcolor Background_Color;
    bool Borders;
    bool Grid;
    int Grid_Scale;
    NVGcolor Grid_Color;
    float Border_Padding;
    void (*init)(NVGcontext* vg, struct Graph_ * graph);
    void (*drawAxes)(NVGcontext* vg, Axis * axis , struct Graph_* graph);
}Graph;

и соответствующие методы, подобные этому в моем заголовке,

void InitGraph(NVGcontext* vg, Graph* graph);
void DrawAxes(NVGcontext* vg, Axis* axisObject);

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

PS Я пытаюсь использовать структуру в качестве класса в моем приложении.

Ответы [ 3 ]

3 голосов
/ 07 апреля 2020

Звучит так, будто вы хотите, чтобы люди не вызывали эти функции напрямую, но позволяли людям вызывать их косвенно через указатели функций. Это достаточно просто: просто не объявляйте функции в вашем заголовочном файле. Вы можете объявлять и определять функции в исходном файле. c, и в этом же файле вы можете реализовать какой-либо способ «получить» указатели на функции, буквально возвращая их или устанавливая их как члены структуры Graph. , В вашем заголовочном файле будут доступны только те функции получения / установки.

Например, в вашем заголовке:

void SetupGraph(Graph* graph);

Затем реализация в вашем файле. c:

static void InitGraph(NVGcontext* vg, Graph* graph) {
    // ...
}

static void DrawAxes(NVGcontext* vg, Axis* axisObject) {
    // ...
}

// public
void SetupGraph(Graph* graph)
{
    graph->init = InitGraph;
    graph->drawAxes = DrawAxes;
}

Теперь внешние пользователи вашей библиотеки могут сделать это:

Graph graph;
SetupGraph(&graph);

NVGcontext vg;
graph.init(&vg, &graph);

Видите, они могут вызывать InitGraph() косвенно, через указатель на функцию, установленный SetupGraph(), но они никогда не смогут позвонить InitGraph() напрямую, потому что не знают его имени.

1 голос
/ 07 апреля 2020

Это, я думаю, частично ответ, который дал Джон, но получил его более абстрактно.

Я предполагаю, что вы пытаетесь имитировать c класс C ++ с функциями-членами publi c и закрытые функции-члены в C.

Publi c "функции-члены" должны быть видимы для "publi c", если вы извините за каламбур, и им нужен указатель на структуру как единое целое параметр, который играет роль неявного указателя this в C ++. Они будут объявлены в заголовке publi c.

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

Есть два способа скрыть функции.

  1. Вы можете сделать «приватные» функции (файл) stati c. Это чисто, потому что мешает компилятору полностью экспортировать символ. Функции Stati c могут использоваться только в той единице перевода, где они определены. Поскольку эти файлы являются частью «библиотеки» вашей структуры, publi c просто не может получить к ним доступ. Линкер не может ссылаться на них вообще; для других единиц перевода они просто не существуют. Но это также недостаток: для больших «классов» со многими «функциями-членами» все функции, использующие «частные» функции, должны находиться в одном исходном файле. (В качестве альтернативы вы можете написать необычный заголовочный файл, который содержит код для функций stati c и включать его везде, где вам нужен доступ к этим функциям; но это увеличит размер кода и, как правило, не рекомендуется.)

  2. Вы создаете коллекцию «частных» функций, потенциально распределенных по нескольким исходным файлам. Эти функции имеют внешнюю связь и могут использоваться в других единицах перевода. Механизм их скрытия состоит в том, чтобы помещать их объявления в заголовок, который не предназначен для включения в публикацию c. Publi c видит только функции publi c, опубликованные в отдельном заголовке. Это было бы похоже на дизайн интерфейса / реализации C ++.

    Теоретически, могут ли эти частные функции вызываться publi c (например, просто путем угадывания имени и параметров или путем поиска "частного" заголовка) и в том числе) зависит от вашей системы сборки. Если вы распространяете предварительно скомпилированную совместно используемую библиотеку, вы можете различить guish ваши публичные c функции, сообщив компилятору в платформе, определяющей c способ сделать символ внешне видимым с помощью __declspec(dllexport) (Visual C) или __attribute__((visibility("default"))) (г cc). Функции, не оформленные таким образом, не видны вне библиотеки и не могут быть связаны с ними. Заголовок "private" даже не будет частью дистрибутива.

    Если вы просто скомпилируете и свяжете несколько исходных и объектных файлов, хотя заголовок "private" должен быть доступен для компиляции, а publi c может использовать их, если они включены или угадывают имена функций. Если публикация c с использованием вашей структуры недисциплинирована и ей нравятся хаки, вполне вероятно, что появится код, который использует функцию "private".

0 голосов
/ 07 апреля 2020

Удалите объявления функций из файла заголовка, определите функции в файле реализации и добавьте ключевую строку static перед объявлением.

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