Когда структура данных (например, очередь) реализуется с использованием языка ООП, некоторые члены структуры данных должны быть частными (например, количество элементов в очереди).
Очередь также может быть реализована на процедурном языке с использованием struct
функций и набора функций, которые работают на struct
. Тем не менее, на процедурном языке вы не можете сделать членов struct
частного. Были ли члены структуры данных, реализованные на процедурном языке, оставлены публичными, или был какой-то прием, чтобы сделать их приватными?
object-oriented
data-structures
history
Кристофер
источник
источник
Ответы:
ООП не изобрел инкапсуляцию и не является синонимом инкапсуляции. Многие языки ООП не имеют модификаторов доступа в стиле C ++ / Java. Многие не-ООП языки имеют различные методы, доступные для инкапсуляции.
Один классический подход к инкапсуляции - это замыкания , используемые в функциональном программировании . Это значительно старше ООП, но в некотором смысле эквивалентно. Например, в JavaScript мы можем создать такой объект:
Вышеуказанный
plus2
объект не имеет члена, который бы позволял прямой доступ к немуx
- он полностью инкапсулирован.add()
Метод представляет собой замыкание поx
переменной.Язык C поддерживает некоторые виды инкапсуляции посредством механизма заголовочных файлов , в частности, метод непрозрачного указателя . В C можно объявить имя структуры без определения ее членов. На этом этапе нельзя использовать переменную типа этой структуры, но мы можем свободно использовать указатели на эту структуру (поскольку размер указателя структуры известен во время компиляции). Например, рассмотрим этот заголовочный файл:
Теперь мы можем написать код, который использует этот интерфейс Adder, не имея доступа к его полям, например:
И здесь будут полностью инкапсулированные детали реализации:
Существует также класс модульных языков программирования , который фокусируется на интерфейсах уровня модуля. Языковая семья ML, вкл. OCaml включает интересный подход к модулям, называемым функторами . ООП затмило и в значительной степени отнесено к модульному программированию, но многие предполагаемые преимущества ООП больше касаются модульности, чем объектной ориентации.
Также есть наблюдение, что классы в языках ООП, таких как C ++ или Java, часто используются не для объектов (в смысле сущностей, которые разрешают операции посредством позднего связывания / динамической диспетчеризации), а просто для абстрактных типов данных (где мы определяем открытый интерфейс, который скрывает детали внутренней реализации). В статье « Понимание абстракции данных» (Cook, 2009) обсуждается это различие более подробно.
Но да, во многих языках вообще нет механизма инкапсуляции. На этих языках члены структуры остаются открытыми. Самое большее, соглашение об именах будет препятствовать использованию. Например, я думаю, что у Паскаля не было полезного механизма инкапсуляции.
источник
Adder self = malloc(sizeof(Adder));
? Есть причина, указывающая на указатели типа, и на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:
foo.c:
Посмотрите на Windows SDK! Он использует HANDLE и UINT_PTR, и тому подобные вещи, чтобы быть общими дескрипторами памяти, используемой в API - эффективно делая реализации частными.
источник
«Непрозрачные типы данных» были хорошо известной концепцией, когда я получил степень по информатике 30 лет назад. Мы не охватывали ООП, поскольку в то время оно не использовалось широко, и «функциональное программирование» считалось более правильным.
Modula-2 имела прямую поддержку для них, см. Https://www.modula2.org/reference/modules.php .
Льюис Прингл уже объяснил, как в C. можно использовать объявление о структуре в отличие от модуля-2, для создания объекта требовалась фабричная функция. ( Виртуальные методы также было легко реализовать в C , так как первый член структуры был указателем на другую структуру, которая содержала указатели на методы.)
Часто соглашение также использовалось. Например, к любому полю, начинающемуся с «_», нельзя обращаться за пределы файла, которому принадлежат данные. Это было легко обеспечено созданием пользовательских инструментов проверки.
В каждом крупномасштабном проекте, над которым я работал (до перехода на C ++, затем на C #), была система, предотвращающая доступ к «частным» данным из-за неправильного кода. Это было чуть менее стандартизировано, чем сейчас.
источник
Обратите внимание, что существует много языков OO без встроенной возможности помечать участников как приватные. Это может быть сделано по соглашению, без необходимости для компилятора обеспечивать конфиденциальность. Например, люди часто ставят префикс частных переменных с подчеркиванием.
Существуют методы, которые затрудняют доступ к «закрытым» переменным, наиболее распространенным из которых является идиома PIMPL . Это помещает ваши приватные переменные в отдельную структуру, с указателем в ваших публичных заголовочных файлах. Это означает дополнительную разыменованность и приведение для получения любых частных переменных, что-то вроде этого
((private_impl)(obj->private))->actual_value
, что раздражает, поэтому на практике редко используется.источник
Структуры данных не имели «членов», только поля данных (при условии, что это был тип записи). Видимость обычно была установлена для всего типа. Однако это может быть не таким ограничивающим, как вы думаете, потому что функции не были частью записи.
Давайте вернемся назад и получим немного истории здесь ...
Доминирующая парадигма программирования до ООП называлась структурным программированием . Первоначальная главная цель этого состояла в том, чтобы избежать использования неструктурированных операторов перехода ("goto"). Это парадигма, ориентированная на поток управления (в то время как ООП в большей степени ориентирована на данные), но она все еще оставалась естественным продолжением попытки сохранить данные логически структурированными, как в коде.
Другим следствием структурированного программирования было сокрытие информации , идея о том, что реализации структуры кода (которая может изменяться довольно часто) должны храниться отдельно от интерфейса (который в идеале не будет меняться почти так же сильно). Это догма сейчас, но в былые времена, многие люди на самом деле считали лучше для каждого разработчика , чтобы узнать подробности о всей системе, так что это было в свое время на самом деле спорная идея. Оригинальное издание « Мистического человека за месяц» Брука фактически выступало против сокрытия информации.
Более поздние языки программирования, явно предназначенные для того, чтобы быть хорошими языками структурированного программирования (например, Modula-2 и Ada), обычно включали в себя скрытую информацию как фундаментальную концепцию, построенную вокруг некоторой концепции связного средства функций (и любых типов, констант и объекты, которые они могут потребоваться). В Модуле-2 их называли «Модулями», в Аде - «Пакетами». Многие современные языки ООП называют одну и ту же концепцию "пространства имен". Эти пространства имен были организационной основой разработки на этих языках, и для большинства целей могли использоваться аналогично классам ООП (конечно, без реальной поддержки наследования).
Таким образом, в Modula-2 и Ada (83) вы можете объявить любую подпрограмму, тип, константу или объект в пространстве имен частным или общедоступным, но если у вас был тип записи, не было (простого) способа объявить некоторые поля записи общедоступными. и другие частные. Либо вся ваша запись является публичной, либо нет.
источник
object.method()
просто синтаксический сахар. Важно ИМХО - см. Принцип единого доступа / ссылки Майера - но все же просто синтаксический сахар.object.method()
в качестве альтернативной формыmethod(object, ...)
людей, которые просто не могли сделать концептуальный скачок.В Си вы уже могли передавать указатели на объявленные, но неопределенные типы, как говорили другие, фактически ограничивая доступ ко всем полям.
Вы также можете иметь частные и публичные функции в зависимости от модуля. Функции, объявленные как статические в исходном файле, не видны снаружи, даже если вы пытаетесь угадать их имя. Точно так же вы можете иметь статические глобальные переменные на уровне файлов, что обычно является плохой практикой, но допускает изоляцию на модульной основе.
Вероятно, важно подчеркнуть, что ограничение доступа в качестве хорошо стандартизированного соглашения, а не навязанной языком конструкции работает просто отлично (см. Python). Кроме того, ограничение доступа к полям объекта может защитить программиста только тогда, когда необходимо изменить значение данных внутри объекта после создания. Который уже пахнет кодом. Можно утверждать, что C и, в частности,
const
ключевое слово C ++ для методов и аргументов функций - гораздо более полезная помощь для программиста, чем довольно слабая Javafinal
.источник
static
глобальными данными и операциями (что означало, что они не были представлены компоновщику для использования из других компиляций). Вы можете правдоподобно утверждать, что любая поддержка, которую C оказывал для хороших практик проектирования программного обеспечения, кроме того, что это было в значительной степени хаком, и не являлось частью оригинального дизайна языка еще в 1972 году.Если ваше определение Public - это возможность доступа к реализации и данным / свойствам через ваш собственный код в любой момент, ответ прост: да . Тем не менее, он был абстрагирован различными способами - в зависимости от языка.
Я надеюсь, что это кратко ответил на ваш вопрос.
источник
Вот очень простой контрпример: в Java
interface
s определяют объекты, аclass
es - нет. Aclass
определяет абстрактный тип данных, а не объект.Следовательно, каждый раз, когда вы используете
private
вclass
Java, у вас есть пример структуры данных с закрытыми членами, которая не является объектно-ориентированной.источник