По описанным причинам трудно согласиться, что ОО зависит от строгой инкапсуляции. В действительности многие языки ОО практически не имеют принудительной инкапсуляции[13].

ОО безусловно полагается на поведение программистов – что они не станут использовать обходные приемы для работы с инкапсулированными данными. То есть языки, заявляющие о поддержке OO, фактически ослабили превосходную инкапсуляцию, некогда существовавшую в C.

Наследование?

Языки ОО не улучшили инкапсуляцию, зато они дали нам наследование.

Точнее – ее разновидность. По сути, наследование – это всего лишь повторное объявление группы переменных и функций в ограниченной области видимости. Нечто похожее программисты на C проделывали вручную задолго до появления языков ОО[14].

Взгляните на дополнение к нашей исходной программе point.h на языке C:


>namedPoint.h

>struct NamedPoint;


>struct NamedPoint* makeNamedPoint(double x, double y, char* name);

>void setName(struct NamedPoint* np, char* name);

>char* getName(struct NamedPoint* np);


>namedPoint.c

>#include "namedPoint.h"

>#include


>struct NamedPoint {

> double x,y;

> char* name;

>};


>struct NamedPoint* makeNamedPoint(double x, double y, char* name) {

> struct NamedPoint* p = malloc(sizeof(struct NamedPoint));

> p->x = x;

> p->y = y;

> p->name = name;

> return p;

>}


>void setName(struct NamedPoint* np, char* name) {

> np->name = name;

>}


>char* getName(struct NamedPoint* np) {

> return np->name;

>}

>main.c

>#include "point.h"

>#include "namedPoint.h"

>#include


>int main(int ac, char** av) {

> struct NamedPoint* origin = makeNamedPoint(0.0, 0.0, "origin");

> struct NamedPoint* upperRight = makeNamedPoint

> (1.0, 1.0, "upperRight");

> printf("distance=%f\n",

> distance(

> (struct Point*) origin,

> (struct Point*) upperRight));

>}


Внимательно рассмотрев основной код в файле >main.c, можно заметить, что структура данных >NamedPoint используется, как если бы она была производной от структуры >Point. Такое оказалось возможным потому, что первые два поля в >NamedPoint совпадают с полями в >Point. Проще говоря, >NamedPoint может маскироваться под >Point, потому что >NamedPoint фактически является надмножеством >Point и имеет члены, соответствующие структуре >Point, следующие в том же порядке.

Этот прием широко применялся[15] программистами до появления ОО. Фактически именно так C++ реализует единственное наследование.

То есть можно сказать, что некоторая разновидность наследования у нас имелась задолго до появления языков ОО. Впрочем, это утверждение не совсем истинно. У нас имелся трюк, хитрость, не настолько удобный, как настоящее наследование. Кроме того, с помощью описанного приема очень сложно получить что-то похожее на множественное наследование.

Обратите также внимание, как в >main.c мне пришлось приводить аргументы >NamedPoint к типу >Point. В настоящем языке ОО такое приведение к родительскому типу производится неявно.

Справедливости ради следует отметить, что языки ОО действительно сделали маскировку структур данных более удобной, хотя это и не совсем новая особенность.

Итак, мы не можем дать идее ОО ни одного очка за инкапсуляцию и можем дать лишь пол-очка за наследование. Пока что общий счет не впечатляет.

Но у нас есть еще одно понятие.

Полиморфизм?

Была ли возможность реализовать полиморфное поведение до появления языков ОО? Конечно! Взгляните на следующую простую программу copy на языке C.


>#include


>void copy() {

> int c;

> while ((c=getchar())!= EOF)

> putchar(c);

>}


Функция >getchar() читает символы из >STDIN. Но какое устройство в действительности скрыто за ширмой >STDIN? Функция >putchar() записывает символы в устройство