Минулого разу я постарався дати початкові відомості про С++ на прикладі компілятора від компанії Borland. Сьогодні, в останній день моїх осінніх канікул =(, я вирішив написати другу частину статті та розповісти про структурах, класах, процедурах, що підключаються модулі та ін. та ін.

Давайте напишемо простеньку програму, вона буде пересувати різнокольорові круги за формою справа наліво (якщо ви не зрозуміли про що це я, то ви все зрозумієте, коли побачите відкомпільований варіант). Отже, запустіть ваш C++ Builder і створіть новий проект. На форму киньте компонент TImage, на вкладці Additional і TTimer, з вкладки System. Картинку розтягніть на всю форму, а в таймера властивість interval поставте 150 (хоча можете і інше число). Отже, як буде працювати наша програма?
На початку ми створимо структуру, в якій буде зберігатися інформація про кожному колі (його координата і колір). Потім створимо масив «кіл» і масив їх можливих кольорів. Рухати кола у нас буде процедура Move();.Нижче я навів повний код нашого проекту:

/ / $ $ —- Form CPP —-

#include // модуль
#pragma hdrstop

#include «MainUnit.h» // модуль

#pragma package(smart_init)
#pragma resource “*.dfm”

struct TShell // власне наша структура
{
int X, Y; // координати
TColor Color; // колір
};

const int MaxShells = 50; // масив визначає максимум куль
const TColor Colors[3] = {clBlue, clWhite, clRed}; // кольору всього три (блакитний, білий,
// червоний)

TForm1 *Form1;

TShell Shells[MaxShells-1]; // масив наших кіл

__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}

void Move() // процедура яка буде рухати кола
{ // зафарбовуємо нашу картинку
Form1->Image1->Canvas->Rectangle(0, 0, Form1->Width, Form1->Height);
for (int i = 0; i < MaxShells -1; i++) // починаємо перебирати наші кульки =)
{
Shells[i].X = Shells[i].X — 5; // Тут зрозуміло, міняємо координату
if (Shells[i].X <= 0) // якщо куля полетів, то повертаємо його з небес на землю =).
{ // тут я думаю все зрозуміло =)
Shells[i].X = Form1->Image1->Width+Random(Form1->Image1->Width);
Shells[i].Y = Random(Form1->Image1->Height);
Shells[i].Color = Colors[Random(3)];
}
// власне, малюємо кола 😉
Form1->Image1->Canvas->Brush->Color = Shells[i].Color;
Form1->Image1->Canvas->Ellipse(Shells[i].X-5, Shells[i].Y-5, Shells[i].X+5, Shells[i].Y+5);
}
Form1->Image1->Canvas->Brush->Color = clWhite;// повертаємо колір заливки на //місце

}

void __fastcall TForm1::FormCreate(TObject *Sender)
{
Randomize(); // рандомизируем генератор випадкових чисел
for (int i = 0; i < MaxShells -1; i++) // випадковим чином розставляємо кульки
{
Shells[i].X = Form1->Image1->Width+Random(Form1->Width);
Shells[i].Y = Random(Form1->Image1->Height);
Shells[i].Color = Colors[Random(3)];
}
}

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
Move();// викликаємо процедуру
}

Спочатку я створив структуру TShell, вона зберігає координати і колір кожного кола окремо. Оголошення структури виглядає наступним чином:
Struct ім’я
{
властивості
};
Тобто на початку йде ключове слово Struct, потім ім’я структури, а потім у фігурних дужках описуються властивості структури. До речі, доступ до властивостей структур відбувається через точку. Наприклад, так TShell.X.
Потім я створив константу, вона буде зберігати число куль. Оголошення константи виглядає так:
const тип ім’я = значення;
Зауважте, на відміну від Delphi в С++ ми зобов’язані вказати тип константи.
Потім йде наступна запис:
const TColor Colors[3] = {clBlue, clWhite, clRed};
так в С++ оголошуються константные масиви. У квадратних дужках я просто вказав кількість елементів масиву (нумерація починається з нуля), а потім у фігурних дужках значення кожного елемента. Квітів звичайно замало, але я вирішив обмежитися цим набором.
Потім я створив масив наших куль:
TShell Shells[MaxShells-1];
Я по звичці написав MaxShells-1 і створив на один елемент менше(тобто не 50, а 49).
Звернення до елементів масиву виглядає так:
Shells[i].X = значення;
Замість точки може стояти стрілка, якщо ви створили масив структур, а класів.
Потім найцікавіше, я створив процедуру, яка буде викликатися кожен раз, коли потрібно буде перемалювати сцену. Оголошення процедур і функцій виглядає наступним чином:
тип ім’я()
{
код
}
тут тип це той тип значення, що повертається, але так як у нас процедура і вона не повинна повертати значення, то ми вказуємо значення void (по-моєму, на моїй рідній мові це означає порожнеча). Якщо ж у нас функція, і вона повинна повертати значення, то замість void пишемо тип значення, що повертається, а щоб повернути яке — небудь значення нам треба написати наступне:
return значення;
наприклад:
int XXX(int X)
{
return X*2;
}

УВАГА!!! Після появи оператора return функція / процедура припинить роботу (це все одно, що написати exit; в делфі)! Якщо ми хочемо, що в якомусь місці перервати виконання процедури (яка не повертає), то потрібно просто написати return; і все. Думаю пояснювати весь залишився код вам не потрібно, там немає нічого надприродного(особливо якщо ви прочитали першу частину статті), а якщо ви чогось не зрозуміли, то пишіть на мою поштову скриньку вказаний в кінці статті).

Так, тепер я розповім вам про класи і про те, як підключати модулі до проекту, що дуже важливо деколи буває =). Я дам лише малу частину можливостей ООП мови С++, але прошу на мене не ображатися, так-так тема дуже об’ємна і в одну статтю все не уместишь, та я й сам не все знаю про це. Так от, давайте напишемо прогу з однією-єдиною кнопкою, при натисканні на яку буде виводитися повідомлення
Hello World, який раз ви натиснули на кнопку (знаю, що цей приклад не несе сенсу, але заради прикладу можна про це забути =)). А для повного геморою повідомлення буде виводити нами ж і створений об’єкт =), ну а щоб було повне щастя, об’єкт ми опишемо в окремому модулі. Ну що ж приступимо! Правда тут є одне АЛЕ я працюю з компілятором 2006 року випуску, якщо у вас білдер 2004 року або старше то у нас може з’явитися розбіжності в основному пов’язані зі зміною шкурки програми. Тепер створіть новий проект, зберігши старий на пам’ять =), створіть новий модуль
File->New->Unit і збережіть проект з модулем на гвинт File->Save All, імена придумайте самі (особисто я назвав проект Units, модуль з формою MainUnit, а створений мною модуль MyClass). Заздалегідь киньте на форму кнопку. Тепер давайте опишемо наш клас у новому модулі, а не у файлі проекту.

Класи описуються наступним чином:
class ім’я класу: public класи батьки
{
public: доступно всім
властивості і методи
__published: видно в інспекторі об’єктів і змінні
властивості і методи
protected: доступно тільки нащадкам
властивості і методи
private: доступно тільки в класі
властивості і методи
}; список змінних;
думаю, коментарі зайві, скажу тільки, що класів батьків може бути декілька і після ключових слів на кшталт public або protect, повинно стояти двокрапка. Ось так я описав свій клас у моєму прикладі:
class TMyClass // ім’я класу
{
public: // тут те що доступно всім
TMyClass(); // Конструктор
~TMyClass(); // Деструктор
void Message(AnsiString Str); // Власне метод виводить повідомлення
private: // доступно тільки об’єкту
unsigned int Cout; // лічильник

};
Ось тепер про класи в С++ по подробней. Так само як і в делфі у класу повинен бути конструктор і деструктор, але в З++ вони оголошуються зовсім по-іншому конструктор повинен мати ім’я, що і клас, а деструктор теж ім’я, що й клас, але разом з тільдою (~), наприклад якщо TMyClass()- конструктор, то ~TMyClass()- деструктор.
Зауважте, що конструктор і деструктор не мають ніяких значень.
Тепер глянемо на лічильник, що це за unsigned int, це та ж цілочисельна змінна тільки разом з модифікатор unsigned, тепер наша змінна може приймати тільки позитивні значення, а так як наш лічильник завжди буде позитивним це цілком виправдано. Ми описали процедури в нашому класі тепер давайте і напишемо, додайте в наш модуль з класом наступні рядки:

TMyClass::TMyClass() // конструктор
{
Cout = 0;
}

TMyClass::~TMyClass() // деструктор
{
Cout = 0;
}

void TMyClass::Message(AnsiString Str) // метод
{
Cout++;
ShowMessage(Str+IntToStr(Cout));
}
опис методу, якогось класу виглядає так:

тип ім’я класу:: ім’я методу(параметри)
{
код;
}
виключення конструктор і деструктор там немає типу, а значить, його не треба вказувати. Звернення до методів відбувається через два двокрапки ( :: ). Весь наш клас описаний і готовий до використання. Але якщо спробувати скомпілювати код прямо зараз, вилетить помилка справа в тому, що ми не підключили потрібні модулі, модулі підключаються так:
#include // якщо глобальний модуль
#includeмодуль // якщо модуль належить тільки нашого проекту
тепер напишіть на самому початку нашого модуля наступне:
#include «MyClass.h»// ця строчка повинна бути у вас
#include
#include
#include
зверніть увагу, що потрібно вказувати розширення файлу (у всіх глобальних, як правило, це «.hpp») Модулі у білдера мають ті ж імена що і у делфі.

Тепер збережіть проект, що б зміни увійшли в силу. І вже в модулі нашого проекту пишіть наступне:
/ / $ $ —- Form CPP —-
//—————————————————————————

#include
#include «MyClass.cpp» //підключаю локальний модуль(в тій самій папці де і сам проект)
#pragma hdrstop

#include «MainUnit.h»
//—————————————————————————
#pragma package(smart_init)
#pragma resource “*.dfm”
TForm1 *Form1;
//—————————————————————————
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{

}
//—————————————————————————
void __fastcall TForm1::Button1Click(TObject *Sender)
{
static TMyClass *Cl;// створюю покажчик на об’єкт
if (Cl == NULL) // якщо об’єкт ще не створений то створюю його
Cl = new TMyClass;// ось так створюється об’єкт
Cl->Message(«Hello World „);// виводжу сообщене
}
ось перше питання, яке у вас повинен знати: «Що за static TMyClass *Cl;?»
пояснюю, static говорить компілятору про те, що дану змінну не потрібно видаляти після виходу з функції, тобто значення цієї змінної збережеться навіть після виходу з функції! А ось чому TMyClass *Cl; замість TMyClass Cl; все просто ми створюємо ПОКАЖЧИК на об’єкт(в принципі це ж відбувається і в делфі тільки там не потрібно вказувати на це явно). Потім я перевіряю створений об’єкт вже якщо ні то створюю(інакше буде помилка). В С++ NULL теж, що в делфі NIL. Створення об’єкта виглядає так:
покажчик = new ім’я класу;
а щоб звільнити об’єкт пишемо:
delete покажчик;

Я на початку не хотів писати про макроси, т. к. по-моєму, нічого такого в делфі немає, та і місце в статті не гумове, але все ж таки зважився. Отже, навіщо потрібні макроси? Згадайте, що відбувається під час виклику функції, на початку в стек піднімаються потрібні змінні, потім відбувається власне виклик нашої функції – все це напружує процесор і оперативку, так от макроси дозволяють позбутися від цього!
Все просто, замість реального виклику процедури, потрібний код просто «дописується» в то місце де це потрібно, створюється макрос приблизно так:
#define ім’я макросу(аргументи) (заміщення), а викликається так само як звичайна процедура:
ім’я макросу (аргументи).
Що б ви краще зрозуміли, я написав маленький приклад:
#define Kvadrat(X) ((X)*(X)) // це макрос, він повинен повертати квадрат числа

void __fastcall TForm1::Button1Click(TObject *Sender)
{
int Chislo;// створюю змінну
Chislo = Kvadrat(4); // ось він наш макрос
ShowMessage(IntToStr(Chislo)); // що б упевнитися виводжу повідомлення
}

компілятор сам, негласно, переписав за нас код натискання на кнопку на цей:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int Chislo;// створюю змінну
Chislo = (4)*(4); // змінений рядок
ShowMessage(IntToStr(Chislo)); // що б упевнитися виводжу повідомлення
}
Зауважте, що дужки залишилися, і я їх не випадково поставив! Якби їх не було то вираз на зразок Chislo = Kvadrat(2+2); давав би не дуже вірний результат, так як текст б замінився на цей:
Chislo = 2+2*2+2;
і результат був би вже не 16, а 8! Пам’ятайте про це! Макроси можна оголошувати і константи, але користуватися цим потрібно дуже обережно, так як макроси помітно збільшують розмір нашого бінарника! Тобто процедури зменшують швидкість виконання, а макроси збільшують розмір экзэшника і значно знижують читабельність коду!

От власне я розповів все що хотів про С++ якщо є питання, то залишай в коментах або пиши сюди [email protected], але перед цим переконайся що пошукав відповідь в гуглі, або іншому пошуковику! (до речі не йшли мені исходники у вигляді вкладених файлів такий лист я відразу видалю).
В якості ради хочу додати, що якщо тобі подобається С++, то пошукай в інеті статті Кріс Касперски, дуже хороший автор (правда деколи пише про дуже складні речі).
Зайди на сайт www.vr-online.ru там є сорники як на делфі, так і на З++. Ну і частіше використовуй пошуковики =).