Кажется, что у С есть свои квазиобъекты, такие как «структуры», которые можно рассматривать как объекты (на высоком уровне, который мы обычно думаем).
Кроме того, сами файлы C в основном являются отдельными "модулями", верно? Тогда разве модули тоже не похожи на «объекты»? Меня смущает, почему C, который кажется очень похожим на C ++, считается низкоуровневым "процедурным" языком, где C ++ является высокоуровневым "объектно-ориентированным"
* edit: (уточнение) почему и где проводится линия, для чего это «объект», а что нет?
object-oriented
procedural
Темный тамплиер
источник
источник
Ответы:
Давайте вместе рассмотрим страницу Википедии об объектно-ориентированном программировании и отметим особенности структур в стиле C, которые соответствуют тому, что традиционно считается объектно-ориентированным стилем:
Структуры C состоят из полей и методов вместе с их взаимодействиями ? Нет .
Структуры C выполняют какие-либо из этих вещей "первоклассным" способом? Нет. Язык работает против вас на каждом шагу.
Структуры C делают это? Нет.
Структуры C делают это? Да.
Нет.
Может ли сама структура отправлять и получать сообщения? Может ли он обрабатывать данные? Нет.
Это происходит в C? Нет.
Есть ли какие-либо из этих особенностей структур C? Нет.
Какие именно характеристики структур, по вашему мнению, являются «объектно-ориентированными»? Потому что я не могу найти ничего, кроме факта, что структуры определяют типы .
Теперь, конечно, вы можете создавать структуры, которые имеют поля, которые являются указателями на функции. Вы можете сделать структуры иметь поля, которые являются указателями на массивы указателей на функции, соответствующие таблицам виртуальных методов. И так далее. Конечно, вы можете эмулировать C ++ на C. Но это очень не идиоматический способ программирования на C; вам лучше использовать C ++.
Опять же, о каких характеристиках модулей вы думаете, что заставляет их действовать как объекты? Поддерживают ли модули абстракцию, инкапсуляцию, обмен сообщениями, модульность, полиморфизм и наследование?
Абстракция и инкапсуляция довольно слабы. Очевидно, что модули являются модульными; Вот почему они называются модулями. Сообщения? Только в том смысле, что вызов метода является сообщением, а модули могут содержать методы. Полиморфизм? Нет. Наследование? Нет. Модули являются довольно слабыми кандидатами на «объекты».
источник
Ключевое слово «ориентированный», а не «объект». Даже код C ++, который использует объекты, но использует их как структуры, не является объектно- ориентированным .
C и C ++ могут одновременно выполнять ООП (кроме контроля доступа в C), но синтаксис для этого в C неудобен (если не сказать больше), в то время как синтаксис в C ++ делает его очень привлекательным. C ориентирован на процедурный, в то время как C ++ ориентирован на объекты, несмотря на почти идентичные основные возможности в этом отношении.
Код, который использует объекты для реализации проектов, которые могут быть выполнены только с объектами (обычно это означает использование преимуществ полиморфизма), является объектно-ориентированным кодом. Код, который использует объекты всего лишь как пакеты данных, даже используя наследование в объектно-ориентированном языке, на самом деле представляет собой просто процедурный код, который сложнее, чем нужно. Код на C, который использует указатели на функции, которые изменяются во время выполнения с структурами, полными данных, в некотором роде вызывает полиморфизм, и его можно назвать «объектно-ориентированным», даже в процедурно-ориентированном языке.
источник
Основано на принципах самого высокого уровня:
Объект - это инкапсуляция данных и поведения взаимосвязанным способом, так что они работают как единое целое, которое может быть создано несколько раз и работать как черный ящик, если вы знаете внешний интерфейс.
Структуры содержат данные, но не имеют поведения и поэтому не могут рассматриваться как объекты.
Модули содержат как поведение, так и данные, но не инкапсулированы таким образом, что эти два связаны и, конечно, не могут быть созданы несколько раз.
И это прежде, чем вы перейдете к наследованию и полиморфизму ...
источник
«структуры» являются только данными. Обычный быстрый и грязный тест «объектной ориентации» таков: «Существует ли структура, позволяющая инкапсулировать код и данные как единое целое?». С не удается, и, следовательно, является процедурным. C ++ проходит этот тест.
источник
this
указатель, но в этом случае данные и средства для обработки данных будут инкапсулированы внутри структуры.#include
d в него, и минус что - то удалены не условно включены (#if
,#ifdef
и тому подобное).C, как и C ++, обладает способностью предоставлять Data Abstraction , которая является одной из идиом парадигмы объектно-ориентированного программирования, существовавшей до него.
ООП в C ++ расширяет средства для абстрагирования данных. Некоторые говорят, что это вредно , в то время как другие считают это хорошим инструментом при правильном использовании.
Тем не менее, вы найдете много проповедей «хакеров» C о том, как C идеально подходит для нужного количества абстракций и как накладные расходы, создаваемые C ++, только отвлекают их от решения актуальной проблемы.
Другие склонны смотреть на это более взвешенно, принимая как преимущества, так и недостатки.
источник
Вам нужно взглянуть на другую сторону медали: C ++.
В ООП мы думаем об абстрактном объекте (и проектируем программу соответственно), например, автомобиль, который может останавливаться, ускоряться, поворачивать влево или вправо и т. Д. Структура с набором функций просто не соответствует концепции.
С «реальными» объектами нам нужно, например, скрывать членов, или мы также можем иметь наследование с реальными отношениями «есть» и многое другое.
ПОСЛЕ ПРОЧИТАНИЯ КОММЕНТАРИЙ НИЖЕ: Хорошо, что (почти) все можно сделать с C (это всегда так), но на первый взгляд я подумал, что то, что отличает c от c ++, - это то, что вы думаете при разработке программы.
Единственное, что действительно имеет значение - это навязывание компилятором политик . т.е. чисто виртуальная функция и тому подобное. но этот ответ будет касаться только технических вопросов, но я думаю, что основное отличие (как уже упоминалось) заключается в оригинальном способе мышления во время кодирования, поскольку C ++ дает вам лучший встроенный синтаксис для выполнения таких задач, вместо того, чтобы выполнять ООП в несколько неуклюжий путь в C.
источник
Вы вроде сказали это сами. Хотя в C есть вещи, которые похожи на объекты, они все же не являются объектами, и поэтому C не считается языком ООП.
источник
Объектно-ориентированный относится как к архитектурному шаблону (или даже к мета-шаблону), так и к языкам, которые имеют функции, помогающие реализовать или предписать использование этого шаблона.
Вы можете реализовать дизайн "OO" (рабочий стол Gnome, пожалуй, лучший пример OO, выполненного на чистом C), я даже видел, как это делается с COBOL!
Однако возможность реализовать проектную дозу ОО не делает язык ОО. Пуристы утверждают, что Java и C ++ на самом деле не являются объектно-ориентированными, так как вы не можете переопределять или наследовать базовые «типы», такие как «int» и «char», а Java не поддерживает множественное наследование. Но поскольку они являются наиболее широко используемыми ОО-языками и поддерживают большинство парадигм, большинство «настоящих» программистов, которым платят за создание рабочего кода, рассматривают их как ОО-языки.
C, с другой стороны, поддерживает только структуры (как это делают COBOL, Pascal и десятки других процедурных языков), вы можете утверждать, что поддерживает множественное наследование в том смысле, что вы можете использовать любую функцию на любом фрагменте данных, но большинство будет рассматривать это как ошибку чем особенность.
источник
Давайте просто посмотрим на определение ОО:
С не предоставляет ни один из этих трех. В частности, он не обеспечивает обмен сообщениями , который является наиболее важным.
источник
static
) функции и члены данных.У ОО есть ряд ключевых ингредиентов, но основными являются то, что большая часть кода не знает, что находится внутри объекта (они видят интерфейс поверхности, а не реализацию), что состояние объекта является управляемой единицей. (т. е. когда объект перестает быть, то же самое происходит и с его состоянием), и когда некоторый код вызывает операцию над объектом, они делают это, не зная точно, что это за операция или что она включает (все, что они делают, это следуют шаблону, чтобы бросить «Сообщение» через стену).
C делает инкапсуляцию просто отлично; код, который не видит определения структуры, не может (законно) заглянуть внутрь нее. Все, что вам нужно сделать, это поместить такое определение в заголовочный файл:
Конечно, понадобится функция, которая строит
Foo
s (т. Е. Фабрика) и которая должна делегировать часть работы самому выделенному объекту (т. Е. Через метод «конструктор»), а также иметь способ снова избавиться от объекта (позволяя очистить его методом «деструктор»), но это детали.Диспетчеризация метода (т. Е. Обмен сообщениями) также может быть выполнена с помощью соглашения, согласно которому первый элемент структуры фактически является указателем на структуру, полную указателей на функции, и что каждый из этих указателей на функцию должен принимать в
Foo
качестве своего первого аргумента. Диспетчеризация становится вопросом поиска функции и вызова ее с правильным перезаписыванием аргумента, что не так сложно сделать с помощью макроса и немного хитрости. (Эта таблица функций является основой того, чем на самом деле является класс в языке, подобном C ++.)Более того, это также дает вам позднее связывание: все, что знает код диспетчеризации, это то, что он вызывает конкретное смещение в таблице, на которую указывает объект. Это нужно только установить во время выделения и инициализации объекта. Можно пойти с еще более сложными схемами диспетчеризации, которые дадут вам больше динамизма во время выполнения (за счет скорости), но они являются вишнями на вершине основного механизма.
Но это не значит, что C является языком OO. Ключевым моментом является то, что C оставляет вам всю сложную работу по написанию соглашений и механизма рассылки самостоятельно (или использует стороннюю библиотеку). Это много работы. Он также не обеспечивает синтаксическую или семантическую поддержку, поэтому реализация полной системы классов (с такими вещами, как наследование) была бы излишне болезненной; Если вы имеете дело со сложной проблемой, которая хорошо описана в ОО-модели, ОО-язык будет очень полезен при написании решения. Дополнительная сложность может быть оправдана.
источник
Я думаю, что C отлично подходит и подходит для реализации объектно-ориентированных концепций, пожав плечами . Большинство различий между общепринятым подмножеством языков, рассматриваемых как объектно-ориентированные, на мой взгляд, незначительны и синтаксичны с моей прагматической точки зрения.
Начнем, скажем, с сокрытия информации. В C мы можем достичь этого, просто скрывая определение структуры и работая с ней через непрозрачные указатели. Это фактически моделирует
public
противprivate
различия полей данных , так как мы получаем с классами. И это достаточно просто сделать и вряд ли анти-идиоматично, так как стандартная библиотека C сильно зависит от этого, чтобы добиться сокрытия информации.Конечно, вы теряете возможность легко контролировать, где именно структура размещается в памяти, используя непрозрачные типы, но это только заметное различие между, скажем, C и C ++. C ++, безусловно, является превосходным инструментом при сравнении его способности программировать объектно-ориентированные концепции на C, сохраняя при этом контроль над макетами памяти, но это не обязательно означает, что Java или C # превосходят C в этом отношении, поскольку эти два делают вас полностью теряет способность контролировать, где объекты размещены в памяти.
И мы должны использовать такой синтаксис, как
fopen(file, ...); fclose(file);
в отличие отfile.open(...); file.close();
большого возгласа. Кто на самом деле заботится? Может быть, просто тот, кто сильно полагается на автозаполнение в своей IDE. Я признаю, что это может быть очень полезной функцией с практической точки зрения, но, возможно, не такой, которая требует обсуждения того, подходит ли язык для ООП.Нам не хватает возможности эффективно внедрять
protected
поля. Я полностью подчинюсь там. Но я не думаю, что есть конкретное правило, которое гласит: « Все ОО-языки должны иметь функцию, позволяющую подклассам получать доступ к членам базового класса, которые по-прежнему недоступны для обычных клиентов ». Кроме того, я редко вижу варианты использования для защищенных пользователей, которые, по крайней мере, немного не подозревают о том, что могут стать препятствием на пути обслуживания.И, конечно, мы должны «эмулировать» ОО-полиморфизм с помощью таблиц функциональных указателей и указателей на них для динамической отправки с небольшим дополнительным шаблоном для инициализации этих аналогичных
vtables
иvptrs
, но немного шаблонного шаблона, который никогда не вызывал у меня большого горя.Наследование во многом аналогично. Мы можем легко смоделировать это с помощью композиции, и во внутренней работе компиляторов все сводится к одному и тому же. Конечно, мы теряем безопасность типов, если мы хотим понизить рейтинг , и я бы сказал, что если вы вообще хотите понизить рейтинг , пожалуйста, не используйте для этого C, потому что то, что люди делают в C для эмуляции понижения, может быть ужасным для типа. с точки зрения безопасности, но я бы предпочел, чтобы люди вообще не унывали . Безопасность типов - это то, что вы легко можете пропустить в C, так как компилятор предоставляет столько возможностей для интерпретации вещей, как просто биты и байты, жертвуя возможностью отлавливать возможные ошибки во время компиляции, но некоторые языки считаются объектно-ориентированными. даже статически не напечатано.
Так что не знаю, я думаю, что все в порядке. Конечно, я бы не использовал C, чтобы попытаться создать крупномасштабную кодовую базу, которая соответствует принципам SOLID, но это не обязательно из-за ее недостатков в объектно-ориентированном фронте. Многие функции, которые мне не хватало бы, если бы я попытался использовать C для таких целей, были бы связаны с языковыми функциями, которые не считаются непосредственно необходимыми для ООП, такими как строгая безопасность типов, деструкторы, которые автоматически вызываются, когда объекты выходят из области видимости, оператор перегрузка, шаблоны / шаблоны и обработка исключений. Это когда я скучаю по тем вспомогательным функциям, которые мне доступны для C ++.
источник
foo_create
иfoo_destroy
иfoo_clone
, напримерstruct Foo
в таком случае, - это обеспечить, чтобы внешние элементы не могли получить доступ к их элементам данных и не могли их изменить, что сразу дают непрозрачные типы (объявленные, но не определенные для внешнего мира). Возможно, это более сильная форма сокрытия информации, по сравнению сpimpl
C ++.Неплохой вопрос.
Если вы собираетесь называть c языком OO, вам нужно будет также назвать почти все процедурные языки OO. Так что это сделало бы этот термин бессмысленным. c не имеет языковой поддержки для OO. Если имеет структуры, но структуры
types
нет классов.На самом деле c не имеет много возможностей по сравнению с большинством языков. В основном это скорость, простота, популярность и поддержка, включая тонны библиотек.
источник