6 етапів на шляху до С++ інженера. Основні теми та нюанси

💡 Усі статті, обговорення, новини для початківців — в одному місці. Приєднуйтесь до Junior спільноти!

Привіт! Мене звати Єгор Великожон, я працюю Software Engineer у SoftServe близько 2 років і приблизно стільки ж програмую на С++. Від знайомих та колег часто чув питання — як почати програмувати на С++? І кожен раз раджу подумати, для чого вам С++.

Так, «плюси» хороша перша мова через те, що використовує багато механік, зав’язаних на операційних системах, і є низькорівневою. Але цей бонус потребує додаткових зусиль. Як людина, що вибрала С++ першою мовою і зараз з нею працює, можу виділити декілька причин для обрання цього шляху:

  1. Знаючи С++, набагато легше вивчити будь-яку іншу мову програмування.
  2. Глибоке розуміння пам’яті комп’ютера.
  3. Глибоке розуміння структур даних.
  4. Можливість перейти як до інших низькорівневих мов, так і до високорівневих.

Якщо ви розібралися зі своєю мотивацією, то почнімо заглиблюватися в основи. У статті ми розберемося, які перші кроки та теми необхідні для вивчення С++.

Окей, вважатимемо, що ви вже обрали С++. Що далі?

Для початку потрібно налаштувати своє оточення. Найпростіший варіант — використання Visual Studio на Windows. У такому випадку ви уникнете проблем з налаштуванням проєкту через Makefile або CMake під час роботи на POSIX системах. Але фактично код можна писати на будь-якій платформі, просто у кожної своя специфіка. Гайд для подібного ви можете знайти інтернеті — їх купа як текстових, так і відеоінструкцій.

Добре, найскладніший крок — почати щось робити — ви вже виконали, тепер залишилися дрібниці — все інше. Моя основна порада — не орієнтуйтеся тільки на один гайд/ курс, а шукайте інформацію всюди. У цій статті я розповідатиму про основні теми, що необхідно знати та розуміти. Ваша ж мета — для кожної з них знаходити інформацію, статті тощо, а потім — експериментувати. Лише через власний досвід знання відкладуться у довгострокову пам’ять.

І невелика нотатка особисто від мене — будь-який код, який напишете, це чітка інструкція для машини, і вона послідовно виконуватиме її. Ніякої магії тут немає, все відбувається за описаним в програмі порядком. Якщо у вас щось не працює, не варто будувати здогадки: просто сядьте і послідовно, рядок за рядком, у голові продумайте, що саме БУДЕ (а не «повинно» бути) виконано. Це допоможе уникнути втрати часу.

Етап 1. Основні концепції мови

Змінні та типи даних

Це перша і, ймовірно, основна тема. Для зручності почнемо зі змінною. Фактично, це просто певна ділянка пам’яті, куди ми записуємо певне значення. Звучить досить просто, чи не так? Тоді час для прикладу:

Я хочу покласти 1 залізну монетку і 1 дерево.

Погодьтеся, класти ці 2 речі в одне місце виглядає не дуже ефективно — вони не тільки різних розмірів, але навіть спосіб їхнього застосування дуже різний. Це — один з багатьох прикладів опису «тип даних». У нього багато різних визначень, але мені дуже подобається таке: «Тип даних — це множина значень та операцій з ними». Якщо вам стало зрозуміло — можете пропустити пояснення.

Припустимо, що тип даних монети — це «гроші». У такому разі, «множина значень» — це всі значення, які підходять «грошам». Тобто, це числові значення. Дивно звучить «горила» грошей, так? Аналогічно з «операції з ними». Не можна «налити» гроші, правда?

Закінчуємо ліричний відступ і повертаємося до С++. Як я казав вище, змінні — ділянка пам’яті, куди можна зберегти значення. Її розмір дуже залежить від самого типу, але має бути достатнім, що умістити релевантні значення. Та й рідко бувають ситуації, коли вам в одну й ту саму ділянку потрібно класти зовсім різні речі. Це лише кілька з багатьох причин, чому в С++ види змінних важливі для ефективної роботи.

Які типи даних є

Дані можуть бути:

  • цілі;
  • з плаваючою точкою;
  • символьні;
  • булівські;
  • поінтери (pointer).

Це базовий список того, що буде далі описано, але їх набагато більше. Про інші ви дізнаєтесь самі під час вивчення синтаксису.

Важливо розуміти, що у кожного типу даних є свої особливості використання.

Наприклад, цілочисленні. Вони діляться на знакові (тобто можу мати негативні значення — ’-1′ як приклад) та беззнакові. Якщо ви розумієте, що ваша змінна не зможе отримати негативне значення, то чи варто використовувати знакові типи даних?

Як для новачка, вам достатньо зрозуміти різницю між різними типами цього виду. Наприклад, чим відрізняється int та long

Числа з плаваючою крапкою — тут трохи складніше, просто враховуйте, що 0.22, найімовірніше, не дорівнюватиме 0.22 під час їхнього порівняння. Швидше за все, про це буде написано у вашому гайді, але про всяк випадок, нехай буде і тут.

Символьні — хоча вони і використовуються, щоб зберігати літері, врахуйте, що кожен символ має числове уявлення (ASCII кодування). Тип char у С++ може зберігати лише 1 символ, а ʼ (одинарна лапка) та ’’ (подвійні лапки) відрізняються — перше використовується для одного символу, друге — для цілої послідовності. Цей тип дещо особливий — зазвичай він використовується, щоб зберігати «слова», тобто набір символів. Для цього використовується масив «чарів» (array of chars), але ця тема потребує деякого розуміння поінтерів, тому про неї я говорити не буду — гайди вам допоможуть краще.

Моя порада — не забувайте візуалізувати у пам’яті вашої програми такі «слова», чи то за допомогою малюнків, чи то у голові.

Булівські — змінна, що має 2 стани, true або false, а якщо уявити це у форматі числа — 0 це брехня (false), все інше — правда (true).

Поінтери — особливість С++ (та С). Її ціль — зберігати адресу іншої змінної. Її синтаксис, як вона працює, особливості створювання — досить складні теми, на які важливо виділити достатньо часу, оскільки дуже багато інших механізмів у С++ працюють за допомогою цього типу.

Для кращого розуміння цього типу можна лише порадити більше з ним працювати. Але пам’ятайте, що при роботі з поінтерами ви працюєте з пам’яттю, а не зі значеннями, доки не використаєте оператори «*» чи «->».

І фінальна порада — не варто витрачати занадто багато часу на вивчення тільки цієї теми, просто сформулюйте для себе основну різницю між різними типами даних, пограйтесь з максимальними-мінімальними значеннями та спробуйте придумати, де у вашому повсякденному житті який тип даних більш застосовний. Вже при вивченні операторів, вбудованих функцій та іншого ви зможете детальніше зрозуміти різницю.

Етап 2. Оператори

Так, а от і наступна тема. Оператори. Що це таке? Фактично, це якась операція або, для простоти, — дія, яка використовує навколишні змінні як операнди (те, що використовує операція, тобто учасник «дії»).

Здається складно, але насправді дуже прозаїчна тема.

Найпростіший приклад — оператор присвоєння «=». «int a = 5 + 5» — тут ми створюємо змінну «а» і записуємо в неї значення, що має бути підрахованим.

Фактично, першим буде виконано підрахунок оператора «+», у якого дві «5» є операндами. А далі це значення буде призначено у змінну «а».

Новий приклад:

int a;

a = 5;

Ось тут вже використовується оператор присвоєння з операндами «а» та «5». Фактично він бере значення правого операнда і зберігає в змінну, написану зліва.

Приємного пошуку гайдів, що можу сказати.

І ще одна невелика порада — фактично, багато операторів схожі на математичні (*, /, =, >, <= і т.д.), так що, ваша мета — підтвердити для себе, що вони роблять і зрозуміти, у якого оператора який пріоритет. Зазвичай у гайдах буде таблиця, але якщо що — ось тут є зручні приклади.

Етап 3. Вбудовані функції

Це найсмачніша частина для новачка. Фактично перший складний челендж. Гайди, гайди та знову гайди. Не зрозуміли, як працює цикл for? Варто спробувати інші лекції, матеріали або взагалі переглянути відео. Ключова мета — розуміти синтаксис, ціль використання та вміння поєднувати кілька функцій.

Сподіваюся, на цей момент ви знаєте, що таке цикл while і if.

Класичний приклад.

Завдання просте — просити користувача вводити число, доки він не введе число 13.

Якщо не використовувати цикл, вам доведеться написати наступний код:

int user_input = 0; 
std::cin >> user_input; 
if (user_input == 13) 
return 0;    // end of program 

І цей шматок коду має повторюватися так багато разів, поки вам не набридне копіювати та вставляти його. І тоді, якщо користувач не надто наполегливий, у вас вийде створити в нього відчуття «нескінченності спроб». Звучить як маячня, правильно?

Окей, тут ви згадали, що «мета використання» циклів — декілька разів повторити ті самі дії (інструкції), доки умова не перестане бути правдивою (умова != true)

Швидко переписали код, вийшло дуже лаконічно:

int user_input = 0; 
while ( user_input != 13 ) 
{ 
std::cin >> user_input; 
} 
return 0; 

Тобто, при вивченні цієї теми, ви повинні намагатися зрозуміти «а навіщо взагалі ця штука потрібна, га?» та довести її корисність самому собі.

Моя порада — як зрозумієте суть вбудованої функції, спробуйте застосувати її в реальності.

На прикладі цих трьох тем я спробував показати, як саме ви повинні підходити до вивчення будь-якої з тем — не тільки читати інструкції, повторювати їх у коді, а потім переходити далі, а саме досліджувати. А що, як зробити так? А як мені зламати те, що я вже написав? А чи є у реальному житті щось схоже?

Далі я коротко опишу теми та мінімальні речі, що вам необхідно зрозуміти. Але не варто зупинятися на цьому — подробиць завжди в рази більше, ніж описано в будь-якому гайді. Отже, відтепер ви дослідник.

Етап 4. Додаткові нюанси

Далі перераховані теми і на що звертати увагу в першу чергу.

(Опціонально) Константи. У чому на відміну від звичайних змінних і покажчиків.

Масиви фіксованого розміру. Як у пам’яті, чому їм потрібні поінтери.

Динамічна пам’ять. Не забувайте, що її потрібно видаляти. Тут важливі експерименти — що буде, якщо видалити виділену пам’ять, а потім щось призначити туди? А що, якщо навпаки, не виділити пам’яті для вказівника, але спробувати щось записати?

(Опціонально) Час життя. Глобальні та локальні змінні, скільки живуть і коли вмирають.

Опції. Навіщо використовувати поінтери чи посилання як параметри, який час життя змінних (у функціях, статичні змінні, оголошені у них тощо), навіщо їх взагалі використовувати.

Кілька файлів для коду. Для чого код необхідно розділяти? Навіщо використовувати #pragma once? А як працюють глобальні змінні у такому разі?

(Опціонально) Одиниці трансляції. Просто розуміння, як формуються файли.

Область видимості. Спробуйте розділити на namespaces свій раніше написаний і поділений на файли код, що з цього вийде?

Етап 5. ООП

До цього моменту швидше за все базові елементи С++ та їх особливості ви вже зрозуміли чи спробували, час переходити до ООП. Важлива ремарка: у статті немає пояснення ООП, лише структури даних С++. Якщо хочете краще зрозуміти цей підхід — пошукайте додаткову інформацію.

Структура. Що це взагалі таке і навіщо воно потрібне? Тут треба розібратися саме з тим, що це певний саме вами тип даних, а, значить, ви створюватимете об’єкти цього типу даних і потім вже використовувати їх. Так само як оголошувати атрибути та як їх використовувати.

Класи. Дуже велика тема. Ключова відмінність від попереднього етапу — тут важливо зрозуміти механізми та фічі, що надає С++. Далі йдуть теми, що розкривають суть цієї.

Конструктори та деструктори. Коли викликаються, що мають робити які проблеми з ними можуть бути. Які види конструкторів бувають.

Модифікатори доступу. Навіщо це взагалі потрібно. (Так, тут уже входить поняття наслідування, але про нього трохи пізніше).

Методи: статичні, константні та інші. Важливо розуміти, що для чого використовується, як викликати, що таке this та інше.

Спадкування. Особливості використання модифікаторів доступу, порядок виклику конструктора-деструктора, віртуальні методи, ромбоподібна проблема та її вирішення.

Крім синтаксису, вам необхідно зрозуміти нащо це все загалі. Спробуйте зрозуміти принцип SOLID та погратись з патерами дизайну, але ця тема може бути ще досить складною, тому перейти до STL-бібліотеки теж непогане рішення.

Етап 6. Що далі

І ось тут настає питання — а що далі? І це складне питання. Правильна відповідь одна — все, але не відразу. Отже, вивчати вам ще дуже багато всього, але, ймовірно, на цьому етапі можна вже задуматися про спробу потрапити на якийсь курс/ стажування від компанії. Кожна подальша тема дійсно потребує окремої статті, так що будьте готові шукати інформацію самостійно.

Робота з кодом. Це улюблена тема на співбесідах. Вам необхідно зрозуміти, які етапи проходить вами написаний код від моменту початку компіляції до запуску виконуваного файлу. Бажано відразу спробувати трохи Makefile і CMake.

Структури даних та алгоритми. Фактично в університетах це окремий предмет «Алгоритми та структури даних». Річ одночасно складна та проста. Найкраща порада — прочитайте для початку книгу Grokking Algorithms: An Illustrated Guide for Programmers and Other Curious People Адітья Бхаргава. У ній чудово описані всі базові концепції. І пам’ятайте: найважливіше під час читання книг з програмування — намагатися писати все те, про що у них йде мова.

STL. Мабуть, ви вже використовували щось зі стандартної бібліотеки, наприклад — cout та cin. Тепер час навчитися використовувати vector, list і т.д. Головна порада до теми в цілому — прочитавши про вид контейнера, спробуйте написати його самі.

Багатопотокове програмування. Майже на всіх співбесідах, де я був, про нього питали. Спробуйте розібратися, але тема досить складна та глибока. Для новачка необхідно розуміти хоча б що таке потоки, мьютекси, які проблеми з нею можуть бути.

Шаблони. Не менша об’ємна тема, але мінімально її розуміти необхідно. Складно щось порадити, гайди, що я бачив переважно на достатньому рівні їх пояснюють.

Думаю, дійшовши до цього етапу, ви вже здатні потрапити в IT-компанію. Але розслаблятися рано — найцікавіше попереду. Втім, про це вже не в цій статті. Далі буде наведено кілька цікавих посилань. Але на цьому, гадаю, можна попрощатися. До зустрічі на кавабрейках!

Корисні посилання

Відеокурси:

Цікаві посилання:

  • Сppreference.com — опис усіх методів базового С++ та std бібліотеки;
  • Cplusplus.com — схожий за контентом сайт;
  • Github.com/practical-tutorials — чим можна зайнятися далі у плані розвитку себе як С++ розробника.

Сподобалась стаття? Підписуйтесь на автора, щоб отримувати сповіщення про нові публікації на пошту.

👍ПодобаєтьсяСподобалось14
До обраногоВ обраному14
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

The Design and Evolution of C++. Скромно рекомендую. Якщо є трохи вільного часу, звісно

Свого часу натрапив на хлопця який на твічі стрімив 24 години розробки гри для Ludum Dare а також збирав гроші на допомогу Україні. Писав він гру на власному Game engine (Hazel). Виявилось що він має свій Youtube канал на якому є 101 відео урок з поясненнями певних тем по С++. Посилання на добірку — www.youtube.com/...​Z98dudnM48yfGUldqGD0S4FFb його вдео про вказівники це поки що найкраще для мене що я бачив з пояснень що то є ті поінтери. За 16 хвилин базове поняття точно сформується.

Ещё приятно что он эмигрант из СНГ, он в одном из видео просил кошку не устраивать бардак на столе, обратившись к ней на русском языке))

Несмотря на это английский у него хороший, полезно слушать канал и одновременно с С++ подтягивать и англ яз

Спп звичайно забориста штука, але як перша мова програмування, то ні в якому випадку.
А в універі перши 3 роки на паскалях/дельфі писав, поки почало щось, стосовно с++, до кепки доходити.

«певний вами тип даних»
і тут я зрозумів, що це просто переклад

будь-який код, який напишете, це чітка інструкція для машини, і вона послідовно виконуватиме її.

Давай немножко поправим. Это не инструкция для машины. Инструкция для машины — это ассемблерный код или машинный код.

То, что ты пишешь в .cpp файле — это не инструкция для машины, это описание сайд эффектов, которые бы ты хотел выполнить. Ты пишешь код не для компьютера, а условно для какой-то абстракции, описанной в стандарте С++, в котором, например, слово «undefined» встречается 250 раз.

вибачте звісно, але у вас «етап 6» — то як «draw the rest of the owl»
Розумію, що це велика тема і ви обрали більш «практичний» підхід, але новачкам з ним буде важче, на мою думку. Як на мене, краще групувати теми для навчання за більшими «концептами», а не специфічними моментами синтаксису.
Наприклад, важко уявити як можна навчитись плюсам без згадування принципу RAII — він покриє відразу багато синтаксичних моментів та й саме поняття «ресурсів» та взаємодії з ОС/залізом.
Error handling повинен бути хоч базово поданий також.
Шаблони, думаю, також треба вивчати раніше як частину теми поліморфізму. Тут вже навіть з практичної точки зору важко уявити ознайомлення з STL без знання що таке оте «T».
І добре структурованим книжкам заміну таки важко знайти, тим паче коли є купа книг різних початкових рівнів від оригінального автора мови — www.stroustrup.com/books.html

Одна з найзаплутаніших мов програмування, ще й співбесіду фіг пройдеш, бо там сидять тіпки, котрі читали стандарт на 2000 сторінок, і думають, який корнер кейс з нього б запитати.

схоже Іллю вкусив віртуальний деструктор. а не проініціалізована змінна взяла в борг 300 грн і не віддає.

Ну от не треба прям так.
Коли до нас на сіньора приходять, то так...
А якщо на джуна, то ніхто кандидата не дрюкає, про всякі атоміки та варіадік темплєйти не питаємо.

на сінйора не приходять, а кличуть, ну принаймні в мене до цього часу так було

Можна перше посилання доповнити сайтом від того ж автора (на скільки я розумію), який веде це все на українській acode.com.ua/uroki-po-cpp

І невелика нотатка особисто від мене — будь-який код, який напишете, це чітка інструкція для машини, і вона послідовно виконуватиме її. Ніякої магії тут немає, все відбувається за описаним в програмі порядком.

... а потім там знайшлися undefined behaviors ))

Третій голос. Тю! Навіщо таку хуйню робить — та підійшов сзаду та засунув!
Четвертий голос. От ти, Косопизд репаний, замість багато п***іти учився б у старших людей.

учить C++ в качестве первого языка это как лишать девственности в коленно-локтевой позе )

по-моему, Ален Голуб в свое время писал, что у них на курсе по программированию сначала все было хорошо, но когда пошли указатели, выяснилось, до у довольного большого числа студентов просто нет в голове участка мозга, который отвечает за понимание этой концепции )

Я також два місяці не міг врубатися, що воно таке — оті їхні вказівники на паскалі, поки нарешті не дійшло, що це те саме, що наш офсет на асемблері

здається поінтер = вказівник.
для того щоб добре знати с++ необхідно прочитати дві книжки: Computer Organization and Design RISC-V Edition та підручник по хаскель. після цього с++ стає звичайним трансформером монади стану з IO в середині. Далі ви вчите японську мову і vhdl. купуєте zynq 7000, пишете відео декодер і драйвер до нього, який вам показує 4К на 600МHz армі. далі вивчаєте квантову механіку і створюєте машину часу, повертаєтеся в минуле і вбиваєте себе в момент, коли ви вирішили вивчати с++.
classic

Знаючи асемблер, набагато легше...

І невелика нотатка особисто від мене — будь-який код, який напишете, це чітка інструкція для машини, і вона послідовно виконуватиме її.

Ага. А як же compiler out of order execution, speculative execution, branch prediction, та цi всi константи з std::memory_order :-)

А це все, бай дізайн, не повинно видавати інший результат від того, який мав би вийти при звичайному послідовному виконанні. Звичайно, в реальному житті трапляються баги і в залізі, і в компіляторі, але все ж це не щодня буває. Я от свій перший баг в компіляторі, підтверджений розробником, знайшов десь на восьмому році програмування на плюсах.

Баг в компіляторі Delphi 2 виліз швидко і обійшовся легко, а то баг в GCC 2.95.2, який дозволяв const-функціям модифікувати пам’ять і крива реалізація c_str() в std::string нам коштувала двох місяців роботи без вихідних...

А розкажіть про криву реалізацію c_str() в std::string

c_str() викликало realloc(), розширюючи буфер на один байт, і дописуюучи в кінець \0.

В результаті, звертання з різних потоків до static const std::string pox = «pox» призводило до самі розумієте до чого, і що про це казали клієнти.

const char* c_str() const;

ух ти, цікаво. а як зараз зроблено?

Зразу виділяють на один байт більше, щоб в кінці завжди був нуль.

Я після цього випадку параноїдально переглядав кожну реалізацію STL, яку ми використовували.

двох місяців роботи без вихідних...

писали свій std::string або пиляли воркераунди навколо багів gcc?

слайди давай!!! ©
реально цікава тема, міжна підрібиць, будь ласка?

Ухти, то може, окремим топіком чи блогом? ;) Пишіть на [email protected]

Підписатись на коментарі