使用OOP语言实现数据结构(例如,队列)时,数据结构的某些成员需要为私有的(例如,队列中的项目数)。
队列也可以使用struct
和在上操作的一组函数以过程语言实现struct
。但是,在过程语言中,您不能将成员struct
设为私有成员。使用过程语言实现的数据结构的成员是否公开了,还是有一些技巧使其私有化?
使用OOP语言实现数据结构(例如,队列)时,数据结构的某些成员需要为私有的(例如,队列中的项目数)。
队列也可以使用struct
和在上操作的一组函数以过程语言实现struct
。但是,在过程语言中,您不能将成员struct
设为私有成员。使用过程语言实现的数据结构的成员是否公开了,还是有一些技巧使其私有化?
Answers:
OOP没有发明封装,并且与封装不相同。许多OOP语言没有C ++ / Java样式访问修饰符。许多非OOP语言具有可用于提供封装的各种技术。
一种经典的封装方法是闭包,如函数编程中所使用的。这比OOP显着老,但是在某种意义上是等效的。例如,在JavaScript中,我们可能会创建一个像这样的对象:
function Adder(x) {
this.add = function add(y) {
return x + y;
}
}
var plus2 = new Adder(2);
plus2.add(7); //=> 9
上面的plus2
对象没有允许直接访问的成员x
-它是完全封装的。该add()
方法是对x
变量的闭包。
所述Ç语言通过其支持一些种封装的报头文件机制,特别是不透明的指针技术。在C中,可以在不定义其成员的情况下声明结构名称。那时不能使用该结构类型的变量,但是我们可以自由使用指向该结构的指针(因为在编译时知道结构指针的大小)。例如,考虑以下头文件:
#ifndef ADDER_H
#define ADDER_H
typedef struct AdderImpl *Adder;
Adder Adder_new(int x);
void Adder_free(Adder self);
int Adder_add(Adder self, int y);
#endif
现在,我们可以编写使用此Adder接口的代码,而无需访问其字段,例如:
Adder plus2 = Adder_new(2);
if (!plus2) abort();
printf("%d\n", Adder_add(plus2, 7)); /* => 9 */
Adder_free(plus2);
这是完全封装的实现细节:
#include "adder.h"
struct AdderImpl { int x; };
Adder Adder_new(int x) {
Adder self = malloc(sizeof *self);
if (!self) return NULL;
self->x = x;
return self;
}
void Adder_free(Adder self) {
free(self);
}
int Adder_add(Adder self, int y) {
return self->x + y;
}
还有一类模块化的编程语言,它专注于模块级接口。ML语言家族,包括 OCaml包含了一种有趣的模块功能,称为函子。OOP在很大程度上掩盖了模块化编程,但OOP的许多优点却更多地在于模块化而不是面向对象。
还观察到,OOP语言(如C ++或Java)中的类通常不用于对象(即通过后期绑定/动态分配来解析操作的实体),而仅用于抽象数据类型(在此我们定义了隐藏的公共接口)内部实施细节)。本文的了解数据抽象,再访(库克,2009年)详细讨论这种差别。
但是,是的,许多语言都没有封装机制。在这些语言中,结构成员不公开。最多会有一个禁止使用的命名约定。例如,我认为Pascal没有有用的封装机制。
Adder self = malloc(sizeof(Adder));
?typedef-ing指针sizeof(TYPE)
是有原因的,并且通常对此不屑一顾。
sizeof(*Adder)
,因为*Adder
它不是类型,就像*int *
不是类型一样。该表达T t = malloc(sizeof *t)
既惯用又正确。看到我的编辑。
private static
于Java中的变量。与C相似,您可以使用不透明指针在Pascal中传递数据而无需声明它是什么。由于记录(数据结构)的公共部分和私有部分可能会一起传递,因此经典MacOS使用了许多不透明的指针。我记得Window Manager会做很多事情,因为Window Record的某些部分是公开的,但也包括一些内部信息。
_private_member
和的命名约定output_property_
,或者使用更先进的技术来制造可植入对象。
首先,面向程序与面向对象与公共与私有无关。许多面向对象的语言没有访问控制的概念。
其次,在“ C”中-大多数人都将其称为过程性的,而不是面向对象的,可以使用许多技巧来有效地使事物私有化。一种非常常见的方法是使用不透明(例如void *)指针。或者-您可以向前声明一个对象,而不必在头文件中定义它。
foo.h:
struct queue;
struct queue* makeQueue();
void add2Queue(struct queue* q, int value);
...
foo.c:
struct queue {
int* head;
int* head;
};
struct queue* makeQueue() { .... }
void add2Queue(struct queue* q, int value) { ... }
看看Windows SDK!它使用HANDLE和UINT_PTR,以及类似的东西作为API中使用的内存的通用句柄-有效地使实现私有化。
30年前,当我获得计算机科学学位时,“不透明数据类型”是一个众所周知的概念。我们没有介绍OOP,因为当时还不普遍使用OOP,因此认为“函数式编程”更为正确。
Modula-2直接支持它们,请参阅https://www.modula2.org/reference/modules.php。
Lewis Pringle已经解释了如何在C中使用向前声明结构的方法。与Module-2不同,必须提供工厂函数来创建对象。(通过将结构的第一个成员作为指向另一个包含指向方法的函数指针的结构的指针,虚拟方法也易于在C中实现。)
通常也使用约定。例如,不应在拥有数据的文件外部访问以“ _”开头的任何字段。通过创建自定义检查工具可以轻松地实施此操作。
我从事的每个大型项目(在我使用C ++之前,然后是C#)都有一个系统来防止错误的代码访问“私人”数据。它只是比现在少了一点标准化。
数据结构没有“成员”,只有数据字段(假设它是记录类型)。通常为整个类型设置可见性。但是,这可能没有您想象的那么有限,因为这些功能不是记录的一部分。
让我们回去看看这里的一些历史...
OOP之前的主导编程范式被称为结构化编程。最初的主要目标是避免使用非结构化的跳转语句(“ goto”)。这是一个面向控制流的范式(而OOP则更面向数据),但是它仍然是它的自然扩展,试图保持数据的逻辑结构像代码一样。
结构化编程的另一个优势是信息隐藏,即认为代码结构的实现(可能会经常更改)应该与接口分开(理想情况下不会发生太大变化)。现在这是教条,但是在过去,许多人实际上认为,对于每个开发人员来说,了解整个系统的详细信息更好,因此,这实际上是一个有争议的想法。布鲁克的《神话人月》的原始版本实际上反对信息隐藏。
后来被明确设计为良好的结构化编程语言的编程语言(例如Modula-2和Ada)通常将信息隐藏作为基本概念,它是围绕某种功能性内聚性功能(以及任何类型,常数和他们可能需要的对象)。在Modula-2中,这些称为“模块”,在Ada中称为“包装”。许多现代的OOP语言将相同的概念称为“命名空间”。这些名称空间是使用这些语言进行开发的组织基础,并且在大多数情况下,它们可以类似于OOP类使用(当然,不真正支持继承)。
因此,在Modula-2和Ada(83)中,您可以在私有或公共名称空间中声明任何例程,类型,常量或对象,但是如果您有记录类型,则没有(简便)方法可以将某些记录字段声明为公共和其他私人。您的整个记录是公开的,还是不是公开的。
object.method()
调用只是语法糖。重要的恕我直言-请参阅迈尔的统一访问/参考原则-但仍然只是语法糖。
object.method()
,method(object, ...)
为那些无法进行概念性跨越的人们提供了一种替代形式。
在C语言中,您已经可以像其他人所说的那样传递指向已声明但未定义类型的指针,实际上限制了对所有字段的访问。
您还可以在模块到模块的基础上拥有私有和公共功能。即使您试图猜测它们的名称,在源文件中声明为静态的函数对外部也不可见。同样,您可以具有静态的文件级全局变量,这通常是不好的做法,但允许在模块基础上进行隔离。
需要强调的是,将访问限制作为一种标准化的约定而不是由语言强制的构造很好地起作用(请参阅Python)。最重要的是,只有在创建后需要更改对象内部数据的值时,限制对对象字段的访问才能保护程序员。这已经是代码的味道了。可以说,const
对于Java和Java而言,C的方法和函数参数的关键字对程序员的帮助更大final
。
static
全局数据和操作(这意味着它们不会提供给链接器供其他编译使用)。您可以合理地辩称,C对良好软件设计实践的任何支持,除此以外,几乎都是黑客,而不是1972
这是一个非常简单的反例:在Java中,interface
s定义对象,而class
es则不。A class
定义了抽象数据类型,而不是对象。
人机工程学,你使用任何时间private
在class
Java中,你有没有被面向对象的私有成员的数据结构的一个例子。