C++
C++ (Сі-плюс-плюс) — універсальна мова програмування високого рівня з підтримкою декількох парадигм програмування: об'єктно-орієнтованої, узагальненої та процедурної. Розроблена Б'ярном Страуструпом (Bjarne Stroustrup) в AT&T Bell Laboratories (Мюррей-Хілл, Нью-Джерсі) у 1979 році та названа «Сі з класами». Страуструп перейменував мову у C++ у 1983 р. Базується на мові Сі. Визначена стандартом ISO/IEC 14882:2003.
У 1990-х роках С++ стала однією з найуживаніших мов програмування загального призначення.
Зміст |
Особливості [ред.]
При створенні С++ прагнули зберегти сумісність з мовою С. Більшість програм на С справно працюватимуть і з компілятором С++. С++ має синтаксис, заснований на синтаксисі С.
Нововведеннями С++ порівняно з С є:
- підтримка об'єктно-орієнтованого програмування через класи;
- підтримка узагальненого програмування через шаблони;
- доповнення до стандартної бібліотеки;
- додаткові типи даних;
- обробка винятків;
- простори імен;
- вбудовані функції;
- перевантаження операторів;
- перевантаження імен функцій;
- посилання і оператори управління вільно розподіленою пам'яттю.
У 1998 році ратифіковано міжнародний стандарт мови С++: ISO/IEC 14882 «Standard for the C++ Programming Language». Поточна версія цього стандарту — ISO/IEC 14882:2003.
Приклад програми «Hello, world!» [ред.]
Нижче наведено приклад простої програми на С++, яка виводить на стандартний канал виводу рядок Hello, world!.
#include <iostream> int main() { std::cout << "Hello, world!" << std::endl; return 0; }
Простори імен [ред.]
Простори імен (namespaces) призначені для локалізації імен ідентифікаторів, і попередження їх конфліктів. По замовчуванню всі ідентифікатори знаходяться в глобальному просторі імен, тому часті випадки існування двох різних об'єктів з однаковими іменами, що призводить до помилок. Щоб цьому запобігти глобальний простір імен ділять на менші. Наприклад стандартну бібліотеку C++ винесено в область названу std.
Створення просторів імен [ред.]
Щоб створити простір імен використовують ключове слово namespace. Код:
namespace space_name { // Оголошення }
Доступ до ідентифікаторів з просторів імен [ред.]
Щоб отримати доступ до об'єктів з простору іменн з за його меж використовують оператор дозволу області видимості ( :: ). Наприклад:
namespace some { int something; } something=1; // Помилка, something невидиме. some::something=1; // Ми вказали в якій області його шукати.
Правда такий спосіб може бути страшенно незручним, якщо ми використовуємо багато ідентифікаторів не з нашої області видимості. Щоб полегшити нам життя придумана директива using. Хай ми маємо простір кімнати:
namespace room { Wall wall1,wall2,wall3,wall4; Ceil ceil; }
Можна внести стелю в наш іменний простір написавши що ми її будем використовувати:
using room::ceil; ceil=42; // Тепер стеля видима wall1=wall2; // А таке все ще викличе помилку!
А можна взагалі розкрити увесь простір імен:
using room; wall1=wall2=wall3; // Всі ідентифікатори з кімнати доступні
Деякі особливості просторів імен [ред.]
Можна робити простори імен без назви. Це просто для того щоб зробити локальні змінні невидимими поза областю. Крім того можна описувати кілька просторів імен з одним ім'ям. Тоді це буде один, і той же простір, просто рознесений в різні частини файлу, чи взагалі в різні файли.
Шаблони [ред.]
Шаблони - механізм C++, який дозволяє створювати узагальнені функції і класи, які працюють з типами даних які передаються в параметрі. Можна наприклад створити функцію яка сортує масив цілих чисел, а можна створити шаблон функції, який буде сортувати масиви будь-яких даних, над якими задані операції порівняння і присвоєння. Таким чином одну, і туж, функцію сортування можна застосовувати для різних масивів, не створюючи окрему для кожного типу.
В початковій версії С++ не було шаблонів, але зараз вони підтримуються кожним компілятором, і разом з бібліотекою шаблонів STL входять до стандарту C++.
Функції [ред.]
Шаблон функції виглядає так:
template <class Ідентифікатор_типу> Тип_результату Назва_функції(Список_параметрів) { // Тіло функції }
Параметр "Ідентифікатор_типу" задає тип з яким працює функція. Всюди в тілі і заголовку функції компілятор замість цього ідентифікатора підставить фактичний тип, який передається. Наприклад функція перестановки двох змінних:
template <class Type> void swap(Type &a, Type &b) { Type tmp=a;a=b;b=tmp; }
Замість ключового слова class можна застосовувати typename, але більше поширений перший варіант.
Шаблон може узагальнювати кілька різних типів даних:
template <class Type1, class Type2> void foo(Type1 a, Type2 b) { printf("Тут ми щось робимо з даними"); // Неправда }
Крім того, параметрами шаблону можуть слугувати не тільки імена типів, а і конкретні значення:
template <int n> int mul(int x) { return n*x; }
Шаблонну функцію можна перевантажувати. Наприклад:
unsigned int foo(unsigned int a,unsigned int b) { return ((a+b+1)*(a+b)/2)+a; }
Примітка: за MSVC++ помічена звичка замість генерування коду для кожного типу параметрів просто для найбільшого з використовуваних (наприклад, внаслідок викликів swap<int>() і swap<double>() буде згенеровано код лише для swap<double>(), який при потребі викликатиметься з перетворенням типів)
Тоді компілятор сам буде вибирати потрібну функцію залежно від параметрів. Наприклад програма:
#include <stdio.h> template <class Type1, class Type2> void foo(Type1 a, Type2 b) { printf("Template foo\n"); } int foo(int a, int b) { return ((a+b+1)*(a+b)/2)+a; } int main(void) { float x; foo(x,x); for(int i=0;i<3;i++) for(int j=0; j<3;j++) printf("foo(%i,%i)=%i\n",i,j,foo(i,j)); return 0; }
Буде давати такий вивід:
Template foo foo(0,0)=0 foo(0,1)=1 foo(0,2)=3 foo(1,0)=2 foo(1,1)=4 foo(1,2)=7 foo(2,0)=5 foo(2,1)=8 foo(2,2)=12
Класи [ред.]
Шаблони класів описуються аналогічно до шаблонів функцій. Наприклад шаблон класу для стеку:
#include <stdio.h> const int SIZE=5; template <class Type> class Stack { Type st[SIZE]; int sp; public: Stack() { sp=0; } void push(Type a); Type pop(); }; template <class Type> void Stack<Type>::push(Type a) { if(sp==SIZE) { printf("Переповнення стеку\n"); return; } st[sp]=a; sp++; }; template <class Type> Type Stack<Type>::pop() { if(sp==0) { printf("Стек порожній\n"); return 0; } sp--; return st[sp]; } int main(void) { printf("Введіть \"e\",або \"q\" щоб вийти. \n"); printf("Введіть \"u\" і ціле число, щоб заштовхнути його в стек.\n"); printf("Введіть \"p\" щоб витягнути число зі стеку і надрукувати його\n"); Stack<int> s; char command=' '; while(!((command=='e')||(command=='q'))) { command=getchar(); switch(command) { case 'u': { int tmp; scanf("%i",&tmp); s.push(tmp); }break; case 'p':printf("%i\n",s.pop()); break; } } return 0; }
Ключове слово typename [ред.]
Добрі люди підказують, що окрім ключового слова class, можна використовувати typename, і вони еквівалентні. Коли Страуструп придумував C++ йому не хотілось використовувати ще одне ключове слово, тому він використав клас. А потім за роботу взявся цілий комітет, і вони вирішили що це може створити неоднозначності. Тому додали ще і typename.
Правда є випадки, коли typename означає не те, що і клас.
Наприклад, що наступний за ним ідентифікатор є типом:
template < class T>
class MyClass {
typename T::SubType* ptr;
...
};
В даному випадку слово typename означає, що SubType є підтипом класу T, відповідно ptr - показчик на тип T::SubType. Без typename ідентифікатор SubType інтерпритується як статичний член класу і рядок сприймається як операція множення значення SubType класу T на значення ptr; Але в даному випадку любий тип який буде підставлений шаблону повинен мати внутрішній тип SubType. SubType може бути як класом оголошеним в середині іншого, так і простом typedef-ом.
Література [ред.]
- Герберт Шилдт - Полный справочник C++
Посилання [ред.]
- Простір імен (CybWiki)
- Шаблони (С++) (CybWiki)