如果这是一个显而易见的问题,我很抱歉,但在 C 中,不透明指针是否类似于 Java 接口?当我试图理解它们时,我将它们解释为与 Java 接口类似,因为它们建立了与方法/函数交互的强制性方式?所以如果我想使用不透明指针,我需要在 .h 文件中定义它,而在 .c 文件中调用它?不透明指针只定义方法/函数的签名(在 .h 文件中),而 .c 文件采用具有这些签名的函数并实现它们。
如果这是一个显而易见的问题,我很抱歉,但在 C 中,不透明指针是否类似于 Java 接口?当我试图理解它们时,我将它们解释为与 Java 接口类似,因为它们建立了与方法/函数交互的强制性方式?所以如果我想使用不透明指针,我需要在 .h 文件中定义它,而在 .c 文件中调用它?不透明指针只定义方法/函数的签名(在 .h 文件中),而 .c 文件采用具有这些签名的函数并实现它们。
不。不透明指针是一种设计,其中类型的实现(通常
struct
;可选typedef
)对客户端隐藏(封装)。此模块可以以它认为合适的方式实例化类型;通常是动态分配(和释放)。客户端必须使用模块提供的函数来操作不透明指针。你的头文件(接口)中会有类似这样的内容:
然后模块实现是:
作为 Allan Wind 答案的补充,不透明指针依赖于一个非常简单的事实:结构指针的大小都是相同的1,而它们指向的东西的大小可能差别很大。
在 C 语言中,函数必须知道其参数、局部变量和返回值的大小。因此,在头文件中,我们无法通过值传递或返回抽象数据类型。
因为实际数据类型是在实现文件中定义的,因此该翻译单元“知道”数据的大小,我们可以直接在那里处理抽象数据类型的值。
只要头文件保持一致,我们就可以按照任何方式定义数据类型。可以在实现中进行改进,而不必调整客户端程序实际使用数据类型的方式。
1指针的大小取决于硬件和软件平台。
您的解释是正确的,但缺少一个关键点:我们使用不透明指针的原因是为了隐藏结构实现的细节,以便我们可以在软件的未来版本中修改此结构,而不会破坏使用它的现有代码。
本质上,与 Java 的类似如下:
不透明指针的声明,以及接受(或返回)这种不透明指针的每个函数的声明,都对应于
interface
Java 中的。(注意:仅是声明。而不是它们的实际定义。)不透明指针指向的结构和函数定义集更像是一个具体的 Java 类
implements
,其接口只包含私有成员字段,因此没有人可以访问它们。另一个与不透明指针非常相似的概念是句柄。函数
open()
返回int
一个文件句柄,、和方法接受这样的句柄作为参数。这个数字可以是任何东西,你不应该以任何方式解释它,也不应该期望它的值在任何特定范围内。理论上,在足够大到可以容纳指向结构的指针的系统上,文件句柄实际上可以是已转换为的结构指针。实际上,它是某个表(或类似表)的索引,该表完全由标准库(或操作系统)维护,因此你看不到它,因此不会弄乱它。read()
write()
close()
int
int
FILE
这些都是在面向对象编程发明之前人们使用的实现封装的非常原始的机制。由于没有指导原则,也没有标准的做事方式,人们到处乱搞,以各种方式破坏了封装。
例如,C 标准库可以将
FILE
其视为不透明指针,但出于某种原因,大多数实现选择不这样做,因为它们在头文件中定义了struct
for ,而您实际上可以这样做。(请参阅Stack Overflow:Unix 中 FILE 的定义在哪里)FILE
#include
再举一个例子,您不应该解释文件句柄的值,但是标准流(输入、输出、错误)的文件句柄确实具有众所周知的值,本质上它们只不过是神奇的数字。
不,这是完全不相关的事情。
不透明指针是指向不完全指定(外部)的指针
struct
,用于隐藏结构的内部表示。更确切地说,它们是指向不完全定义类型(未指定的字段结构或未指定长度的数组)的指针。这样,可以使用指针,但不能使用指向的数据,因为结构内容对于编译器来说是未知的。在上面的代码中,我们将类型定义
hash_table_p
为指向未定义结构的指针,该指针可被哈希表例程用作提供给用户的不透明数据,只需将其传递回处理结构内部作为外部不可访问字段的例程即可。由于指向类型的指针不可互换,因此指针引用不能混合使用,因此指向的指针
struct hash_table
必须始终使用真实的哈希表引用进行初始化(如果您小心谨慎,编译器将始终保证这一点)。指向不同类型的指针永远不会与指向不同类型的指针兼容(除非您对其进行强制转换)。唯一的例外是指向的指针void
与任何其他类型的指针兼容。您可以将声明保留在外部,并在实现代码中提供 的完整定义
struct hash_table
。编译器将允许您声明尽可能多的引用类型的指针,但数据的内部结构对外部代码是隐藏的。结构struct hash_table
通常在包含文件中定义hash_tableP.h
(其中还包括外部文件),因此 C 可以模拟Modula-2 语言的DEFINITION MODULE
和IMPLEMENTATION MODULE
编译单元(或Ada 的package
和package body
)另一方面,Java 接口是一组方法声明,允许面向对象的类进行
implement
所谓的接口,因此被视为实现所有这些方法的类的对象。这在某种程度上定义了一个像对象的类,但不是从另一个类派生出来的。C 不能将一组过程声明关联到一种类型中,从而只有实现这些过程的实例才被视为属于单一类型(如果类型可以与类进行比较),因此 C 中没有与 Java 接口模型类似的图形。