如何将某些功能限制为C中的某些结构?

时间:2020-04-07 11:41:26

标签: c struct

我的Struct设置如下:

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中是否有可视性,解决方法? 抱歉,这是一个菜鸟问题。

P.S。我正在尝试将该结构用作应用程序中的类。

3 个答案:

答案 0 :(得分:3)

这听起来像是要阻止人们直接调用这些函数,而是允许人们通过函数指针间接调用它们。这很容易:根本不用在头文件中声明函数。您可以在.c源文件中声明和定义函数,并且可以在同一个文件中实现某种方式来“获取”函数指针,方法是从字面上返回它们,或者将它们设置为Graph结构的成员。头文件中只会显示那些getter / setter函数。

例如,在标题中:

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()。 / p>

答案 1 :(得分:1)

我认为,这部分是约翰给出的答案,但得出的结论要抽象一些。

我假设您尝试使用C中的公共成员函数和私有成员函数来模仿C ++类。

如果您对双关语感到抱歉,则公共“成员函数”必须对“公共”可见,并且它们需要指向struct的指针作为一个参数,该参数在C ++中承担隐式this指针的作用。 。它们将在公共标头中声明。

在C中,您没有可访问性说明符,因此只能通过隐藏私有函数来限制对私有函数的访问。没关系;只有实现了对结构操作的其他功能的代码才需要查看它们。

有两种隐藏功能的方法。

  1. 您可以将“私有”功能(文件)设为静态。这很干净,因为它阻止编译器完全导出符号。静态函数只能在定义它们的转换单元中使用。因为这些文件是您的结构“库”的一部分,所以公众根本无法访问它们。链接器根本无法链接到它们。对于其他翻译单元,它们根本不存在。但这也是一个缺点:对于具有许多“成员函数”的大型“类”,所有使用“私有”函数的函数必须位于同一源文件中。 (或者,您可以编写一个不寻常的头文件,其中包含静态函数的代码,并在需要访问这些函数的任何地方都包含它;但这会增加代码的大小,因此不建议使用一般模式。)

  2. 您将创建“私有”功能的集合,这些功能可能分布在多个源文件中。这些功能具有外部链接,可以在其他翻译单元中使用。隐藏它们的机制是将它们的声明放在标头中,该标头不打算公开包含。公众只能看到在单独的标题中发布的“公共”功能。这将类似于C ++接口/实现设计。

    理论上,这些私有函数是否可以由公众调用(例如,仅通过猜测名称和参数,或者通过找到“私有”标头并将其包含在内)就取决于您的构建系统。如果您分发预编译的共享库,则可以通过以平台特定的方式告诉编译器,使符号在__declspec(dllexport)(Visual C)或__attribute__((visibility("default")))(gcc)外部可见,从而可以区分公共功能。 。未如此修饰的函数在库外部不可见,也无法链接。 “私有”标头甚至都不是分发的一部分。

    如果仅编译和链接一堆源文件和目标文件,尽管“私有”标头必须可用于编译,并且公众可以自由使用它们,只要它们包含了源文件或猜测函数名称即可。如果使用您的struct的公众是不受纪律的,并且喜欢黑客,那么很有可能会出现依赖于“私有”功能的代码。

答案 2 :(得分:0)

从头文件中删除函数声明,并在实现文件中定义函数,并在声明的前面添加关键字static