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-ом.

Література [ред.]

  1. Герберт Шилдт - Полный справочник C++

Посилання [ред.]