Класи C++

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

Клас в С++ — це визначений користувачем тип або структура даних, оголошена ключовим словом class , яка містить дані (поля) і функції (методи) як свої члени, доступ до якої регулюється трьома специфікаторами доступу: private, public, protected (за умовчанням - private). Private-члени не доступні за межами класу, вони доступні тільки через методи класу. Public-члени є доступними і поза класом.

Екземпляри класу називаються об'єктами, вони можуть містити змінні, константи, функції і перевантажені оператори, визначені програмістом.

Відмінності між структурами і класами в C++

[ред. | ред. код]

У C++, клас оглошується ключовим словом class і за умовчанням має специфікатор доступу - private. А структура - це клас, визначений ключовим словом structure. Її члени та базові класи є public за умовчанням.

Оголошення та використання

[ред. | ред. код]

Класи C++  мають свої елементи. До цих елементів  належать змінні (включаючи інші класи), функції , відомі як методи, конструктори і деструктори. Члени оголошуються публічно або в приватному порядку можна з допомогою специфікаторів доступу public: і private: відповідно. Будь-який елемент, оголошений після специфікатора, буде мати відповідний тип доступу. Існує також наслідування між класами, яке може бути застосоване з допомогою специфікатораprotected:.

Глобальні і локальні класи

[ред. | ред. код]

Клас оголошений поза функціями називається глобальним класом, тому що його об'єкти можуть бути створені у будь-якому місці в програмі. Якщо клас визначений в тілі функції, то він є локальним класом, тому що об'єкти такого класу є локальними в області видимості функції.

Оголошення та члени класу

[ред. | ред. код]

Класи оголошуються ключовим словом class або structure. Члени класу оголошуються в тілі цього класу.

struct person

{

string name;

int age;

}

class person

{

public:

string name;

int age;

}

Наведені вище оголошення є функціонально еквівалентними. 

Після одного з таких оголошень, клас person може бути використаний, щоб створити нові змінні типу person:

#include <iostream>
#include <string>

class person
{
  public:
    string name;
    int age;
};

int main()
{
  person a, b;
  a.name = "Calvin";
  b.name = "Hobbes";
  a.age = 30;
  b.age = 20;
  std::cout << a.name << ": " << a.age << std::endl;
  std::cout << b.name << ": " << b.age << std::endl;
  return 0;
}

Наведений вище код буде виводити:

Calvin: 30
Hobbes: 20

Методи

[ред. | ред. код]

Важливою особливістю класів C++ і структур  є методи. Кожен тип даних може мати свої власні вбудовані функції (методи), які мають доступ до всіх (public і private) полів цього типу даних. В тілі цих нестатичних методів, ключове слово this  використовується для посилання на об'єкт, для якого ця функція викликається. Це зазвичай реалізується шляхом прихованої передачі адреси об'єкта першим параметром функції. Візьмемо наведений вище клас person в якості прикладу знову:

class person
{
  std::string name;
  int age;
public:
  person() : age(5) { }
  void print() const;
};

void person::print() const
{
  std::cout << name << ":" << age << std::endl;
  /* "name" і "age" є полями.
     Ключове слово "this" це адреса об'єкта в якому 
     цей метод викликається. Його тип - const person*, 
     тому що метод оголошений як const.
 */
}

У наведеному вище прикладі  функція print()оголошена в тілі класу і визначена назвою класу, за яким слідує ::. name і age є приватними (за умовчанням для класу) і Print() оголошена як public, що необхідно, якщо вона використовується поза межами класу. З функцією print(), вивід може бути спрощений до:

a.print();
b.print();

Наслідування

[ред. | ред. код]

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

Застосування механізму успадкування дозволяє покращити повторне використання коду шляхом використання вже визначених властивостей та методів (поведінки) базових класів.

Перевантажувані оператори

[ред. | ред. код]

В C++, оператори + - * /, можуть бути перевантажені, щоб задовольнити потреби програмістів. Ці оператори називаються перевантажуваними операторами.

За домовленістю, перевантажені оператори мають вести себе для створених типів майже так само, як і для вбудованих типів даних (int, floatі т. д.), але це не

вимагається. Оголосимо структуру, яка називається integer , в якій змінна це число, а integer*integer це сума, а не добуток :

struct integer 
{
    int i;
    integer(int j = 0) : i(j) {}
    integer operator*(const integer &k) const 
    {
        return integer (i + k.i);
    }
};

В наведеному вище коді використовується конструктор, щоб "побудувати" значення, що повертається. Для більш чіткого уявлення (хоча це може знизити ефективність програми), наведений вище код можна переписати так:

integer operator*(const integer &k) const 
{
    integer m;
    m.i = i + k.i;
    return m;
}

Програмісти також можуть помістити прототип оператора в тіло структкри і визначити функцію оператора в глобальній області видимості:

struct integer 
{
    int i;
   
    integer(int j = 0) : i(j) {}
 
    integer operator*(const integer &k) const;
};
 
integer integer::operator*(const integer &k) const 
{
    return integer(i * k.i);
}

Такі самі властивості перевантаження операторів можуть використовуватися для класів.

Бінарні оператори 

[ред. | ред. код]

Бінарні оператори (з двома аргументами) можна перевантажувати, оголосивши функцію з ідентифікатором operator , який викликає один єдиний аргумент.

Нижче наведено список бінарних операторів, які можна перевантажувати:

Оператор Загального користування
+ - * / % Арифметичний розрахунок
^ & | << >> Побітовий розрахунок
< > == != <= >= Логічне порівняння
&& Логічне множення
|| Логічна диз'юнкція
+= -= *= /= %=

^= &= |= <<= >>=
Складні завдання
,
(не має загального

використання)

Оператор '='  між двома змінними одного типу перевантажений за умовчанням: скопіювати весь вміст змінних від одного до іншого. Він може бути перезаписаний, якщо це необхідно.

Унарні оператори, які можна перевантажувати

[ред. | ред. код]

У той час як деякі оператори приймають два символи: один зліва , інший справа, у деяких операторів є тільки один знак - його називають "унарний". Прикладами є від'ємний знак і "логічне не" (знак оклику, !).

Відправник унарного оператора може бути ліворуч, або праворуч від оператора. Нижче наведено список унарних перевантажуваних операторів:

Оператор Загального користування Позиція відправника
+ - Позитивний / негативний знак справа
* & Розіменування справа
! ~ Логічні / побітове не справа
++ -- Пре-інкремент / декремент справа
++ -- Пост-інкремент / декремент зліва

Синтаксис перевантаження унарноно плюс оператора, де знак знаходиться праворуч, виглядає наступним чином:

return_type operator@ ()

Коли знак знаходиться зліва:

return_type operator@ (int)

@  - первантажений оператор. 

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

const аргументи можуть бути додані в кінці, якщо потрібно.

Перевантаження дужок

[ред. | ред. код]

Квадратні дужки [] і круглі дужки () можуть бути перевантажені в C++ структурах. Квадратні дужки повинні містити рівно один параметр, в той час як круглі дужки можуть містити певну кількість параметрів або нічого.

Перевантаження квадратних дужок:

return_type operator[] (argument)

argument - те, що міститься в квадратних дужках.

Круглі дужки перевантажуються подібним чином.

return_type operator() (arg1, arg2,...)

Вміст того що буде в круглих дужках (оператор) визначається в других дужках.

Крім операторів, зазначених вище, оператор стрілка (->),  ключове слово new  і delete також можуть бути перевантажені.

Конструктори

[ред. | ред. код]

Іноді програмісти можуть знадобитися змінні за умовчанням або певне значення при оголошенні. Це може бути зроблено шляхом оголошення конструктора.

person::person(string N, int A) 
{
    name = N;
    age = A;
}

Змінні можуть бути ініціалізовані в списку ініціалізації, з використанням двокрапки, як в прикладі нижче. Це відрізняється від попереднього тим, що ініціалізація відбувається з допомогою конструктора, а не з допомогою оператора присвоювання. Це більш ефективно, тому що так об'єкт будується відразу, тоді як в іншому випадку, він спочатку ініціалізується за допомогою конструктора за умовчанням, а потім присвоюються різні значення. Також деякі типи (наприклад: посилання і константи) не можуть бути присвоєні, тому вони повинні бути ініціалізовані за допомогою списку ініціалізації.

person(std::string N, int A) : name(N), age(A) {}

Зверніть увагу, що фігурні дужки не можуть бути опущені, навіть якщо вони порожні. За умовчанням, значення надаються останнім параметрам.

person(std::string N = "", int A = 0) : name(N), age(A) {}

Коли немає аргументів, що передаються конструктору як у наведеному вище прикладі, це еквівалентно виклику конструктора без параметрів (конструктор за умовчанням):

person() : name(""), age(0) {}

Оголошення конструктора виглядає як функція з тим же ім'ям, що і тип даних. Насправді виклик конструктора може набувати форми виклику функції.

int main() 
{
    person r = person("Wales", 40);
    r.print();
}

Наведений вище код створює об'єкт Person, а потім присвоює його r, використовуючи конструктор копіювання. Кращий спосіб створення об'єкта (без непотрібного копіювання) є:

int main() 
{
    person r ("Wales", 40);
    r.print ();
}

Специфічні дії програми, можуть бути додані як частина конструктора.

person() 
{
    std::cout << "Hello!" << std::endl;
}

Конструктор за умовчанням

[ред. | ред. код]

Конструктори за умовчанням викликаються, коли конструктори не визначені для класів.

class A { int b;};
//створення об'єкта з використанням дужок
A *a = new A(); //викликається конструктор за умовчанням і b ініціалізується '0'
//об'єкт створується без використанням дужок
A *a = new A; // виділяється пам'ять, потім викликається конструктор за умовчанням і b 
//ініціалізується '0'
//створення об'єкта без new
A a;  //просто виділяється пам'ять і b невизначено

Деструктори

[ред. | ред. код]

Деструктор - це протилежність конструктору. Він викликається, коли екземпляр знищується, наприклад, коли об'єкт класу створюється у блоці (фігурні дужки "{}") він видаляється після закриваючої дужки, то деструктор викликається автоматично. Деструктори використовуютьчя для звільнення пам'яті у купі, коли екземпляр знищується.

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

~person() 
{
    cout << "I'm deleting " << name << " with age " << age << endl;
}

Схожість між конструкторами і деструкторами

[ред. | ред. код]
  • Обидва мають однакове ім'я класу, в якому вони оголошені.
  • Якщо не оголошені користувачем то обидва є в класі за умовчанням.

Властивості

[ред. | ред. код]

Синтаксис с++ намагається надати кожному аспекту структури вигляд базовго типу даних. Таким чином, перевантажені оператори дозволяють маніпулювати структурами так само як цілими та дробовими числами, масиви структур можуть бути оголошені за допомогою квадратних дужок (array [size]), і вказівник на структуру може бути роз'іменований точно так само, як вказівник на вбудований тип даних.

Ключове слово this

[ред. | ред. код]

Для полегшення написання коду в c++ реалізовано ключове слово this для всіх функцій-членів. Ключове слово this  є вкізівником на об'єкт, який викликає функцію.

Ключове слово thisособливо важливе для методів як величина що повертається:

complex& operator+=(const complex & c) 
{
    realPart += c.realPart;
    imagPart += c.imagPart;
    return *this;
}

Як зазначено вище, this є вказівником, тому використання зірочки (*) необхідне для перетворення його у посилання, яке повертається.

Посилання

[ред. | ред. код]

Головні посилання: