C++Въведение:

Начин на използване 

 

 

 

 

За кого е предназначено това ръководство?

Това ръководство е предназначено за хора, които искат да се научат да програмират на езика C++. Не е задължително те да имат основни познания върху някой друг програмен език. Разбира се, познаването на друг програмен език или други компютърни познания ще спомогнат за по-доб­рото разбиране на това ръководство, въпреки че това не е от решаващо значение.

Ако сте запознати с езика C, можете да приемете първите три части на това ръководство (от 1.1 до 3.4) за обзорни, тъй като те предимно обясняват C частта на езика C++.

Част 4 описва поддръжката за обектно-ориентираното програмиране.

Част 5 обяснява основно новите възможности, въведени от стандарта ANSI C++.

Структура на ръководството

Ръководството е разделено на 6 части, всяка от които съдържа няколко секции. Много от секциите съдържат допълнителна страница със специфични примери, описващи използването на наученото в дадената глава. Препоръчително е да прочетете тези примери и да разберете всеки ред с код в тях, преди да преминете към следващата глава.

Един добър начин за придобиването на опит с програмния език е да променяте и добавяте към примерните програми нови функции, които напълно разбирате. Не се страхувайте да променяте примерите, представени в това ръководство. Досега това не е довело до случаи на компютърни експлозии.

Бележки за съвместимостта

Приетият стандарт ANSI C++ е международен стандарт от сравнително неотдавна. Той беше публикуван през ноември 1997, въпреки че езикът C++ съществува от доста отдавна (80-те) и въпреки многото компилатори, които не поддържат всички нови възможности, включени в ANSI C++ – по-специално тези отпреди публикуването на стандарта.

Когато се обясняват добавени от стандарта ANSI C++ концепции, които не са включени в по-старите C++ компилатори, до обясненията ще има една от следните икони:

<- ново в ANSI C++

Също така имайки предвид огромната популярност и разпространение, на които се радва езикът C (езикът, от който произлиза C++), ще бъде добавена и икона в случаите, когато се обяснява концепция, чиято имплементация е коренно различна в C и в C++, или пък съществува само в C++.

<- различна имплементация в C и в C++

Компилатори

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

Всички C++ компилатори поддържат компилирането на конзолни програми. За повече информация относно това, как да компилирате примерите от това ръководство, вижте секцията “Компилиране на конзолни програми” в приложението. В него можете да намерите информация за няколко от съществуващите на пазара C++ компилатори.


 

Секция 1.1: C++

Структура на една C++ програма

 

 

 

 

Възможно най-добрият начин да се започне изучаването на един програмен език е да се разгледа проста програма. Така че ето и нашата първа програма:

// моята първа програма на C++
 
#include <iostream.h>
 
main ()
{
  cout << "Hello World!";
  return 0;
}

Hello World!

В лявата част е показан сорс кодът на нашата първа програма, на която може да присвоим произволно име – например hiworld.cpp. В дясната част е показан резултатът от изпълнението на компилираната програма. Начинът за компилиране на една програма зависи от компилатора, който използвате, от това, дали има интегрирана среда за разработка, както и от неговата версия. Вижте секцията “Компилиране на конзолни програми” в приложението, както и учебника или помощното ръководство, включени във вашия компилатор, ако имате съмнения относно това, как да компилирате C++ програма.

Предишната програма е първата програма, която се пише от повечето начинаещи програмисти, и нейният резултат е отпечатването на екрана на изречението “Hello World” (“Здравей свят”). Това е една от най-простите възможни програми, които могат да бъдат написани на C++, но тя все пак включва основните компоненти, които трябва да притежава всяка C++ програма. Нека ги разгледаме един по един:

// моята първа програма на C++

Това е ред с коментар. Всички редове, които започват с две наклонени черти (//), се приемат за коментари и не оказват влияние на поведението на програмата. Те могат да се използват от програмиста за включване на обяснения и наблюдения в рамките на сорс кода на програмата. В нашия случай редът представлява кратко обяснение за работата на програмата.

#include <iostream.h>

Изреченията, които започват с диез (#) представляват директиви на препроцесора. Това не са изпълними редове с код, а указания за компилатора. В този случай изразът #include <iostream.h> казва на препроцесора на компилатора да включи библиотеката iostream. Това е стандартната библиотека за вход/изход на C++. Тя трябва да бъде включена, защото се използва по-късно в програмата. Това е класическият начин за включване на C++ библиотеката iostream.

main ()

Този ред представлява началото на декларацията на функцията main. Функцията main е точката, от която всички C++ програми започват своето изпълнение. Без значение къде се намира (в началото, в края или в средата на кода), при стартирането на програмата първо се изпълнява нейното съдържание. Поради тази причина е задължително всяка C++ програма да има функция main.

След main има две скоби (), защото това е функция. В C++ всички функции са следвани от две скоби (), между които може да има параметри. Съдържанието на функцията main се намира веднага след нейната формална декларация и е обградено с фигурни скоби ({}), също както в нашия пример.

cout << "Hello World";

Тази инструкция извършва най-важното нещо в нашата програма. cout е стандартният поток за изход в C++ (екрана), както е дефиниран в библиотеката iostream. Това, което тази инструкция прави, е да изпрати низа от знаци “Hello World” на този поток (екрана).

Забележете, че изразът завършва с точка и запетая (;). Този знак означава край на инструкцията и трябва да се поставя след всяка инструкция, която включвате в дадена C++ програма (всъщност една от най-често срещаните грешки на C++ програмистите е да забравят да сложат точка и запетая в края на някоя инструкция).

return 0;

Инструкцията return кара функцията main() да приключи и да върне кода, който следва след инструкцията – в този случай 0. Това е нормалното завършване на една програма, която не е намерила грешки по време на своето изпълнение. В следващите примери ще видите, че това е обичайният начин за приключване на C++ програма.

И така, сигурно сте забелязали, че не всички редове от тази програма извършват някакво действие. Има редове, съдържащи само коментари (тези, които започват с //), редове с инструкции за препроцесора на компилато­ра (тези, които започват с #), редове, иницииращи декларация на функция (в този случай функцията main ) и накрая редове с инструкции (като извикването на cout <<), които бяха включени във фигурните скоби ({}) на функцията main.

Програмата беше подредена на различни редове, за да бъде по-лесна за четене, но това не е задължително. Например вместо

main ()
{
  cout << “ Hello World “;
  return 0;
}

бихте могли да напишете:

main () { cout << “ Hello World “; return 0; }

което има абсолютно същото значение.

В C++ разграничаването на инструкциите се определя от крайната точка и запетая (;). Разделянето на кода на различни редове се използва за по-лес­но четене и по-голяма схематичност.

Ето една програма с повече инструкции:

// моята втора програма на C++
#include <iostream.h>
main ()
{
  cout << “Hello World! “;
  cout << “I'm a C++ program”;
  return 0;
}

Hello World!
I'm a C++ program

В този случай използвахме конструкцията cout << в две различни инструкции. Отново е направено разделяне на различни редове за по-лесно четене на програмата. Функцията main би могла да бъде дефинирана идеално и по-следния начин:

main () { cout << “ Hello World! “; cout << “ I'm a C++ program “; return 0; }

Бихме могли също така да разделим кода и на повече редове, ако считаме това за нужно:

main ()
{
  cout <<
    “Hello World!”;
  cout
    << “I'm a C++ program”;
  return 0;
}

като резултатът ще бъде абсолютно същият, както и в предишните примери.

Директивите на препроцесора (тези, които започват с #) не се подчиняват на тези правила, тъй като те не са чисти инструкции. Това са редове, които се прочитат и обработват от препроцесора, като накрая не произвеждат никакъв код. Те трябва да са указани на свой собствен ред и не изискват точка и запетая (;) в края на реда.

Коментари

Коментарите са парчета сорс код, които компилаторът премахва от кода. Те служат само за да може програмистът да слага бележки или описания в части от програмата.

C++ поддържа два начина за отбелязване на коментари:

// коментар за ред
/* коментарът за блок */

При първия начин коментарът за ред отменя кода от двете наклонени черти (//) до края на реда. При втория начин коментарът за блок започва от първите символи /* и свършва при първото появяване на други символи */, като е възможно да се включат няколко реда.

Ще добавим коментари в нашата втора програма:

/* моята втора програма на C++ с 
повече коментари
*/
 
#include <iostream.h>
 
main ()
{
  cout << “Hello World! “;     
// казва Hello World!
  cout << “I'm a C++ program”; 
// казва I'm a C++ program
  return 0;
}

Hello World!
I'm a C++ program

Ако включите коментари в сорс кода на вашите програми, без да използвате символите за коментар //, /* или */, компилаторът ще ги приеме като C++ инструкции и най-вероятно ще покаже едно или повече съобще­ния за грешка.


                                                                                                

Секция 1.2: C++

Променливи. Типове данни. Константи.

 

 

 

Ползата от програмата “Hello World” е повече от съмнителна, след като трябваше да напишем няколко реда с код, да ги компилираме и да изпълним готовата програма, само за да получим като резултат една фраза на екрана. Това е така, но програмирането не се ограничава само с отпечатването на текст на екрана – нещо, което бихме могли да извършим по-бързо и сами. За да напреднем малко и за да можем да пишем програми, изпълняващи полезни задачи, които действително ни спестяват работа, ще трябва да въведем понятието променлива (variable).

Нека си представим, че ви помоля да запазите числото 5 във вашата умствена памет и след това ви помоля да запомните също така и числото 2. Току-що запазихте две числа във вашата памет. Сега ако ви помоля да добавите 1 към първото число, което казах, трябва да запазите числата 6 (т.е. 5+1) и 2 във вашата памет. Сега можем да извадим тези стойности и като резултат да получим 4.

Всичките действия, които направихте, приличат на тези, които компютърът е способен да извършва с две променливи. Този процес може да бъде изразен в C++ със следния набор от инструкции:

a = 5;
b = 2;
a = a + 1;
result = a - b;

Очевидно това е много прост пример, понеже в него използвахме две мал­ки цели числа, но имайте предвид, че компютърът може да съхранява едновременно няколко милиона подобни числа, с които може да извършва сложни математически операции.

И така, можем да дефинираме променливата като част от паметта за съхраняване на определена стойност.

Всяка променлива се нуждае от идентификатор, който да я отличава от другите – например в предишния код идентификаторите на променливите бяха a, b и result, но бихме могли да ги наречем както си поискаме, те пак щяха да са валидни идентификатори.

Идентификатор

Валиден идентификатор е последователност от една или повече букви, цифри или символи за подчертаване ( _ ). Дължината на един идентификатор не е ограничена, независимо че за някои компилатори само първите 32 знака на идентификатора имат значение (останалите не се вземат под внимание).

Идентификаторът не може да съдържа интервали, както и някои определени символи. Валидни са само букви цифри или символи за подчертаване ( _ ). В допълнение на това идентификаторите за променливи трябва да започват с буква. Те могат да започват и със символи за подчертаване ( _ ), но обикновено това се прави за външни връзки. В никакъв случай идентификаторите не могат да започват с цифра.

Друго правило, което трябва да имате предвид, когато започнете да измисляте свои собствени идентификатори, е, че те не трябва да съвпадат нито с ключовите думи на езика, нито с тези на компилатора, тъй като това може да доведе до объркване. Следващите изрази винаги се приемат за ключови думи според стандарта ANSI C++ и следователно не трябва да се използват за идентификатори:

asm, car, bool, break, marry, catch, to char, class, const, const_cast, continue, default, delete, do, double, dynamic_cast, else, enum, explicit, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, operator, private, protected, public, to register, reinterpret_cast, return, short, signed, sizeof, static, static_cast, struct, switch, template, this, throw, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volatile, wchar_t

Освен това не трябва да се използват за идентификатори и алтернативните представяния на някои оператори, тъй като при някои обстоятелства те са запазени ключови думи:

and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq

Вашият компилатор също така може да включи някои запазени ключови думи. Например много компилатори, които генерират 16-битов код (като например някои компилатори за DOS) включват ключовите думи far, huge и near.

Важно:   Езикът C++ е чувствителен към регистъра (горен или долен) на буквите, което означава че един идентификатор, който е написан с големи букви, не е еквивалентен на друг със същото име, но написан с малки бук­ви. Например променливата RESULT не е същата като променливата result, нито като Result.

Типове данни

Когато програмираме, ние съхраняваме променливите в паметта, но компютърът трябва да знае какво искаме да съхраняваме в нея, защото за съх­раняването на просто число, буква или голямо число се изисква различно количество памет.

Паметта на нашия компютър е организирана в байтове. Байтът е минималното количество памет, с което можем да работим. Един байт може да съхранява сравнително малко информация, като например цяло число от 0 до 255 или един знак. В допълнение на това компютърът може да работи с по-сложни типове данни, като големи числа и числа с плаваща запетая, които се формират, като се групират няколко байта. По-долу е показан списък на основните типове данни в C++, както и диапазона от стойности, който може да бъде представен от тях:

Типове данни

Име

Байтове

Описание

Диапазон

char

1

знак или цяло число с
дължина 8 бита.

със знак (signed): от -128 до 127
без знак (unsigned): от 0 до 255

short

2

цяло число с дължина
16 бита.

със знак: от -32763 до 32762
без знак: от 0 до 65535

long

4

цяло число с дължина
32 бита.

със знак: от -2147483648 до 2147483647
без знак: от 0 до 4294967295

int

*

Цяло число. Неговата дължина зависи от дължината на типа Word на системата, която в MSDOS е 16 бита, докато в 32-битовите системи (като Windows 9x/2000/ NT и системи, работе­щи в защитен режим в x86 системи) дължината е 32 бита, а в 64-битовите системи е 64.

Вижте short, long

float

4

число с плаваща запетая.

3.4e + / - 38 (7 цифри)

double

8

число с плаваща запетая с двойна точност.

1.7e + / - 308 (15 цифри)

long double

10

long число с плаваща
запетая с двойна точност.

1.2e + / - 4932 (19 цифри)

bool

1

Булева стойност. Това е най-скоро добавеният от ANSI C++ стандарта тип данни. Ето защо не всеки компилатор го поддържа. Вижте сек­цията “Типът bool” за информация относно съвместимостта.

true или false

Освен тези основни типове данни има още два типа спецификации за параметър: указатели и void, които ще разгледаме по-късно.

Деклариране на променливи

За да можем да използваме една променлива в C++, трябва първо да я декларираме, като определим някой от по-горните типове, от който искаме да бъде тя. За тази цел трябва само да напишем спецификатора за типа данни, който ни е нужен (като int, short, float...), следван от валиден идентификатор за променлива. Например

int a;
float mynumber;

представляват възможни декларации на валидни променливи. Първата декларира променлива от тип int с идентификатор a. Втората декларира променлива от тип float с идентификатор mynumber. След като веднъж са декларирани, променливите a и mynumber могат да се използват в рамките на областта на тяхната видимост в програмата.

Ако трябва да декларирате няколко променливи от един и същи тип и искате да си спестите малко писане, можете да ги декларирате всичките на един ред, като разделяте идентификаторите със запетаи. Например:

int a, b, c;

декларира три променливи от тип int (a, b и c) и има абсолютно същото значение като:

int a;
int b;
int c;

Целочислените типове данни (char, short, long и int) могат да бъдат signed (със знак) или unsigned (без знак) в зависимост от диапазона от стойности, от които се нуждаем. За да определим подобен целочислен тип данни, трябва да поставим ключовата дума signed или unsigned пред самия тип данни. Например:

unsigned short NumberOfSons;
signed int MyAccountBalance;

По подразбиране, ако не определим нито signed, нито unsigned, то типа се приема за signed, така че бихме могли да напишем втората декларация по следния начин:

int MyAccountBalance

с точно същото значение. Това е и най-популярната декларация, като в действителност много рядко в сорс кодовете се включва ключовата дума signed.

Единственото изключение от това правило е типът char, който съществува сам по себе си и е определен от ANSI C++ като различен тип от signed char и unsigned char.

За да видите как изглежда една декларация в действаща програма, ще разгледаме C++ кода на примера за вашата мисловна памет, предложен в началото на тази секция:

// работа с променливи
 
#include <iostream.h>
 
main ()
{
  // деклариране на променливи:
  int a, b;
  int result;
 
  // обработка:
  a = 5;
  b = 2;
  a = a + 1;
  result = a - b;
 
  // извеждане на резултата:
  cout << result;
 
  // завършване на програмата:
  return 0;
}

4

Не се притеснявайте, ако някои от декларациите на променливи ви изглеждат малко странно. Ще видите по-подробно нещата в следващите секции.

Инициализация на променливи

Когато се декларира една променлива, по подразбиране нейната стойност е неопределена. Вие обаче може да искате променливата да съхранява конкретна стойност, когато я декларирате. За тази цел към декларацията на променливата трябва да добавите знак за равенство и стойността, която желаете:

тип идентификатор = първоначална_стойност;

Например ако искаме да декларираме int променлива с име a, която да съдържа стойност 0 от момента, в който е декларирана, можем да напишем:

int a = 0;

В допълнени на този приличащ на C начин за инициализиране на променливи, в C++ е добавен нов начин за тяхната инициализация, при който началната стойност се поставя в скоби ():

тип идентификатор (първоначална_стойност);

Например:

int a (0);

И двата начина са позволени в C++.

Област на видимост на променливите

Всички променливи, които ще използваме, трябва първо да се декларират. Важна разлика между езиците C++ и C е, че в C++ можем да декларираме променливи на всяко място от програмата, дори между изпълними изрази, а не само в началото на даден блок с инструкции, както това е в C.

Но дори при това положение е препоръчително да се следват указанията на езика C при декларирането на променливи, тъй като това може да ви бъде от полза, когато дойде време за коригиране на програмата. И така, традиционният C начин за деклариране на променливи е техните декларации да се поставят в началото на всяка функция (локални променливи) или директно в тялото на програмата, извън функциите (глобални променливи).

Глобалните променливи могат да бъдат извиквани от всяка част на кода, дори от функции, независимо от мястото на тяхното деклариране.

Областта на видимост на локалните променливи е ограничена от кодовото ниво, в което са декларирани. Ако са декларирани в началото на функция (както в main), тяхната област на видимост е цялата функция main. Това означава, че ако в горния пример освен функцията main() съ­ществуваше и друга функция, то декларираните в main локални променливи нямаше да могат да се използват в другата функция, и обратното.

Освен локалната и гло­балната област на види­мост съществува и външна област на видимост, която позволява на дадена променлива да се вижда не само в същия сорс файл, но и във всички други архиви, с които е свързана.

В C++ областта на ви­димост на една про­менли­ва е зададена в блока, в който е била декларирана (блокът представлява група от инструкции, ог­раничени между фигурни скоби {}). Ако променливата е декларирана в дадена функция, нейната област на видимост ще бъде функцията, ако е декларирана в цикъл, областта ще е цикълът, и т.н 

Константи: литерални

Константата е произволен израз с фиксирана стойност, като :

Цели числа

1776
707
-273

Те са числени стойности, които определят цели десетични числа. Обърнете внимание, че за изразяването на числова константа не трябва да пишем (") или друг специален символ. Няма съмнение, че това е константа: където и в програмата да включим 1776, ние ще имаме предвид стойността 1776.

В допълнение на десетичните числа (тези, които всички ние познаваме) C++ позволява използването на литерални константи за осмични (с основа 8) и шестнайсетични (с основа 16) числа. За да изразим едно осмично число, трябва да поставим знак 0 (знак за нула) пред него. А за да изразим едно шестнайсетично число, пред него трябва да поставим знаците 0x. Например следващите литерални константи са еквивалентни една на друга:

75         // десетично
0113       // осмично
0x4b       // шестнайсетично

Всички те представят едно и също число: 75 (седемдесет и пет), изразено съответно с основа 10, 8 и 16.

[Забележка:  Можете да намерите повече информация за осмичните и шестнайсетичните представяния в секцията “Числови основи” на приложението към книгата.]

Числа с плаваща запетая
Те изразяват числата с десетици и/или експонента. Тези числа могат да включват точка за десетична запетая, знака
e (който изразява “по десет на степен ...”) или и двете.

3.14159    // 3.14159
6.02e23    // 6.02 x 1023
1.6e-19    // 1.6 x 10-19
3.0        // 3.0

Това са четири валидни числа с десетици, изразени в C++. Първото число е PI, второто е числото на Авогадро, третото е електрическият заряд на един електрон (изключително малко число) – всички са с приближение – а последното е числото 3,изразено като число с плаваща запетая.

Знаци и низове
Съществуват и не-числови константи, като:

'z'
'p'
"Hello world"
"How do you do?"

Първите два израза представят отделни знаци, оградени с единични кавички ('), а следващите два представят низове от по няколко знака, поставени между двойни кавички (").

Когато отделните знаци и низовете от знаци се представят като константи, трябва да се поставят знаци за кавички, за да бъдат разграничени от възможни идентификатори на променливи или запазени думи. Забележете следното:

x
'x'

x се отнася за променливата x, докато 'x' се отнася за знаковата константа 'x'.

Знаковите и низовите константи имат някои особености, като например escape кодовете. Това са специални символи, които не могат да бъдат изразени по друг начин в сорс кода на дадена програма – например нов ред (\n) или табулация (\t). Всичките започват с обратно наклонена черта (\). Ето списък на подобни escape кодове:

\n

нов ред

\r

връщане на каретката

\t

табулация

\v

вертикална табулация

\b

backspace

\f

нова страница

\a

аларма

\'

единични кавички (')

\"

двойни кавички (")

\

въпросителна (?)

\\

обратно наклонена черта (\)

Например:

'\n'
'\t'
"Left \t Right"
"one\ntwo\nthree"

В допълнение на числовото изразяване на ASCII код, можете да използвате обратно наклонена черта (\), следвана от ASCII кода, изразен в осмичен (основа 8) или шестнайсетичен (основа 16) вид. В първия случай числото трябва да се намира веднага след обратно наклонената черта (например \23 или \40), а във втория трябва да подадете кода в шестнайсетичен вид, като поставите знак x пред числото (например \x20 или \x4A).
[Вижте секцията “
ASCII код” в приложението за повече информация относно този вид escape кодове].

Низовите константи могат да се продължат на повече от един ред, ако всеки ред завършва с обратно наклонена черта (\):

"низ,продължен на\
два реда
"

Можете също така да конкатенирате няколко низови константи, като ги разделите с един или повече интервали, табулации, нови линии или други валидни празни символи:

"ние образуваме" "един " "низ" "от знаци"

Дефинирани константи (#define)

Можете да дефинирате свои собствени имена за константите, които използвате често, без да прибягвате до използването на променливи. Трябва просто да използвате директива #define на препроцесора. Нейният формат е:

#define идентификатор стойност

Например:

#define PI 3.14159265
#define NEWLINE '\n'
#define WIDTH 100

това дефинира три нови константи. От момента на тяхната декларация можете да ги използвате в кода, както всички други константи. Например:

circle = 2 * PI * r;
cout << NEWLINE;

Всъщност единственото нещо, което компилаторът прави, когато открие директива #define, е да замести буквално всяко срещане на елемента (в предишния пример PI, NEWLINE или WIDTH) с константата, с която е дефиниран (съответно 3.14159265, 'n' или 100). Поради тази причина #define константите се разглеждат като константи макроси.

Директивата #define не е кодова инструкция, тя е директива на препроцесора. Ето защо се предполага, че тя заема целия ред и не се нуждае от точка и запетая (;) в неговия край. Ако поставите точка и запетая (;) в края, тя също ще бъде добавена, когато препроцесорът замести всички появявания на дефинираната константа в тялото на програмата.

Декларирани константи (const)

С префикса const можете да декларирате константи от определен тип по същият начин, по който декларирате променливи:

const int width = 100;
const char tab = '\t';
const zip = 12440;

В случай че типът не е определен (както в последния пример), компилаторът предполага, че той е int.


 

Секция 1.3: C++

Оператори

 

 

 

 

След като вече знаем за съществуването на променливите и константите, вече е време да започнем да работим с тях. За тази цел съществуват оператори, които в C++ са запазени думи, и знаци, които не са включени в азбуката, но са в наличност на почти всяка клавиатура на света. Важно е да се познават, тъй като те са основата на езика C++.

Няма нужда да учите наизуст цялото съдържание на тази страница, тъй като подробностите са дадени само за да ви послужат за по-късна справка.

Присвояване (=)

Операторът за присвояване служи за присвояването на стойност на дадена променлива.

      a = 5;

присвоява целочислената стойност 5 на променливата a. Частта отляво на оператора = е известна като lvalue (лява стойност), а тази отдясно като rvalue (дясна стойност). lvalue трябва винаги да е променлива, докато дяс­ната страна може да бъде константа, променлива, резултат от операция или комбинация от тях.

Нужно е да се наблегне върху това, че операцията за присвояване се извършва винаги от дясно на ляво и никога обратно.

a = b;

присвоява на променливата a (lvalue) стойността, която се съдържа в про­менливата b (rvalue), независимо от стойността, която е била съхранена преди това в a. Важно е да отбележим, че в случая само присвояваме стойността на b на a и че последващата промяна на b няма да повлияе на новата стойност на a.

Например ако вземем следния код (с разгръщане на съдържанието на про­менливите, показано в коментарите):

int a, b;    // a:?  b:?
a = 10;      // a:10 b:?
b = 4;       // a:10 b:4
a = b;       // a:4 b:4
b = 7;       // a:4 b:7

като резултат ще получим, че стойността, съдържаща се в a, е 4, а в b е 7. Последната промяна на b не е повлияла на a, въпреки че сме декларирали a = b;.

Свойството на оператора за присвояване в C++, което го отличава от другите програмни езици, е че той може да служи като rvalue (или част от rvalue) за друго присвояване. Например:

a = 2 + (b = 5);

е еквивалентно на :

b = 5;
a = 2 + b;

което означава: първо да се присвои 5 на променливата b и след това на a да се присвои стойността 2 плюс резултата от предишното присвояване на b (т.е. 5), като накрая a остава със стойност 7. Следователно следният израз също е валиден в C++:

a = b = c = 5;

В случая числото 5 се присвоява на трите променливи a, b и c.

Аритметични оператори ( +, -, *, /, % )

Петте аритметични оператора, поддържани от езика, са :

+

събиране

-

изваждане

*

умножение

/

делене

%

модул

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

Единственият оператор, който изглежда малко странно, е модулът, определен със знака за процент (%). Модулът е операция, която дава остатъка от делене на две целочислени стойности. Например ако погледнем израза a = 11 % 3;, то променливата a ще съдържа 2 като резултат, тъй като 2 е остатъкът от 11 делено на 3.

Съставни оператори за присвояване (+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=)

Възможността за определяне, която допринася за славата на C++ като икономичен при писане език, е осигурена от операторите за присвояване (най-вече +=, -=, *= и /=), които ви позволяват да промените стойността на дадена променлива посредством някой от основните оператори:

value += increase; е еквивалентно на value = value + increase;
a -= 5; е еквивалентно на a = a - 5;
a /= b; е еквивалентно на a = a / b;
price *= units + 1; е еквивалентно на price = price * (units + 1);

Същото важи и за останалите съставни оператори за просвояване.

Увеличаване и намаляване

Друг пример за пестеливост при писането на код са операторите за увеличаване (++) и намаляване (--). Те увеличават или намаляват с 1 стойността, съхранена в променливата. Тези оператори са еквивалентни съответно на +=1 и на -=1. Така че:

a++;
a+=1;
a=a+1;

са еквивалентни по своята функция: и трите израза увеличават с 1 стойността на a.

Тяхното съществуване се дължи на факта, че в първите C компилатори трите предишни израза произвеждаха различен изпълним код в зависимост от това, кой от тях се използва.

За този оператор е характерно, че може да бъде префиксен или суфиксен, което означава, че може да бъде написан преди (++a) или след (a++) идентификатора на променливата. Въпреки че в прости изрази като a++ или ++a операторите имат еднакво действие, при други операции, при които резултатът от увеличаването или намаляването се изчислява като друг израз, може да има важна разлика в значенията: В случай че операторът за увеличаване се използва като префиксен (++a), стойността се увеличава преди изчисляването на израза, така че вече увеличената стойност се приема в израза; в случай че той се използва като суфиксен (a++), съхраняваната в a стойност се увеличава след изчисляването и така в израза се използва стойността, съхранена преди изчислението. Забележете разликата:

Пример 1

Пример 2

B=3;
A=++B;
// A е 4, B е 4

B=3;
A=B++;
// A е 3, B е 4

В Пример 1 променливата B е увеличена преди нейната стойност да бъде копирана в A. В Пример 2 стойността B е копирана в A и след това е увеличена.

Оператори за сравнение ( ==, !=, >, <, >=, <= )

За да извършим оценка за сравнение на два израза, можем да използваме операторите за сравнение. Според спецификацията на ANSI C++ стандарта резултатът от операция за сравнение е bool стойност, която може да е само true или false в зависимост от това, дали резултантният израз е верен или неверен.

Може да се наложи да сравняваме два израза, за да знаем например дали са еднакви или единият е по-голям от другия. Ето списък на операторите за сравнение, които можете да използвате в C++:

==

Равно

!=

Различно

>

По-голямо

<

По-малко

>=

По-голямо или равно

<=

По-малко или равно

Ето и няколко примера:

(7 == 5)

ще върне false.

(5 > 4)

ще върне true.

(3 != 2)

ще върне true.

(6 >= 6)

ще върне true.

(5 < 5)

ще върне false.

Разбира се, вместо числа бихме могли да използваме и изрази. Да приемем, че a=2, b=3 и c=6. Тогава

(a == 5)

ще върне false.

(a*b >= c)

ще върне true, тъй като (2*3 >= 6).

(b+4 < a*c)

ще върне false, тъй като (3+4 < 2*6).

((b=2) == a)

ще върне true.

Помнете, че = (един знак за равенство) не е същото като == (два знака за равенство) – първото е оператор за присвояване (присвоява дясната страна на израза на променливата отляво), а второто (==) е оператор за сравнение, който проверява дали изразите от двете му страни са равни един на друг. Следователно в последния израз ((b=2) == a) първо присвоихме на b стойността 2 и след това я сравнихме с a, която също съдържа стойността 2, като резултатът от това действие е true.

В много компилатори, създадени преди публикуването на ANSI C++ стандарта, както и в езика C, операторите за сравнение не връ­щат bool стойност true или false, а връщат int променлива със стойност 0, за да представят “false”, и стойност, различна от 0 (обикновено 1), за да представят true. Ако вашият компилатор не поддържа типа bool, както и за повече информация относно булевите операции вижте секцията “Булева логика” в приложението в края на книгата.

Логически оператори ( !, &&, || )

Операторът ! е еквивалентен на логическия оператор NOT. Той има само един операнд отдясно и единственото нещо, което прави, е да обръща неговата стойност, като го прави false, ако операндът е true, или true, ако операндът е false. Може да се каже, че този логически оператор връ­ща противоположния резултат от изчислението на своя операнд. Например:

!(5 == 5)

връща false, защото изразът отдясно (5 == 5) е true.

!(6 <= 4)

връща true, защото (6 <= 4) е false.

!true

връща false.

!false

връща true.

Логическите оператори && и || се използвате при изчисляването на два израза за получаването на един резултат. Те отговарят на логическите операции AND и OR. Резултатът от тях зависи от връзката между двата операнда:

Първи операнд
a

Втори операнд
b

резултат
a && b

резултат
a || b

true

true

true

true

true

false

false

true

false

true

false

true

false

false

false

false

Например:

( (5 == 5) && (3 > 6) ) връща  false ( true && false ).
( (5 == 5) || (3 > 6) ) връща  true ( true || false ).

Оператор за условие ( ? )

Операторът за условие изчислява даден израз и връща различна стойност в зависимост от това, дали изчисленият израз е true или false. Неговият формат е:

условие ? резултат1 : резултат2

ако условие е true, изразът ще върне резултат1, а ако не е, ще върне резултат2.

7==5 ? 4 : 3

връща 3, тъй като 7 не е равно на 5.

7==5+2 ? 4 : 3

връща 4, тъй като 7 е равно на 5+2.

5>3 ? a : b

връща a, тъй като 5 е по-голямо от 3.

a>b ? a : b

връща по-голямото от a и b.

Побитови оператори ( &, |, ^, ~, <<, >> ).

Побитовите оператори променят променливите, като вземат под внимание битовете, представящи числата в променливите, т.е тяхното двоично представяне.

op

asm

Описание

&

AND

Логическо И

|

OR

Логическо ИЛИ

^

XOR

Логическо изключващо ИЛИ

~

NOT

Допълнение към едно (инвертиране на бит)

<<

SHL

Преместване наляво

>>

SHR

Преместване надясно

За повече информация относно двоичните числа и побитовите операции, вижте секцията “Булева логика” в приложението.

Оператори за явно преобразуване на типове

Операторите за преобразуване на типове ви позволяват да конвертирате данни от даден тип в друг тип. В C++ има няколко начина за това. Най-основният, идващ от езика C начин е пред израза за преобразуване в скоби ()да се постави новият тип, както е в следния пример:

int i;
float f = 3.14;
i = (int) f;

Предишният код преобразува числото с плаваща запетая 3.14 в целочислена стойност (3). В този случай операторът за преобразуване на типове е(int). Друг начин за същото нещо в C++ е да се използват конструктори, вместо оператори: типът се поставя пред израза за преобразуване, а самият израз се поставя в скоби:

i = int ( f );

И двата начина за преобразуване на типове са валидни в C++. В допълнение ANSI C++ въвежда оператори за преобразуване, които са по-специ­фични за обектно-ориентираното програмиране.

sizeof()

Този оператор приема един параметър, който може да е или типа на променливата, или самата променливата, и връща размера в байтове на този тип или обект:

a = sizeof (char);

Това ще върне 1 в a, защото char по принцип е с дължина един байт във всички системи.
Връщаната от
sizeof стойност е константа, така че тя винаги се определя преди изпълнението на програмата.

Други оператори

По-нататък ще разгледаме още няколко оператора, отнасящи се за указатели, както и специфични за обектно-ориентираното програмиране оператори, които се разглеждат в съответните секции.

Приоритет на операторите

При изграждането на сложни изрази с няколко операнда могат да се появят съмнения относно реда на тяхното изчисляване. Например в следващия пример:

a = 5 + 7 % 2

може да се съмняваме дали това наистина означава:

a = 5 + (7 % 2) с резултат 6 или
a = (5 + 7) % 2 с резултат 0

Верният отговор е първият от двата израза с резултат 6. За тази цел е установен ред с приоритети за всеки оператор, при това не само за аритметичните (тези, които познавате от математиката), а за всички оператори, които могат да се появят в C++. Редът на приоритетите от най-високия към най-ниския е следният:

Приоритет

Оператор

Описание

Асоциативност

1

::

област на видимост

лява

2

() [ ] -> . sizeof

 

лява

3

++ --

увеличаване/намаляване

дясна

~

допълнение към едно
(побитово)

!

унарно НЕ (NOT)

& *

извличане на адрес и
стойност (указатели)

(тип)

преобразуване на тип

+ -

унарен знак за по-малко

4

* / %

аритметични операции

лява

5

+ -

аритметични операции

лява

6

<< >>

побитово преместване

лява

7

< <= > >=

оператори за сравнение

лява

8

== !=

оператори за сравнение

лява

9

& ^ |

побитови оператори

лява

10

&& ||

логически оператори

лява

11

?:

условие

лява

12

= += -= *= /= %=
>>= <<= &= ^= |=

присвояване

дясна

13

,

запетая, разделител

лява

Асоциативността се дефинира за случаите, когато има няколко оператора с едно и също ниво на приоритет. Тя определя кой трябва да бъде изчислен пръв –най-левият или най-десният.

Всички тези нива за приоритет на операторите могат да бъдат избегнати и направени по-лесни за четене, като се използват скоби “(“ и”)”. Например изразът:

a = 5 + 7 % 2;

може да бъде записан като:

a = 5 + (7 % 2);  или
a = (5 + 7) % 2;

в зависимост от операцията, която искаме да извършим.

Ето защо, ако искате да пишете усложнени изрази и не сте сигурни за реда на приоритетите, винаги слагайте скоби. По този начин и кодът ще бъде по-лесен за четене.


 

Секция 1.4: C++

Комуникация чрез конзолата

 

 

 

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

В C++ библиотеката iostream стандартният вход и изход за една програма се поддържа от два потока данни: cin за вход и cout за изход. Освен това са имплементирани и cerr и clog - два потока, проектирани специално за показване на съобщения за грешки, които могат да бъдат насочвани към стандартния изход (обикновено екрана) или към log (отчетен) файл.

Ето защо cout (потокът за стандартен изход) обикновено се насочва към екрана, а cin (потокът за стандартен вход) обикновено се присвоява на клавиатурата.

Работейки с тези два потока ще имате възможност да взаимодействате с потребителя на вашата програма, тъй като ще можете да показвате съобщения на екрана и да получавате неговия/нейния вход от клавиатурата.

Изход (cout)

Потокът cout се използва съвместно с предефинирания оператор << (два знака за “по-малко”).

cout << "Изходно изречение"; // печата изходно изречение 
                                
на екрана
cout << 120;             // печата числото 120 на екрана
cout << x;               // печата съдържанието на 
                            променливата x на екрана

Операторът << се нарича оператор за вмъкване (insertion operator), тъй като вмъква намиращите се след него данни в потока, който стои пред него. В по-горните примери той вмъква константния низ Изходно изречение, цифровата константа 120 и променливата x в потока cout. Обърнете внимание, че първото изречение е поставено в двойни кавички ("), понеже е низ от знаци. Винаги, когато искаме да използваме константни низове, трябва да ги поставяме между двойни кавички ("), за да могат да бъдат ясно разграничени от променливите. Например следните два израза са коренно различни:

cout << "Hello";      // печата Hello на екрана
cout << Hello;        // печата съдържанието на 
                        
променливата Hello на екрана

Операторът за вмъкване (<<) може да се използва повече от един път в един и същ израз:

cout << "Hello, " << "I am " << "a C++ sentence";

Този израз ще изведе на екрана съобщението Hello, I am a C++ sentence. Ползата от повтарянето на оператора за вмъкване (<<) се вижда ясно, когато искаме да изведем комбинация от променливи и константи или повече от една променлива:

cout << "Здрасти, аз съм на " << age << " години и моят код е " << zipcode;

Ако предположим, че променливата age съдържа числото 6, а променливата zipcode съдържа 12032, то изходът от предния израз ще бъде:

Здрасти, аз съм на 6 години и моят код е 12032

Важно е да се подчертае, че cout не добавя прескачане на нов ред след своя изход, така че следните изрази:

cout << "Това е изречение.";
cout << " Това е друго изречение.";

ще се покажат на екрана по следния начин:

Това е изречение. Това е друго изречение.

дори да сме ги написали в две различни извиквания на cout. Така че, за да може изходът на екрана да направи прескачане на нов ред, трябва явно да му зададем знак за нов ред, който в C++ може да бъде написан като \n:

cout << "Първо изречение.\n ";
cout << "Второ изречение.\nТрето изречение.";

което предизвиква следния изход:

Първо изречение.
Второ изречение.
Трето изречение.

Вместо да добавяте знак за нов ред, можете да използвате манипулатора endl. Например:

cout << " Първо изречение." << endl;
cout << " Второ изречение." << endl;

ще отпечата:

Първо изречение.
Второ изречение.

Манипулаторът endl има специално поведение, когато се използва с буферирани потоци: те се изпразват. Но както и да е, cout по подразбиране не е буфериран.

Можете да използвате или escape знака \n, или манипулатора endl, за да зададете на cout прескачане на нов ред. Обърнете внимание на различията при използване на двата метода, показани по-рано.

Вход (cin)

Работата със стандартния вход в C++ се осъществява с помощта на преде­финирания оператор за извличане (extraction) (>>) и потока cin. Той трябва да бъде следван от променлива, която ще съхранява прочетените данни. Например:

int age;
cin >> age;

декларира променливата age като int и след това чака за вход от cin (клавиатурата), за да го съхрани в тази целочислена променлива.

cin може да обработва входа от клавиатурата само след като се натисне клавишът ENTER. Ето защо, въпреки че искате само един знак, cin няма да обработи входа, докато потребителят не натисне ENTER, след като е въвел знака.

Трябва винаги да имате в предвид какъв е типът на променливата, която използвате като контейнер за cin. Ако искате цяло число, cin ще върне цяло число, ако искате character, ще върне character, а ако искате низ от знаци, ще върне низ от знаци.

// пример за вход/изход
#include <iostream.h>
 
main ()
{
  int i;
  cout << "Моля, въведете цяло 
       
число: ";
  cin >> i;
  cout << "Числото, което 
        въведохте, е " << i;
  cout << ", а умножено по 2 е" 
        << i*2 << ".\n";
  return 0;
}

Моля, въведете цяло
число: 702
Числото, което въведохте, е 702, а умножено по 2 е 1404.

Потребителят на програмата може да е един от източниците на грешки в най-простите програми, които използват cin (като тази, която току-що видяхте). Например ако искате целочислена стойност, а потребителят въведе своето име (което е низ от знаци), резултатът може да накара вашата програма да извърши грешни действия, тъй като това, което очакваме от потребителя, не е вярно. Ето защо, когато използвате вход за данни, предоставен от cin, ще трябва да се надявате, че потребителят ще съдейства напълно на вашата програма и няма да въведе своето име вместо исканата целочислена стойност. По-нататък, когато разгледаме как се използват низове от знаци, ще видите възможните решения за грешките, които могат да бъдат предизвикани от подобен вход на потребителя.

Можете също така да използвате cin, за да искате от потребителя повече от едно въвеждане на данни:

cin >> a >> b;

е еквивалентно на:

cin >> a;
cin >> b;

И в двата случая потребителят трябва да предостави две данни: една за променливата a и една за променливата b. Те могат да бъдат разделени с произволен празен разделител: интервал, знак за табулация или нов ред.