我的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。我正在尝试将该结构用作应用程序中的类。
答案 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中,您没有可访问性说明符,因此只能通过隐藏私有函数来限制对私有函数的访问。没关系;只有实现了对结构操作的其他功能的代码才需要查看它们。
有两种隐藏功能的方法。
您可以将“私有”功能(文件)设为静态。这很干净,因为它阻止编译器完全导出符号。静态函数只能在定义它们的转换单元中使用。因为这些文件是您的结构“库”的一部分,所以公众根本无法访问它们。链接器根本无法链接到它们。对于其他翻译单元,它们根本不存在。但这也是一个缺点:对于具有许多“成员函数”的大型“类”,所有使用“私有”函数的函数必须位于同一源文件中。 (或者,您可以编写一个不寻常的头文件,其中包含静态函数的代码,并在需要访问这些函数的任何地方都包含它;但这会增加代码的大小,因此不建议使用一般模式。)
您将创建“私有”功能的集合,这些功能可能分布在多个源文件中。这些功能具有外部链接,可以在其他翻译单元中使用。隐藏它们的机制是将它们的声明放在标头中,该标头不打算公开包含。公众只能看到在单独的标题中发布的“公共”功能。这将类似于C ++接口/实现设计。
理论上,这些私有函数是否可以由公众调用(例如,仅通过猜测名称和参数,或者通过找到“私有”标头并将其包含在内)就取决于您的构建系统。如果您分发预编译的共享库,则可以通过以平台特定的方式告诉编译器,使符号在__declspec(dllexport)
(Visual C)或__attribute__((visibility("default")))
(gcc)外部可见,从而可以区分公共功能。 。未如此修饰的函数在库外部不可见,也无法链接。 “私有”标头甚至都不是分发的一部分。
如果仅编译和链接一堆源文件和目标文件,尽管“私有”标头必须可用于编译,并且公众可以自由使用它们,只要它们包含了源文件或猜测函数名称即可。如果使用您的struct的公众是不受纪律的,并且喜欢黑客,那么很有可能会出现依赖于“私有”功能的代码。
答案 2 :(得分:0)
从头文件中删除函数声明,并在实现文件中定义函数,并在声明的前面添加关键字static
。