Многие люди говорят, что C ++ - это совершенно другой язык, чем C, но сам Бьярне сказал, что C ++ - это язык, который расширен от C, поэтому и является его источником ++
. Так почему же все продолжают говорить, что C и C ++ - это совершенно разные языки? Чем C отличается от C ++, кроме расширенных функций в C ++?
programming-languages
c++
c
Джошуа Партоги
источник
источник
Ответы:
В 1980-х годах, когда разработка C ++ только начиналась, C ++ был почти правильным надмножеством C. Именно так все и началось.
Однако со временем и C, и C ++ развивались и отличались друг от друга, хотя совместимость между языками всегда считалась важной.
Кроме того, технические различия между C и C ++ привели к тому, что типичные идиомы в этих языках стали расходиться еще больше.
Это является движущим фактором для людей, говорящих такие вещи, как «нет такого языка, как C / C ++» или «C и C ++ - это два разных языка». Хотя можно писать программы, приемлемые как для компилятора C, так и для C ++, обычно считается, что код не является ни примером хорошего кода C, ни примером хорошего кода C ++.
источник
void *
но C ++ никогда не делал. (Не понизило)Сам Страуструп отвечает на это в своем FAQ :
Это поддержка объектно-ориентированного программирования и универсального программирования, которые делают C ++ «совершенно отличным» от C. Вы можете почти написать чистый C и затем скомпилировать его с помощью компилятора C ++ (если вы позаботитесь о более строгой проверке типов). Но тогда вы все еще пишете C - вы не пишете C ++.
Если вы пишете на C ++, вы используете его объектно-ориентированные и шаблонные функции, и это совсем не то, что вы видели бы в C.
источник
Проще говоря, то, что считается идиоматическим в C, определенно не является идиоматическим в C ++.
C и C ++ на практике очень разные языки из-за того, как люди их используют. C стремится к минимализму, где C ++ является очень сложным языком с множеством функций.
Есть также некоторые практические различия: C легко вызывается практически из любого языка и часто определяет ABI платформы, тогда как C ++ довольно сложно использовать из других библиотек. Большинство языков имеют FFI или интерфейс на C, даже языки, реализованные на C ++ (например, Java).
источник
Помимо очевидного факта, что C ++ поддерживает объектно-ориентированное программирование, я думаю, у вас есть ответ здесь: http://en.wikipedia.org/wiki/Compatibility_of_C_and_C++
Эта статья содержит примеры кода, показывающие то, что хорошо в C, но не в C ++. Например:
Перенос программы на C на C ++ часто прост и состоит в основном из исправления ошибок компиляции (добавления приведений, новых ключевых слов и т. Д.).
источник
C ++ добавляет не только новые функции, но и новые концепции и новые идиомы к C. Несмотря на то, что C ++ и C тесно связаны, факт остается фактом: чтобы эффективно писать на языке, вы должны мыслить в стиле этого языка. Даже самый лучший код C не может использовать в своих интересах различные сильные стороны и идиомы C ++, и поэтому, скорее всего, это не очень плохой код C ++.
источник
«Расширенные возможности», вы делаете так, чтобы они звучали как в C ++, они добавили, как, variadic макросы или что-то в этом роде, и все. «Расширенные возможности» в C ++ являются полным пересмотром языка и полностью вытесняют лучшие практики C, потому что новые функции C ++ намного лучше, чем оригинальные функции C, что оригинальные функции C полностью и полностью избыточны в подавляющем большинстве случаев. , Предположение, что C ++ просто расширяет C, предполагает, что современный боевой танк расширяет нож для целей ведения войны.
источник
Разница в том, что в C вы мыслите процедурно, а в C ++ вы думаете объектно-ориентированным образом. Языки очень похожи, но подход очень другой.
источник
В то время как C ++ может быть супернабором C в синтаксических терминах - то есть любая конструкция программы C может быть скомпилирована компилятором C ++.
Тем не менее, вы почти никогда не пишете программы на C ++ так, как вы делали бы это с программой на C. Список может быть бесконечным или кто-то должен просто сделать больше исследований, чтобы представить его как исчерпывающие отчеты. Тем не менее, я ставлю несколько указателей, которые делают ключевые различия.
Суть данного поста заключается в том, что в C ++ есть следующие функции, которые хорошие программисты на C ++ должны использовать в качестве передового опыта программирования, даже если возможен компиляция эквивалента C.
Как это должно быть сделано в C ++ над C
Классы и наследование. Это наиболее важные различия, которые допускают систематическую объектную ориентацию, что делает программирование выражений очень мощным. Я думаю - этот пункт не нуждается в лучшем объяснении. Если вы находитесь на C ++ - почти всегда, вам лучше использовать классы.
Приватизация - Классы и даже структуры имеют то, что есть частные члены. Это делает возможным инкапсуляцию класса. Эквивалентом в C является типизация объекта как void * для приложения, чтобы приложение не имело доступа к внутренним переменным. Тем не менее, в C ++ вы можете иметь элементы как с общими, так и с закрытыми классами.
Пройдите по ссылке. C ++ позволяет модификацию на основе ссылки, для которой требуется передача указателей. Передача по ссылке делает код очень чистым и более безопасным от опасностей указателя. Вы также передаете указатель стиля C, и это работает, но если вы находитесь в C ++, то вам лучше, если
новый и удалить против malloc и бесплатно. Операторы new () и delete () не только выделяют и освобождают память, но и позволяют коду выполняться как часть destru-er, вызываемого в цепочке. Если вы используете C ++ - на самом деле ПЛОХО использовать malloc и бесплатно.
Типы ввода-вывода и перегрузка операторов Перегрузка операторов делает код читаемым или интуитивно понятным, если все сделано хорошо. То же самое для операторов << и >> io. C способ сделать это будет использовать указатели на функции - но это грязно и только для опытных программистов.
Используя «строку». Char * из C работает везде. Так что C и C ++ почти одинаковы. Однако, если вы находитесь в C ++ - всегда намного лучше (и безопаснее) использовать классы String, которые избавляют вас от опасностей массивов при работе, которые есть почти во всех вещах.
Функции, которыми я до сих пор не поклонялся бы в C ++ 1. Шаблоны - хотя я не использую тяжелые шаблоны во многих кодах - он может оказаться очень мощным для библиотек. Этого почти нет в Си. Но в обычный день, особенно если вы математически пропускаете.
Вещи, которые мне нравятся в C и не хватает в C ++
Полиморфные алгоритмы с использованием указателей на функции. В C, когда вы запускаете сложные алгоритмы - иногда вы можете использовать набор указателей на функции. Это делает истинный полиморфизм мощным способом. Когда вы находитесь в C ++ вы МОЖЕТЕ использовать указатели на функции - но это плохо. Вы должны использовать только методы, иначе будьте готовы запутаться. Единственная форма полиморфизма в классах C ++ - это перегрузка функций и операторов, но это довольно ограничивает.
Простые темы. При создании потоков были pthreads - это довольно просто и управляемо. Это происходит, когда вам нужно создать потоки, которые должны быть «приватными» для классов (чтобы они имели доступ к закрытым членам). Существует расширенный тип фреймворков, но ничего в базовом C ++ нет.
Dipan.
источник
Определенные языковые функции, даже если они являются дополнениями, могут полностью изменить способ использования языка. В качестве одного примера рассмотрим этот случай:
Если в приведенном выше коде задействованы функции вызова, реализованные в C ++, мы можем столкнуться с целым миром проблем, поскольку любой из этих вызовов функций может выдать, и мы никогда не разблокируем мьютекс в этих исключительных путях.
Деструкторы больше не находятся в сфере удобства, чтобы помочь программистам не забыть освободить / освободить ресурсы в этот момент. RAII становится практическим требованием, потому что по-человечески невозможно предвидеть каждую отдельную строку кода, которая может привести к нетривиальным примерам (не говоря уже о том, что эти строки могут не генерироваться сейчас, но могут позже с изменениями). Возьмите другой пример:
Такой код, хотя в целом безвреден в C, подобен адскому огню, царящему хаосу в C ++, потому что
memcpy
бульдозеры разбивают биты и байты этих объектов и обходят такие вещи, как конструкторы копирования. Такие функции , такие какmemset
,realloc
,memcpy
и т.д., в то время как ежедневные инструменты среди разработчиков C привыкли смотреть на вещи в довольно однородным образом битов и байтов в памяти, не гармонируют с более сложной и более богатой системы типов C ++. C ++ поощряет гораздо более абстрактное представление пользовательских типов.Таким образом, эти типы вещей больше не позволяют C ++ любому, кто хочет правильно его использовать, смотреть на него как на «надмножество» языка C. Эти языки требуют совершенно другого мышления, дисциплины и способа мышления для наиболее эффективного использования. ,
Я не нахожусь в лагере, который считает C ++ лучше во всех отношениях, и на самом деле большинство моих любимых сторонних библиотек по какой-то причине являются библиотеками C. Я не знаю, почему именно, но C-библиотеки имеют тенденцию быть более минималистичными по своей природе (возможно, потому, что отсутствие такой богатой системы типов делает разработчиков более сосредоточенными на предоставлении минимальной требуемой функциональности без создания большого и многоуровневого набора абстракций), хотя я часто заканчиваю тем, что просто помещаю обертки C ++ вокруг них, чтобы упростить и адаптировать их использование для моих целей, но этот минималистский характер предпочтительнее для меня даже при этом. Я действительно люблю минимализм как привлекательную особенность библиотеки для тех, кто тратит дополнительное время на поиск таких качеств, и, возможно, С склонен поощрять это,
Я предпочитаю C ++ гораздо чаще, чем нет, но на самом деле мне приходится довольно часто использовать API-интерфейсы C для самой широкой двоичной совместимости (и для FFI), хотя я часто реализую их в C ++, несмотря на использование C для заголовков. Но иногда, когда вы переходите на действительно низкоуровневый уровень, например, к распределителю памяти или очень низкоуровневой структуре данных (и я уверен, что среди тех, кто занимается встроенным программированием, есть и другие примеры), иногда бывает полезно Можно предположить, что типы и данные, с которыми вы работаете, не имеют определенных функций, таких как vtables, costructors и destructors, так что мы можем рассматривать их как биты и байты для перемешивания, копирования, освобождения, перераспределения. Для особо низкоуровневых задач иногда бывает полезно работать с гораздо более простой системой типов, которую предоставляет C,
Разъяснение
Один интересный комментарий, на который я хотел бы ответить более подробно (я считаю, что комментарии здесь настолько строги по ограничению символов):
Это справедливо, но все, на чем я сконцентрировался, в основном сосредоточено на системе типов C ++, а также на RAII. Одна из причин, по которой такое рентгеновское байт-копирование
memcpy
илиqsort
типы функций представляют меньшую практическую опасность в C, заключается в том, что уничтожениеf1
иf2
выше является явным (если они даже требуют нетривиального уничтожения), тогда как когда деструкторы перемещаются в картину они становятся неявными и автоматизированными (часто с большой ценностью для разработчиков). Это даже не говоря о скрытом состоянии, таком как vptrs и т. Д., Которые такие функции могли бы разрушить прямо сейчас. Еслиf1
владеет указателями иf2
поверхностное копирование их в некотором временном контексте, тогда это не представляет проблемы, если мы не попытаемся явно освободить те, у кого есть указатели, во второй раз. С C ++ это то, что компилятор автоматически захочет сделать.И это становится еще более значительным, если обычно в C: « Если у Foo есть собственные указатели», потому что ясность, требуемая при управлении ресурсами, часто делает это чем-то более сложным, чтобы пропустить, тогда как в C ++ мы можем сделать UDT более не тривиальным конструируемый / разрушаемый, просто заставляя его хранить любую переменную-член, которая не является тривиально конструируемой / разрушаемой (опять же, как правило, очень полезно, опять же, но не в том случае, если у нас возникает искушение использовать такие функции как
memcpy
илиrealloc
)Моя главная мысль не в том, чтобы пытаться спорить о какой-либо пользе от этой явности (я бы сказал, что если таковые имеются, они почти всегда отягощены минусами повышенной вероятности человеческой ошибки, которая сопровождает их), а просто сказать, что функции как
memcpy
иmemmove
иqsort
иmemset
иrealloc
и т. д. нет места в языке с такими UDT, такими же богатыми по своим возможностям и возможностям, как C ++. Несмотря на то, что они существуют независимо, я думаю, что было бы не слишком оспаривать, чтобы сказать, что подавляющее, огромное большинство разработчиков C ++ было бы разумно избегать таких функций, как чума, тогда как в C это очень повседневные функции, и я Я утверждаю, что они создают меньше проблем в C по той простой причине, что его система типов намного более проста и, возможно, «тупее». Рентгенография типов C и обработка их как битов и байтов подвержена ошибкам. Делать это в C ++ возможно просто ошибочно, потому что такие функции борются с очень фундаментальными особенностями языка и тем, что он поощряет в системе типов.Это на самом деле самое привлекательное для меня C, тем не менее, особенно с учетом того, как оно связано с совместимостью языков. Было бы намного сложнее заставить что-то вроде FFI в C # понимать полноценную систему типов и языковые особенности C ++ вплоть до конструкторов, деструкторов, исключений, виртуальных функций, перегрузки функций / методов, перегрузки операторов, всех различных типов наследование и т. д. С C это относительно тупой язык, который стал довольно стандартным для API, так что многие различные языки могут импортировать напрямую через FFI или косвенно через некоторые функции экспорта API C в желаемой форме (например, Java Native Interface ). И именно здесь у меня больше не остается выбора, кроме как использовать C, так как эта функциональная совместимость языка является практическим требованием в нашем случае (хотя часто я
Но вы знаете, я прагматик (или, по крайней мере, я стараюсь быть). Если бы C был этим самым отвратительным и отвратительным, склонным к ошибкам языком, то некоторые из моих коллег-энтузиастов C ++ утверждали, что это так (и я бы считал себя энтузиастом C ++, за исключением того, что каким-то образом это не привело к ненависти к C с моей стороны). напротив, это оказало на меня противоположное влияние, заставив меня ценить оба языка лучше в их собственных отношениях и различиях), тогда я ожидал бы, что это проявится в реальном мире в форме некоторых из самых плохих и утечек и ненадежные продукты и библиотеки пишутся на C. И я не нахожу этого. Мне нравится Linux, мне нравится Apache, Lua, zlib, я нахожу OpenGL приемлемым для своего давнего наследия против таких меняющихся требований к оборудованию, Gimp, libpng, Cairo и т. Д. По крайней мере, все, что мешает изложить язык, похоже, не создает тупиковых ситуаций, если я пишу классные библиотеки и продукты в компетентных руках, и это действительно все, что меня интересует. Поэтому я никогда не был настолько заинтересован в самых страстных. языковые войны, если не считать прагматического обращения и сказать: «Эй, есть классные вещи! Давайте узнаем, как они это сделали, и, возможно, есть классные уроки, не настолько специфичные для идиоматической природы языка, которые мы можем вернуть на любой язык, который мы используем. " :-D
источник
memcpy(&f2, f1, sizeof f2);
это также «хаос, правящий адским огнем» в C, еслиFoo
есть какие-либо собственные указатели, или еще хуже, так как вам также не хватает инструментов, чтобы справиться с этим. Таким образом, люди, пишущие на С, не делают таких вещейFoo
экземпляра теперь могут захотеть уничтожить динамический массив, или вектор, или что-то с этой целью. Я часто нахожу в некоторых специфических случаях, что полезно иметь возможность писать определенные структуры данных, опираясь на тот факт, что уничтожение явное, а не неявное.Foo
него есть какие-либо собственные указатели, мы могли бы дать ему правильный ctor, dtor, семантику использования значений и т. Д., И иметь гораздо более богатый и безопасный код. Но иногда я обнаруживаю, что достигаю C в тех случаях, когда я хочу обобщить структуру данных или распределитель на однородном уровне битов и байтов, с некоторыми допущениями, которые я могу сделать для типов, которые, как правило, в их узких случаях упрощаются немного из-за таких предположений я чувствую себя более уверенно делать в C.API void filter_image(byte* pixels, int w, int h);
в простом примере, а не какAPI void filter_image(ImageInterface& img);
(который связывает наш код с таким интерфейсом изображений, сужение его применимости). В таких случаях я иногда просто реализую такие функции в C, поскольку в C ++ мало что можно получить, и это снижает вероятность того, что такой код потребует будущих изменений.