Основи програмування в C

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

Зміст

Введення

  1. Історія розвитку мов програмування

  2. Основи об'єктно-орієнтованого програмування

  3. Класи

  4. Конструктори і деструктори

  5. Успадкування

  6. Покажчик this

  7. Друзі

  8. Перевантаження операцій

  9. Константні об'єкти і константні методи

Література



Введення

Важливою віхою в розвитку програмування стало створення і широке поширення мови С + +. Ця мова, зберігши засобу що став загальновизнаним стандартом для написання системних і прикладних програм мови З (процедурно-орієнтована мова), увів у практику програмування можливості нового технологічного підходу до розробки програмного забезпечення, що одержало назву "об'єктно-орієнтоване програмування". Впровадження у практику програмування об'єктно-орієнтованої парадигми дає розвиток нових областей інформатики, значне підвищення рівня технологічності створюваних програмних засобів, скорочення витрат на розробку і супровід програм, їх повторне використання, залучення в процес розширення інтелектуальних можливостей ЕОМ. Об'єктний підхід інформаційного моделювання предметних областей все більш успішно застосовується в якості основи для структуризації їх інформаційних віддзеркалень і, зокрема, баз знань.



1. Історія розвитку мов програмування

Перші комп'ютери з'явилися в кінці Великої Вітчизняної Війни спочатку в Сполучених Штатах Америки, а пізніше в СРСР. Ці машини могли вирішувати обмежений клас задач.

Кодування відбувалося на фізичному рівні. Спочатку програми зберігалися на перфокартах. Таким чином, процес налагодження програми займав дуже багато часу. Пізніше з'явилися магнітні стрічки і магнітні диски, що полегшило завдання переносимості програм.

В кінці 1950 - початку 1960 років з'явилися мови програмування Fortran (FORmula TRANslation) і Cobol (COmmon Business Oriented Language)-мова, орієнтований на виконання спільних економічних розрахунків.

У 1960-70 роках було написано безліч мов програмування. Майже кожен програміст придумував свою мову, мріючи увічнити своє ім'я.

В кінці 1970-х з'явилися Паскаль, Модула, Сі, які широко застосовувалися.

На початку 1980-х широкого поширення набули персональні комп'ютери. Приблизно в цей же час з'явилася мова C + +.

Природно, що C + + найбільше близький до мови C. Мова С повністю включений в C + +, залишені всі можливості З як мови низького рівня для виконання найбільш складних і універсальних програм. Іншим джерелом натхнення була мова Simula 67; звідти запозичені концепції класів і похідних класів з віртуальними функціями.

Назва мови C + + виникло влітку 1983 року. Більш ранні версії, відомі під ім'ям "C з Класами", використовуються з 1980 року. Спочатку мова виникла в процесі створення програми подієво-керованої симуляції, для якої ідеально підійшов би мову Simula 67, якщо б не міркування ефективності. "C з Класами" використовувався для основних проектів з симуляції тільки в програмах, критичних за часом виконання та об'ємом використовуваній пам'яті. C + + вперше виник поза групою автора в липні 1983року, проте він вже тоді практично не відрізнявся від сучасної версії мови.

Назва "C + +" було запропоновано Ріком Масцітті і символізує еволюційні зміни, що відбулися з мовою C ("++" - позначення оператора інкрементаціі в мові C).

Таким чином, еволюцію мови можна показати на схемі:

Коди Асемблер Мови високого Об'єктно-орієнтоване і рівня модульне програмування

2. Основи об'єктно-орієнтованого програмування:

Об'єктно-орієнтоване програмування - це самий високорівнева вид програмування в даний час. Тут підтримуються досягнення попередніх поколінь і додані нові властивості. Ці нові властивості реалізують парадигму об'єктно-орієнтованого програмування.

Об'єктно-орієнтоване програмування на C + + грунтується на таких основних етапах розробки програм.

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

Другий етап полягає в типізації об'єктів та синтезі абстрактних типів даних.

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

Третій етап полягає в об'єктній декомпозиції як виділення підтипів або підоб'єктів та їх складових для кожного з типів об'єктів.

Четвертий етап являє собою композиційну ієрархізація об'єктів як виділення родовідових і композиційних відносин над об'єктами.

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

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

Мова програмування C + + володіє всіма основними властивостями мов об'єктно-орієнтованого програмування і суттєво відрізняється за своєю концепцією від базової мови C.

Існує кілька принципів, що лежать в основі мови C + +:

1. Інкапсуляція - це об'єднання похідного типу даних з набором функцій, що використовуються при роботі з цим типом, в єдиний клас. При цьому функції, включені в клас, називаються методами класу, дані - елементами даних, а конкретні представники класу - об'єктами класу. Закриття даних і методів оперування цими даними відбувається таким чином, щоб звертатися можна було б тільки певним об'єктам (в даному випадку тільки об'єктам цих типів).

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

3. Поліморфізм - це можливість визначення функції, що працює з різними за типом даних списками параметрів у межах якого-небудь одного виду алгоритмів. Такі функції називаються зазвичай віртуальними і проектуються як деяке сімейство однойменних функцій, що працюють з різними типами даних. Механізм, який реалізує вибір будь-якої конкретної функції з певного сімейства, носить назву механізму пізнього зв'язування, оскільки може бути використаний в процесі виконання готової програми.

3. Класи

Центральним поняттям об'єктно-орієнтованого програмування є поняття класу. Саме він реалізує основні властивості: інкапсуляцію, успадкування, поліморфізм.

Клас являє собою тип, визначений користувачем. Цей тип включає в себе сукупність полів даних і функцій для роботи з цими полями.

Клас оголошується:

class <ім'я класу> [: public <ім'я базового класу>]

{Поля даних

специфікатор доступу

функції};

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

Специфікатор доступу

Існує ряд міркувань, за якими було б доцільно обмежити доступ до елементів даних класу. До найбільш важливим з них відносяться наступні:

- Обмеження доступу до даних класу рамками тих функцій, які включені програмістом в цей клас, дозволяє локалізувати програмні помилки практично до початку роботи програми;

- Опис класу в цьому випадку дозволяє користувачам класів більш просто знайомитися з новими бібліотеками класів;

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

- Функціональне розмежування класів робить можливою розробку програм, що використовують концепцію паралельних процесів.

public

Цим специфікатором позначається група даних і функцій, які доступні іншим функцій програми.

protected

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

private

Служить для завдання даних і функцій, доступних тільки функцій даного класу. Це приватні дані.

За замовчуванням елементи вважаються приватними (private) для класу і відкритими (public) для структури (об'єднання також відносять до класів).

Класи краще визначати у файлі з розширенням. H, а реалізацію у файлі з тим же ім'ям, але з розширенням. Cpp або. C. Найчастіше клас поодинці не визначається, а створюються бібліотеки.

Для ілюстрації розглянемо приклад класу, який задає координату на екрані:

class Location

{Int x;

int y;

public:

Location (int _x, int _y); / / конструктор

void setx (int nx);

void sety (int ny);

int Getx ()

{Return x;}

int Gety ()

{Return y;}

};

У даному прикладі, використавши специфікатор public, ми зробили відкритими для інших функцій методи, описані у класі.

Визначити функції - члени класу можна всередині опису класу або за його межами. У першому випадку функція вважається вбудовуваною. Вбудована функція характерна тим, що компілятор C + +, обробляючи виклики цієї функції в програмі, замінює їх не на виклик функції як підпрограми, а безпосередньо на об'єктний код, що відповідає визначенню цієї функції. Внаслідок сказаного, програміст повинен брати до уваги, що вбудовуються функції, як правило, мають короткі визначення. Як приклад можна навести визначення функцій Getx () і Gety ().

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

void Location:: setx (int nx)

{X = nx;}

void Location:: sety (int ny)

{Y = ny;}

Location:: Location (int _x, int _y)

{X = _ x; y = _ y;}

Операція дозволу контексту (::) дозволяє вказати компілятору, до якого з класів належить обумовлена ​​функція.

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

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

Для того, щоб почати роботу з реальними об'єктами будь-якого класу, ці об'єкти необхідно спочатку визначити. При цьому в програмі необхідно вказати ім'я класу, об'єкт якого повинен бути створений, а також ім'я самого об'єкта. У кожного з класів може бути довільне число об'єктів.

4. Конструктори і деструктори

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

Ім'я конструктора збігається з ім'ям класу. Наприклад, у класі Location конструктор має наступний вигляд: Location (int _ x, int _ y).

Конструктор не повертає ніякого значення, навіть void.

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

У загальному випадку конструктори класів можуть мати списки параметрів, які можуть знадобитися при ініціалізації. При цьому програміст буде зобов'язаний задати список ініціалізації при описі кожного нового об'єкта.

Конструкторів в класі може бути багато. У цьому випадку реалізується механізм перевантаження функції.

Якщо конструктори не оголошені, компілятор сам створює конструктор без параметрів за умовчанням.

Оголошення об'єктів можна проілюструвати наступним чином:

void main (void)

{Location NK (0,0), KK (10,10), * PL;

cout <<KK. Getx (); / / значення, що повертається: 10

PL = & NK;

cout <<PL -> Gety (); / / значення, що повертається: 0

}

Тут при оголошенні NK (0,0) і KK (10,10) неявно викликаються конструктори.

cout <<KK. Getx () звернення йде через змінну.

cout <<PL -> Gety () звернення йде через покажчик.

Конструктор копій

{Location A (1,1), B, D = A;

...}

Спочатку створюється об'єкт D і він ініціалізується значенням об'єкта A. Для ініціалізації потрібно явно визначити конструктор.

У конструкторі копій як параметр використовується проста або константних посилання на об'єкт.

Location:: Location ([const] Location & S)

{X = S. X; y = S. Y}

Для кожного з об'єктів класу при очищенні пам'яті компілятором створюється деструктор за замовчуванням. Визначається деструктор наступним чином: ~ ім'я. Ім'я деструктора збігається з ім'ям класу, але з символом ~ (тильда) на початку.

Деструктор вирішує зворотну конструктором завдання, тобто очищає пам'ять.

Якщо в конструкторі об'єкту запитується динамічна пам'ять або відкривається файл, то при знищенні об'єкта необхідно передбачити дії по очищенню пам'яті і закриття файлу. У цьому випадку користувачеві необхідно визначати деструктор. Цей деструктор буде викликатися при виході об'єкта з області видимості.

Локальні об'єкти видаляються тоді, коли вони виходять з області видимості. Глобальні об'єкти видаляються при завершенні програми.

5. Успадкування

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

Клас, властивості і поведінку якого успадковуються, називається базовим класом.

Клас, який успадковує називає, називається похідним класом.

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

Успадкування, при якому вказується один базовий клас, називається простим.

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

Оголошення виглядає наступним чином:

class ім'я класу: public ім'я базового класу

Наприклад, class D: public A

{...}

Після імені класу D є двокрапка, за якою слід ключове слово public та ім'я класу A. Для компілятора це вказівка ​​на те, що клас D ​​буде наслідувати всі компоненти класу A. Саме ключове слово public інформує компілятор про те, що, оскільки клас A буде успадковуватися, значить, всі відкриті елементи базового класу будуть також відкритими елементами похідного класу. Проте всі закриті елементи базового класу залишаться закритими і до них не буде прямого доступу з похідного класу. Причина, по якій закриті члени класу стають недоступними для похідних класів - підтримка інкапсуляції. Якби закриті члени класу ставали відкритими просто за допомогою успадкування цього класу, інкапсуляція була б абсолютно неспроможна.

При множині спадкуванні оголошення виглядає так:

class D: public A [, public C]

{Тіло класу D}

Розглянемо приклад:

enum Bool

{False, true}; / / константи зводяться до int. Вони змінюються з кроком рівним одиниці.

class Point: public Location

{Protected:

Bool vis;

public:

Point (int _x, int _y);

void Show ();

void Hide ();

};

Point:: Point (int_x, int_y): Location (_x, _y)

{Vis = false;}

Тут клас Point успадковує властивості базового класу Location.

Успадкування та контроль доступу

Специфікатор доступу визначає те, як елементи базового класу успадковуються похідним класом. Якщо специфікатором доступу успадкованого базового класу є ключове слово public, то всі відкриті члени базового класу залишаються відкритими і в похідному. Якщо специфікатором доступу успадкованого базового класу є ключове слово private, то всі відкриті члени базового в похідному класі стають закритими. В обох випадках всі закриті члени базового класу в похідному класі залишаються закритими і недоступними.

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

Доступ до полів базового класу в похідному класі може бути збережено або посилений, але ніколи не може бути полегшений. Щоб наочніше уявити собі цей принцип, звернемося до таблиці:

Доступ

успадкування

Доступ компонентів

в базовому класі

Доступність компонентів

базового класу в

похідному класі

public

private

protected

public

Немає доступу

protected

public


protected

private

protected

public

Немає доступу

protected

protected

private

private

protected

public

Немає доступу

private

private



6. Покажчик this

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

імя_класса * const this = адресу оброблюваного об'єкта;

Ім'я this є службовим (ключовим) словом. Явно описати чи визначити вказівник this не можна і не потрібно. Відповідно до неявним визначенням this є константним покажчиком, тобто змінити його не можна, проте в кожній належить класу функції він указує саме на той об'єкт, для якого функція викликається. Кажуть, що покажчик this є додатковим (схованим) параметром кожної нестатичні компонентної функції. Іншими словами, при вході в тіло належить класу функції вказівник this ініціалізується значенням адреси того об'єкта, для якого викликана функція. Об'єкт, який адресується вказівником this, стає доступним усередині приналежної класу функції саме за допомогою покажчика this. При роботі з компонентами класу усередині приналежної класу функції можна було б скрізь використовувати цей покажчик.

Таким чином, кожна нестатичні функція - елемент класу має доступ до об'єкта, для якого вона викликана через вказівник this.

Розглянемо приклад:

comp & operator + (comp)

{Real = real + x.real;

im = im + x.im;

return * this;}

У прикладі реалізована для класу comp перевантаження операції додавання. Тут послідовно складаються дійсні та уявні частини. Повернення результату відбувається через вказівник this. Якщо потрібно повернути адреса об'єкту, то пишеться return this.

7. Друзі

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

Функція не може стати другом класу "без його згоди". Для отримання прав одного функція повинна бути описана в тілі класу зі специфікатором friend. Саме за наявності такого опису клас надає функції права доступу до захищених і власних компонентів.

class C

{...

friend class A;}

Всі функції класу A мають доступ до закритих полів класу C.

Дружба не носить "наскрізного" характеру (не володіє властивістю транзитивності): якщо клас A друг класу B, а клас B друг класу C, то це не означає, що A друг C.

Відзначимо особливості дружніх функцій. Дружня функція при виклику не отримує покажчика this. Об'єкти класів повинні передаватися дружньої функції тільки явно через апарат параметрів. При виклику дружньої функції не можна використовувати операції вибору:

імя_об'екта.імя_функціі і указатель_на_об'ект-> імя_функціі

8. Перевантаження операцій

На всі операції мови C + +, крім операцій оголошення, new, delete, та інших операцій, пов'язаних з визначенням похідних типів даних, поширюється властивість поліморфізму, тобто можливості використання в різних випадках для однієї і тієї ж операції операндів різних типів. Так, наприклад, операція складання дозволяє "змішувати" типи int, double, float і інші в одному виразі. Такий поліморфізм забезпечений внутрішніми механізмами мови C + +.

Таким чином, не можна перевантажувати такі операції:.:: *?:

Щоб з'явилася можливість використовувати стандартну для мови C + + операцію з незвичайними для неї даними, необхідно спеціальним чином визначити її нову поведінку. Це можливо, якщо хоча б один з операндів є об'єктом деякого класу, тобто введеного користувачем типу. У цьому випадку застосовується механізм, багато в чому схожий з механізмом визначення функцій. Для поширення дії операції на нові користувальницькі типи даних програміст визначає спеціальну функцію, звану "операція-функція" (operator function). Формат визначення операції-функції:

тіп_возвращаемого_значенія operator знак_операціі (специфікація параметрів операції-функції) {оператори тіла операції-функції}

При необхідності може додаватися і прототип операції-функції з таким форматом:

тіп_возвращаемого_значенія operator знак_операціі (специфікація параметрів операції-функції);

І в прототипі, і в заголовку визначення операції-функції використовується ключове слово operator, слідом за яким розміщений знак операції. Якщо прийняти, що

конструкція operator знак_операціі є ім'я деякої функції, то визначення і прототип операції-функції подібні до визначення і прототипу звичайної функції мови C + +. Наприклад, для поширення дії бінарної операції * на об'єкти класу T може бути введена функція з заголовком T operator * (T x, T y).

Визначена таким чином операція (у нашому прикладі операція "зірочка") називається перевантаженої (по-англійськи - overload), а сам механізм - перевантаженням або розширенням дії стандартних операцій мови C + +.

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

Якщо для класу T введена операція-функція з наведеним вище заголовком і визначено два об'єкти A і B класу T, то вираз A * B інтерпретується як виклик функції operator * (A, B).

Розглянемо приклад. Реалізуємо перевантаження операції додавання для класу комплексних чисел.

class comp

{Float im; float real;

public:

comp (float i, float r)

{Real = r;

im = i;}

comp operator + (comp X)

{Return comp (im + X.im, real + X.real);}

}

void main ()

{...

comp C1 (1,1), C2 (5,5), C3;

C 3 = C 1. Operator + (C 2) / / Прямий виклик операції-функції. Не використовується.

C 3 = C 1 + C 2 / / Непрямий виклик операції-функції.

...

}

Компілятор за типами об'єктів С1 і С2 визначає, що необхідно реалізувати не просто складання двох скалярів, як це буває у звичайному використанні операції +, а викликати перевантажену функцію operator +. Так як при визначенні класу поля im і real доступні функцій класу, є необхідність визначати тільки другий об'єкт (X в нашому прикладі).

У мові C + + потрібно, щоб операції привласнення, індексації та непрямого звернення до полів класу (->) обов'язково визначалися як методи, тобто як функції-члени класу.

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

Для багатьох операцій C + + існують свої особливості при перевантаженні (довизначення). Так, унарні операції перевизначаються з описом операції-функції без аргументу, наприклад:

class A

{...

A operator - () {текст функції}

...}



Відповідно довизначення бінарної операції використовує опис операції-функції з одним аргументом, тому що другим є об'єкт, для якого викликана операція. Слід також пам'ятати, що операція присвоювання "=" може перевантажуватися тільки оголошенням методу без описувача static. Те ж відноситься до операцій "()" і "[]".

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

comp & operator = ([const] comp & X)

{Real = X.real;

im = X.im;

return * this;}

Якщо вказуємо const, то це показує, що параметр не повинен змінюватися всередині функції, а крім того, дозволяє обробляти константні об'єкти.

Операція присвоювання не успадковується.

Константні об'єкти і константні методи

const Loc NK (0,0); / / константних об'єкт

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

Оголошення константної функції в тілі класу виглядає наступним чином:

Прототип const;

ПРАВИЛО:

Константні методи

  1. не повинні міняти значення елементів класу;

  2. не повинні викликати інші неконстантние методи класу.

Константні методи можуть застосовуватися як для константних, так і для неконстантних об'єктів.



Література

  1. М. Уейт, С. Прата, Д. Мартін Мова Сі: Пер з англ.-М.: Світ, 1988.-463 с., Іл.

  2. Уінер Р. Мова Турбо Сі: Пер з англ.-М.: Світ, 1991.-384 с., Іл.

  3. Беррі Р., Мікінз Б. Мова Сі: введення для програмістів: Пер. з англ.-М.: Фінанси і статистика, 1988.-с., мул.

  4. TURBO C + +. Borland International. Inc. 1990.

Додати в блог або на сайт

Цей текст може містити помилки.

Програмування, комп'ютери, інформатика і кібернетика | Реферат
81.4кб. | скачати


Схожі роботи:
Основи програмування
Основи алгоритмізації та програмування
Основи технології програмування
Програмування та основи алгоритмізації 2
Основи програмування та алгоритмізації 2
Програмування та основи алгоритмізації
Основи мови програмування Лісп
Основи програмування в середовищі Delphi 7 0
Основи програмування в середовищі Qbasic
© Усі права захищені
написати до нас