C: Хорошие привычки в отношении перехода на C++

Я изучаю C в Varsity всего два месяца, а в следующем году мы перейдем на C++.

Есть ли какие-то привычки, которые я должен приобрести при программировании на C, которые помогут перейти на C++ в будущем, или лучше думать о них отдельно?

Когда вы выучили C, а затем C++, изменился ли способ написания кода на C?


person Ande Turner    schedule 14.09.2009    source источник
comment
На Coursera есть курс «C++ для программистов на C». Видео можно посмотреть в превью курса. coursera.org/course/cplusplus4c   -  person Nikhil    schedule 01.04.2014


Ответы (13)


Уже есть много хороших ответов. Моя будет больше ориентирована на мышление.

Данные против действий!

  • В C все сделано так, чтобы думать, как применить этот эффект к этим данным.
  • В C++ это больше похоже на поведение Data.

В то время как поведение данных может быть выполнено в C (и это сделано!), в C++ все необходимое для простой реализации этого уже доступно: инкапсуляция, конструкторы, переопределение перегрузки, шаблоны и т. д..

Я обнаружил, что эта идея "Данные должны вести себя" является очень хорошим руководящим принципом при написании кода на C++.

Синтаксический сахар С++ не является обязательным

Вы найдете множество функций C++, которые можно реализовать на C, и некоторые люди используют это как предлог, чтобы не изучать их. Такое мышление опасно (это часть относиться к C++ как к новому языку, а не как к расширению, которую можно увидеть в некоторых сообщениях).

Побочным эффектом отказа от написания C++ способом C++ является то, что, хотя разработчик C++ должен понимать код C++, он/она не должен понимать вашу маленькую личную структуру, имитирующую сахар C++ с функциями только C. На самом деле его не заинтересует ваш фреймворк. По правде говоря, он/она почувствует к вам только жалость/презрение, потому что вы потеряли драгоценное время на это. В конце концов, он/она возненавидит вас, если ему/ей придется использовать ваш фреймворк вместо сахара C++.

Руководящие принципы, подобные тому, что я могу сделать это в стиле C, просто заставят вас упустить фургон. Лучше вообще не начинать изучать C++, если у вас уже есть такой C-ориентированный образ мышления.

Выбранный вами язык никогда не бывает лучшим. ВЫ должны стать лучшими. Если вы пишете код на С++, то пишите его так же, как на С++.

C-совместимый код C++ является семантической ошибкой

Типизация ваших структур, чтобы сделать их компилируемыми компилятором C, - плохая шутка. Использование указателей вместо ссылок — это пощечина самому себе в будущем. extern "C" только сделает ваш код слабее, а не сильнее. А использование void * для универсальности только увеличит число коллег-программистов на C++, которые с радостью заплатят за то, чтобы вам отрубили голову невероятно болезненным способом.

Никогда не пытайтесь писать C-совместимый код, если вам это действительно действительно не нужно.

Вы просто отягощаете себя трудоемким стилем написания кода для функции, которую никогда не будете использовать.

Компилятор — могущественный друг/враг

Работа на низком уровне оказывает странное влияние на некоторых разработчиков. Они очень верят в свой контроль над скомпилированным кодом. Для них сложно делегировать этот контроль конструкциям более высокого уровня.

Хорошим примером этого является отказ от шаблона конструктор/деструктор, потому что иногда конструкторы занимают слишком много времени... Лучше сделать это по-моему....

Компилятор C++ вполне способен оптимизировать явно неоптимизированный код. На самом деле код, созданный компилятором, может сильно отличаться от того, который, по вашему мнению, был создан вами.

Не пытайтесь быть лучше/умнее компилятора, потому что:

  1. Вы, вероятно, уже проиграли битву, поскольку даже старые компиляторы обычно производят лучший код, чем вы можете мечтать сегодня.
  2. Даже если сегодня вы выиграли битву, завтра она автоматически обернется поражением, поскольку в будущем компиляторы будут становиться все лучше и лучше, поэтому ваш сегодняшний оптимизированный код станет узким местом программы и предметом рефакторинга в ближайшие годы (не говоря уже о позорные воспоминания для вас).

Так что доверяйте своему компилятору.

Не управляйте созданием своего кода на микроуровне. Делайте свою работу, а компилятор сделает свою.

Обратите внимание, что этот момент не следует использовать для оправдания создания медленного/неэффективного кода. Если преждевременная оптимизация является корнем всех зол, вы все равно должны использовать свои знания языка и компилятора для создания хорошего и эффективного кода (см. следующий пункт).

Знайте преимущества/недостатки/затраты каждой конструкции C++

Например, тот факт, что виртуальные методы добавляют одну косвенность к вызову функции, означает, что для некоторых людей производительность резко снизится. Правда в том, что проблемы с производительностью часто возникают в другом месте.

Невежество не является оправданием.

Знайте код, созданный для каждой конструкции C++ (т. е. встраивание, ссылки, конструктор, деструктор, исключение, перегрузка функции, переопределение функции, шаблон, виртуальная функция и т. д.). Знайте, что будет оптимизировано, а что нет.

Таким образом, вы не только не будете платить за то, что вам не нужно (это руководящий принцип C++), но и получите прибыль от того, что вам ничего не стоит, но приносит много.

Быть скромным

Есть люди, занимающиеся исследованиями в области C++, которые в день своего рождения владели C++ лучше, чем большинство из нас когда-либо сможет. Даже если мы проигнорируем Stroustrup, такие имена, как Мейерс, Абрахамс, Александреску, Sutter и т. д. регулярно появляются вместе с новыми идеями. Несмотря на (или вследствие) свой чужой внешний вид, STL является революционной библиотекой. И такая библиотека, как Boost, несмотря на ее небольшой размер по сравнению с некоторыми полными платформами (такими как API Java или .NET), представляет собой огромный репозиторий превосходного кода, предлагаемого вам для изучения.

Просто потому, что вы находите какую-то новую функцию странной или чуждой, не стоит недооценивать ее. Попытка понять это, ВОЗМОЖНО, даст вам еще один инструмент в вашем распоряжении, и ВСЕГДА улучшит ваше мастерство языка, и ВСЕГДА заставит ваш мозг работать, что хорошо в бизнесе разработки.

Большинство моих знакомых, которым не удалось перейти на C++, просто решили, что та или иная функция бесполезна, потому что не удосужились ее понять.

RAII !!!!

Если вы не знаете, что это такое, изучите это.

Без RAII ваш код на C++ — это просто код с ошибками, который позволяет избежать ошибки компиляции.

RAII — это самое важное понятие C++.

Все остальное связано.

person paercebal    schedule 14.09.2009
comment
Несколько вещей, чтобы добавить к этому превосходному ответу. Используйте STL с первого дня — не думайте об этом как о чем-то умном, когда вы станете экспертом. Прежде чем что-то придумывать загляните в буст. - person Martin Beckett; 16.09.2009
comment
Чтобы завершить ответ мгб: для вашего производственного кода используйте STL. Код STL на 99% ВСЕГДА будет лучше вашего собственного. Теперь хорошее упражнение в свободное время - создать свои собственные классы и сравнить результат с STL, как по интерфейсу, реализации, так и по производительности. - person paercebal; 16.09.2009
comment
и правильность. Достаточно легко создать замену STL, которая, кажется, работает хорошо. Но он почти наверняка будет иметь тонкие ошибки, связанные с безопасностью исключений, утечками ресурсов или опорой на неопределенное поведение. - person jalf; 17.09.2009
comment
Одним из редких оправданий для отказа от использования STL является использование вместо этого основной библиотеки Qt (если вы все равно используете Qt, например, для графического интерфейса, параллельных вещей или чего-то еще). - person mbx; 04.07.2013
comment
@paercebal: Замечательный ответ, я хотел бы проголосовать за этот ответ еще в 10 раз больше. Мне нравится этот ответ. в любом случае, объясните, пожалуйста, смысл этой цитаты, которую вы написали в своем профиле. Если бы ключевого слова class было достаточно, чтобы квалифицироваться как объектно-ориентированное программирование, Джеймс Бонд был бы компилятором Java. Мне любопытно узнать, что означает приведенная выше цитата. - person Destructor; 23.02.2016
comment
Как ни странно, в FAQ от парня, разработавшего C++, говорится, что совершенно нормально изучать C++ по частям. Думаю, он ничего не знает. - person Barleyman; 29.09.2017
comment
Я большой поклонник того, что вы вообще не должны/не можете учиться, в частности, с мышлением Х. - person Barleyman; 29.09.2017

Лучший совет, вероятно, состоит в том, чтобы рассматривать их как совершенно отдельные языки. Да, большая часть кода C может быть скомпилирована компилятором C++, но обычно это не лучший способ.

C — очень низкоуровневый хакерский язык. Что вы видите, то и получаете. У него есть указатели и структуры, поэтому вы используете указатели и структуры. У него очень низкая безопасность типов, поэтому вы максимально игнорируете безопасность типов.

C++, с другой стороны, допускает огромное количество абстракций. Вместо указателей обычно лучше использовать итераторы, которые концептуально ведут себя как указатели, но таковыми не являются (или могут не быть).

Вместо того, чтобы выбрасывать информацию о типе (например, если функции принимают значение void*, чтобы они могли работать с любым типом указателя), вы можете использовать шаблоны, чтобы сохранить безопасность типов и по-прежнему иметь возможность повторно использовать одно и то же определение одной функции.

И вам предоставляется превосходная стандартная библиотека, которая позволяет вам выражать сложные алгоритмы в терминах простых предопределенных строительных блоков.

C++ — мультипарадигмальный язык. В некоторых ответах здесь говорится, что С++ является объектно-ориентированным, что частично верно. Да, в нем есть поддержка объектно-ориентированного кода, но это не то, что C++.

C++ также поддерживает универсальное программирование, которое часто предпочтительнее ООП. Он также имеет ограниченную поддержку функционального программирования. И, конечно же, он по-прежнему поддерживает процедурное программирование в стиле C. Хитрость в C++ заключается в том, чтобы понять все это, чтобы знать, что и когда использовать. В этом сила C++, способность переключаться между всеми этими парадигмами и смешивать их. Люди, которые называют C++ языком ООП, упускают из виду не меньше, чем люди, называющие его улучшенным C. Он позволяет вам писать код в любом из этих стилей, но ни один из них сам по себе не стоит. C — лучший C-подобный язык, и есть много лучших языков ООП. Если вы хотите придерживаться одной единственной парадигмы, используйте язык, предназначенный для этого.

person jalf    schedule 14.09.2009
comment
Спасибо за самый вдохновляющий ответ. - person Liran Orevi; 14.09.2009

Забавно, как много людей здесь утверждают, что C и C++ «совершенно разные», и как «C++ объектно-ориентирован, а C нет»...

Прежде всего: C++ изначально разрабатывался как расширение языка C. На самом деле стандартная документация C++ ссылается на стандарт C. Это правда, что многие вещи в C++ выполняются по-другому, чем в C, но утверждать, что они полностью не связаны, — это слишком далеко. Хороший код на C можно скомпилировать с помощью компилятора C++, и для некоторых тривиальных проблем решения C и C++ могут выглядеть почти одинаково.

Во-вторых, не дайте себя обмануть, полагая, что C++ — это «объектно-ориентированный язык». C++ — это язык, поддерживающий объектную ориентацию, правда. Но он также поддерживает общее программирование и процедурное программирование. Сосредоточение внимания только на аспекте ООП C++ лишает большую часть его возможностей.

Что касается привычек... не слишком привязывайтесь к строкам в стиле C (char *) и массивам (int foo[]). Оба очень редко используются в C++, так как есть гораздо более мощные (и удобные) замены, string и vector.

Обратите особое внимание на указатели и динамическое выделение памяти. Хотя в хорошем коде на C++ их очень мало, вы должны знать, как они работают. При этом вы также поймете, почему хороший код C++ инкапсулирует их или заменяет ссылками, поэтому они не часто появляются в коде производственного качества.

При разработке кода C начните с struct, содержащего соответствующие данные (например, поля адреса), а затем создайте функции, работающие с этим типом структуры (address_read( struct address_t * ), address_write( struct address_t * ), address_modify_name( struct address_t *, char * ) и т. д.). Добавьте функцию main(), которая вызывает эти функции в соответствующем порядке последней. Данные являются важной частью программы, а не функции. Это то, что облегчит переход к C++ (и объектной ориентации).

Есть еще, но я не претендую на то, что отвечаю на все в одном посте SO. :-)

person DevSolar    schedule 14.09.2009
comment
Хороший код C не сможет быть скомпилирован строгим компилятором C++. См. stackoverflow.com/q/605845/4961259. - person Kami Kaze; 23.10.2018
comment
@KamiKaze: Как и все практические правила: сначала изучите и прислушайтесь к практическому правилу. Затем изучите исключения. Но я признаю, что девять лет назад я знал о мелком шрифте обоих языков меньше, чем сейчас. - person DevSolar; 23.10.2018
comment
То же самое, наверное, у всех. Может быть, вы могли бы дать немного больше информации о вашем развитии 9 в этом посте ^^. Я бы с удовольствием прочитал ее, потому что мой C++ — это в основном то, что я знаю из C, плюс то, что я узнаю, читая здесь. То, что я знаю, что malloc нуждается в другом синтаксисе, — это практически все, что я могу сделать. - person Kami Kaze; 23.10.2018
comment
@KamiKaze: Самое важное, что я понял, это то, что очень плохая идея сначала изучать C, потому что практически все, что вы узнали и сделали в C, хотя и возможно в C++, должно там по другому сделать. (Контейнеры, алгоритмы, ссылки, диапазон для, интеллектуальные указатели, ...) Я подумал о написании учебника по С++ сверху вниз и сделал бы это вместо того, чтобы редактировать какой-то ответ десятилетней давности. на SO ... но жизнь такая, какая она есть, и я действительно не вижу, чтобы у меня было свободное время для этого (среди других проектов, связанных с C / C ++, которые у меня есть). Прости. ;-) - person DevSolar; 23.10.2018

Если вы можете получить его, я бы порекомендовал первые 3 главы Язык программирования C++ от создателя C++ Бьерна Страуструпа.

В частности, "Примечания для читателя" и "Тур по C++" дадут вам хорошее представление о том, чем/чем C++ отличается от C, и сфокусируют ваше дальнейшее изучение. Конечно, всю книгу полезно иметь под рукой при работе с C++.

Что интересно для вашей ситуации, в главе 1 Бьярне на самом деле говорит

«в продолжающихся дебатах о том, нужно ли изучать C перед C++, я твердо убежден, что лучше сразу перейти к C++».

Конечно, он бы согласился, не так ли, но если вы согласны с его рассуждениями, вам лучше сразу перейти к C++ как можно скорее.

person Ash    schedule 14.09.2009
comment
@Ash: Это обязательный текст для курсов C++ в моем университете, я получу его, когда позволят средства. :) - person Ande Turner; 14.09.2009
comment
Если вы хотите изучить C++ в долгосрочной перспективе, вам не нужно сначала изучать C, это правда. Но изучать ли C или C++ — это другой вопрос. - person Kami Kaze; 23.10.2018

Держите языки отдельно.

C и C++ могут показаться похожими, но это разные языки с разными правилами для подобных конструкций. Если вы можете изолировать одно от другого, тем лучше.

При переходе на C++ будьте готовы разучиться (выучить другой, несовместимый метод) о:

  1. препроцессор: в C++ не следует использовать препроцессор так часто, как в C.
  2. строки: в C их нет
  3. указатели: C++ можно закодировать, чтобы обрабатывать их более безопасно.
person pmg    schedule 14.09.2009

Вы переходите на C++ означает, что вам нужны классы или лучшие библиотеки. Вот что я чувствую. Я также изучаю лучшие возможности C++, имея опыт работы с C. До сих пор я рассматривал в основном векторы [помимо классов и шаблонов].

Я чувствую, что языки слишком похожи на

думать о них совершенно отдельно.

person Lazer    schedule 14.09.2009

Я предполагаю, что C++, который вы будете изучать, вероятно, не будет чрезмерно объектно-ориентированным, по крайней мере, так не было в моем университете. Мы запускали программы на C++ по существу как программы на C.

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

Ваша обработка файлового ввода-вывода также будет отличаться... вместо fstream прочитайте синтаксис реализации функций iostream.

Поищите в Интернете руководства по простым программам на C++... CodeProject — всегда хороший ресурс.

person the_e    schedule 14.09.2009
comment
@espasis: C ++ используется для обучения ООП, странно, что преподавание ООП как предмета оставлено до 3-го года, а мы используем Java в течение первых 18 месяцев. :с - person Ande Turner; 14.09.2009
comment
Я один из немногих в моем университете, кто понимает, как кодировать C/C++ без ООП. Старые лекторы C могут, но некоторые новые лекторы и большинство студентов понятия не имеют, как кодировать в стиле C, а не в стиле C++. - person ewanm89; 14.09.2009

Программы на С++ совершенно разные. лучше потратить время на изучение C++, чем работать над элементами C, пытаясь улучшить их для C++.

Например, даже простая программа «Hello World» значительно отличается:

C:

#include <stdio.h>
int main(void)
{
  printf("Hello, world!\n");
  return 0;
}

C++:

#include <iostream>
int main()
{
   std::cout << "Hello, world!\n";
}

(Примеры из здесь).

Поскольку «printf» — это функция, тогда как «cout» — это не функция, а экземпляр класса ostream.

Дополнительная литература: iostream.

person Liran Orevi    schedule 14.09.2009
comment
Правильно, я голосую за изменение названия C++ на k++: C отличается от C++, у него нет ничего общего, кроме буквы. - person Clement Herreman; 14.09.2009
comment
достижение конца main() вернет 0 в C99, поэтому на одну разницу меньше - person Christoph; 14.09.2009
comment
первая часть приведенного кода на 100% валидна c++: ‹ewanm89@enterprise› ~ % g++ hello.cpp [0] ‹ewanm89@enterprise› ~ % ./a.out [0] Привет, мир! ‹ewanm89@enterprise› ~ % cat hello.cpp [0] #include ‹stdio.h› int main(void) { printf(Hello, world!\n); вернуть 0; } - person ewanm89; 14.09.2009
comment
Я согласен с текстом ответа, но это не очень хороший пример. Это просто показывает, что printf заменен на cout, и он находится в другом заголовке. Это само по себе не показывает, что программы на C++ совершенно разные. - person jalf; 14.09.2009
comment
Возврат обрабатывается одинаково, c99 возвращает 0 в конце функции, обычно рекомендуется включать cstdio, а не stdio.h (хотя в конце дня он идентичен). На самом деле единственная разница во втором заключается в том, что вы используете объектно-ориентированную библиотеку iostream lib для вывода консоли. И это удваивает размер как ассемблерного кода, так и конечного бинарника с таким тривиальным фрагментом кода. - person ewanm89; 14.09.2009
comment
Я мог бы начать перечислять asm ;) - person ewanm89; 14.09.2009
comment
большая часть версии C++ такого тривиального фрагмента кода является мусором инициализации уровня объектной ориентации. - person ewanm89; 14.09.2009
comment
@jalf, вы правы, это не полностью иллюстрирует разницу. Как вы умно выразились, C ++ огромен, может быть, этого небольшого примера достаточно, чтобы дать среднему новичку ощущение, что C ++ не то же самое, что C, и будет предложить открыть книгу для более сложных примеров. (Кроме того, в нем немного рассказывается о классах, пространствах имен и операторе ‹‹, но есть еще многое другое...) - person Liran Orevi; 14.09.2009

Максимально используйте структуры и указатели функций, чтобы имитировать методы классов и абстрактные методы.

Например, если вы хотите определить транспортное средство и автомобиль, производный от транспортного средства, используя C, вы должны написать (извините, я не буду проверять код :-)):

struct Vehicle
  {
  void (*checkFuel)(Vehicle*);
  void (*start)(Vehicle*);
  void (*move)(Vehicle*);
  void (*stop)(Vehicle*);
  }

void start1(Vehicle* v)
  {
  v->checkFuel(v);
  printf("START!");
  }

void start2(Vehicle* v)
  {
  v->checkFuel(v);
  printf("VROOOOMM!");
  }


struct Car
  {
  Vehicule base;
  int (*klaxon)(Car*);
  }

Vehicule* newVehicule()
 {
 Vehicule* v=(Vehicule*)malloc(sizeof(Vehicule));
 v->start= start1;
 v->move=
 (...)
 return v;
 }


Car* newCar()
 {
 Car* c=(Car*)malloc(sizeof(Car));
 Vehicule* v=(Vehicule*)c;
 v->start= start2;
 v->move=
 (...)
 c->kaxon=(...)
 return c;
 }
person Pierre    schedule 14.09.2009
comment
Чтобы использовать функции базовой структуры, это будет Car* c = ...; c-›base.function ? - person Ande Turner; 14.09.2009
comment
Так как Vehicule является первым элементом Car, вы можете безопасно применить его к Vehicule*. Автомобиль* c=(...); ((Автомобиль*)c)->start((Автомобиль*)c); - person Pierre; 14.09.2009

Вот некоторые моменты:

1) Убедитесь, что вы владеете указателями. Сосредоточьтесь на том, как работают массивы и указатели, в чем сходство и различие между ними.

2) Лучший способ усовершенствовать Си — писать программы. Напишите столько, сколько сможете. Для начала вы можете написать собственные функции для некоторых библиотечных функций. Вы можете попробовать свои силы в Strcpy, strcmp, strncpy, memcpy, memmove.

3) Научитесь отлаживать (GDB действительно крут).

4) Начните следовать определенному стилю кодирования и старайтесь придерживаться его.

5) Всегда снабжайте свой код осмысленными комментариями.

person Duleb    schedule 14.09.2009
comment
До следующего года еще далеко. Не беспокойтесь о С++. Я бы посоветовал просто сосредоточиться на навыках c и способности к логическому мышлению. - person Duleb; 14.09.2009
comment
Если gdb действительно крут, то что такое отладчик MSVC? Супер классный? Как минимум. :-Д - person KiNgMaR; 14.09.2009
comment
Указатели? В C++ они менее проблематичны, чем в C. Чем полезен этот совет для тех, кто переходит с C на C++? - person jalf; 14.09.2009
comment
В следующем году он перейдет на c++, а до этого, как я уже говорил, еще далеко. В настоящее время он должен просто сосредоточиться на C. Я твердо верю, что вы не знаете указателей, вы не знаете C. - person Duleb; 14.09.2009

С++ объектно-ориентирован, а С нет. Так что общие вещи, такие как поддержание чистоты кода указателя и комментарии к функциям/методам, и понимание того, как не получить бесконечные циклы препроцессора с помощью #IFDEF.

Тем не менее, объектно-ориентированный подход часто может быть лучше, когда код думает об объектах. Поэтому вам нужно подумать о разнице новых функций.

person ewanm89    schedule 14.09.2009

Стиль программирования на C и C++ совершенно разный. C++ — это объектно-ориентированное программирование, а C — процедурно-ориентированное программирование. Программирование на C++ лучше всего подходит для моделирования реальных проблем с использованием классов/объектов. Но базовые понятия, такие как указатели, структуры, операторы, операторы приведения, обработка данных, одинаковы в обоих случаях. вы учитесь на 'C'

person Red    schedule 14.09.2009

Указатели функций. Google первое попадание.

person kenny    schedule 14.09.2009
comment
Что такого особенного в указателях на функции? Он не хочет использовать «класс» в C? - person Naveen; 14.09.2009
comment
Указатели на функции менее полезны в C++, чем в C, просто потому, что существует ряд проблем, решением которых в C могут быть указатели на функции, тогда как в C++ есть другие возможности языка, которые могут предоставить альтернативное решение. На ум приходят функции virtual и классы функторов. При переходе с C на C++ я бы не рекомендовал уделять больше внимания указателям на функции. - person CB Bailey; 14.09.2009
comment
Да, @Naveen, это моя точка зрения. Зная их и откуда они пришли. - person kenny; 14.09.2009
comment
Почему указатели на функции важны для тех, кто уже знает C и хочет изучить C++? - person jalf; 14.09.2009
comment
@jalf, я был бы удивлен, если бы кто-то, кто использует C в течение 2 месяцев, твердо придерживался указателей на функции. - person kenny; 14.09.2009