C++
C++ (Сі++) — кампіляваная статычна тыпізаваная мова праграмавання агульнага прызначэння. Падтрымлівае розныя парадыгмы праграмавання, але, у параўнанні са сваёй папярэдніцай мовай Сі, найбольшая ўвага скіравана на падтрымку аб’ектна-арыентаванага і абагульненага праграмавання.[1] Назва «C++» паходзіць ад назвы мовы Сі (C), у якой унарны (аднамесны) аператар У 1990-х гадах мова стала адной з самых ўжывальных моў праграмавання агульнага прызначэння. Пры стварэнні C++ імкнуліся захаваць сумяшчальнасць з мовай Сі. Большасць праграм на Сі можна, амаль не змяняючы, сабраць і з дапамогай кампілятара C++. Мова C++ мае сінтаксіс, заснаваны на сінтаксісе Сі. ГісторыяМова з’явілася напачатку 1980-х гадоў, калі супрацоўнік фірмы Bell Laboratories Б’ёрн Страўструп прыдумаў шэраг удасканаленняў да мовы Сі пад уласныя патрэбы. Да пачатку афіцыйнай стандартызацыі мова развівалася галоўным чынам сіламі Страўструпа ў адказ на запыты праграмісцкай супольнасці. У 1998 годзе быў прынят міжнародны стандарт мовы C++: ISO/IEC 14882:1998 «Standard for the C++ Programming Language»; пасля прыняцця тэхнічных выпраўленняў да стандарту ў 2003 годзе — цяперашняя версія гэтага стандарту — ISO/IEC 14882:2003. Раннія версіі мовы, вядомыя пад назвай «C з класамі», пачалі з’яўляцца ў 1980-я гады.[2] Ідэя стварэння новай мовы бярэ пачатак з доследаў Страўструпа ў праграмаванні падчас працы над дысертацыяй. Ён выявіў, што мова мадэлявання Сімула (Simula) мае такія магчымасці, якія былі б вельмі карыснымі пры распрацоўцы вялікага праграмнага забеспячэння, але працуе занадта павольна. У той жа час мова BCPL даволі хуткая, але занадта блізкая да моў нізкага ўзроўню і не падыходзіць для распрацоўкі вялікага праграмнага забеспячэння. Страўструп пачаў працаваць у Bell Labs над задачамі тэорыі чэрг (у прыкладаннях да мадэлявання тэлефонных выклікаў). Спробы прымяніць існаваўшыя ў той час мовы мадэлявання засталіся безвыніковымі. Успомніўшы доследы са сваёй дысертацыі, Страўструп вырашыў дапоўніць мову Сі (пераемніцу BCPL) магчымасцямі мовы Сімула. Мова Сі, якая была асноўнай мовай сістэмы UNIX, на якой працавалі камп’ютары Bell, хуткая, шматфункцыянальная і пераносная. Страўструп дадаў да яе магчымасць працы з класамі і аб’ектамі. У выніку, практычныя задачы мадэлявання сталі даступнымі для развязання як з пункту гледжання часу распрацоўкі (дзякуючы выкарыстанню Сімула-падобных класаў) так і з пункту гледжання часу вылічэнняў (дзякуючы хуткадзеянню Сі). Напачатку ў Сі былі ўключаны класы (з інкапсуляцыяй), вытворныя класы, строгая праверка тыпаў, inline-функцыі і аргументы па змаўчанні. Распрацоўваючы Сі з класамі (пазней C++), Страўструп таксама напісаў праграму cfront — транслятар, які перакладаў зыходны код Сі з класамі у зыходны код звычайнай Сі. Новая мова, нечакана для аўтара, набыла вялікую папулярнасць сярод калег, і неўзабаве Страўструп ужо не мог падтрымліваць яе асабіста, адказваючы на тысячы пытанняў. У 1983 годзе адбылося перайменаванне мовы з Сі з класамі у C++. Акрамя таго, у яе былі ўключаны новыя магчымасці, такія як віртуальныя функцыі, перагрузка функцый і аператараў, спасылкі, канстанты (сталыя), карыстальніцкі кантроль над кіраваннем свабоднай памяццю, палепшаная праверка тыпаў і новы стыль каментарыяў ( Развіццё і ўпарадкаванне мовыУ 1985 годзе выйшла першае выданне кнігі «Мова праграмавання C++», першае апісанне гэтай мовы, што было надзвычай важным з-за адсутнасці афіцыйнага стандарту. У 1989 годзе адбыўся выхад C++ версіі 2.0. Яго новыя магчымасці ўключалі множнае наследаванне, абстрактныя класы, статычныя функцыі-члены, функцыі-канстанты і ахаваныя члены. У 1990 годзе выйшла «Каментаванае даведачнае кіраўніцтва па C++», якое пасля легла ў аснову стандарту. Апошнія абнаўленні ўключалі шаблоны, выключэнні, прасторы імён, новыя спосабы прывядзення тыпаў і булеўскі тып. Стандартная бібліятэка мовы C++ таксама развівалася разам з ёю. Першым дабаўленнем к стандартнай бібліятэцы C++ сталі патокі ўводу/вываду, якія даюць сродкі для замены традыцыйных функцый Сі У 1998 годзе, пасля некалькіх гадоў працы, сумесны камітэт ANSI-ISO прыняў стандарт мовы C++ (ISO/IEC 14882:1998 — Мова праграмавання C++). На працягу некалькіх гадоў пасля афіцыйнага выхаду стандарту камітэт апрацоўваў паведамленні пра памылкі і ў выніку выпусціў выпраўленую версію стандарту C++ у 2003 годзе. У наш час працоўная група МОС (ISO) працуе над новай версіяй стандарту пад кодавай назвай C++09 (раней вядомы як C++0X), які павінен выйсці ў 2009 годзе.
Гісторыя назвыНазва «C++» была прыдумана Рыкам Масіцці (Rick Mascitti) і ўпершыню была выкарыстана ў снежні 1983 года. Раней, на ступені распрацоўкі, новая мова называлася «Сі з класамі».[2] Імя, атрыманае ў выніку, паходзіць ад аператара мовы Сі «++» (павелічэнне значэння зменнай на адзінку). Імя «C+» не было выкарыстана таму, што з’яўляецца сінтаксічнай памылкай у Сі і, акрамя таго, гэта імя было занята іншай мовай. Мова таксама не названа «D», бо «з’яўляецца пашырэннем Сі і не спрабуе здымаць праблемы шляхам выдалення элементаў Сі».[2] Філасофія C++У кнізе «Дызайн і эвалюцыя C++» Б’ёрн Страуструп апісвае прынцыпы, якіх ён прытрымліваўся пры распрацоўцы мовы C++.[3] Гэтыя прынцыпы тлумачаць, чаму C++ менавіта такая, якой яна ёсць. Некаторыя з іх:
Агляд мовыСтандарт C++ на 1998 год складаецца з дзвюх асноўных частак: ядра мовы і стандартнай бібліятэкі. Стандартная бібліятэка C++ увабрала ў сябе бібліятэку шаблонаў STL, якая распрацоўвалася адначасова са стандартам. Цяпер назва STL афіцыйна не ўжываецца, аднак у кругах праграмістаў на C++ і ў навучанні гэта назва выкарыстоўваецца для пазначэння часткі стандартнай бібліятэкі, якая змяшчае азначэнні шаблонаў кантэйнераў, ітэратараў, алгарытмаў і функтараў. Стандарт C++ утрымоўвае нарматыўную спасылку на стандарт Сі ад 1990 года і не вызначае самастойна тыя функцыі стандартнай бібліятэкі, якія пазычаны са стандартнай бібліятэкі Сі. Акрамя таго, існуе велізарная колькасць бібліятэк C++, якія не ўваходзяць у стандарт. У праграмах на C++ можна выкарыстоўваць шматлікія бібліятэкі Сі. Мова праграмавання C++ вызначана стандартам, аднак за гэтай назвай могуць хавацца таксама няпоўныя, абмежаваныя, дастандартныя адмены мовы. Напачатку свайго існавання мова развівалася па-за фармальнымі рамкамі, адказваючы на задачы, якія ставіліся перад ёю. Развіццю мовы спадарожнічала развіццё крос-кампілятара cfront. Змены і новыя ўласціваці ў мове адлюстроўваліся ў змене нумара версіі крос-кампілятара. Гэтыя нумары версій крос-кампілятара распаўсюджваліся і на саму мову. Аднак цяпер звычайна пра версіі мовы C++ не кажуць. Новыя магчымасці ў параўнанні з СіНоваўвядзеннямі C++ у параўнанні з Сі з’яўляюцца:
Мова C++ шмат у чым з’яўляецца надмноствам Сі. Новыя магчымасці C++ уключаюць аб’яўленні ў выглядзе выразаў, пераўтварэнні тыпаў у выглядзе функцый, аператары У C++ з’явіліся каментары ў выглядзе падвойнай касой рысы ( Некаторыя асаблівасці C++ пазней былі перанесены ў Сі, напрыклад ключавыя словы Магчымасці, не звязаныя з ААПУ гэтым раздзеле апісваюцца магчымасці, непасрэдна не звязаныя з аб’ектна-арыентаваным праграмаваннем (ААП). Аднак, многія з іх набываюць асаблівую важнасць іменна ў спалучэнні з ААП.
Аператар
void Print(int x);
void Print(double x);
void Print(int x, int y);
struct Date {int day, month, year;};
void operator ++(struct Date& date);
Аператары нічым не адрозніваюцца ад звычайных функцый (па сутнасці, аператар ёсць функцыяй, і ўсе адрозненні складаюцца ў тым, як выглядае выклік аператара ў зыходным кодзе). Аднак існуе шэраг абмежаванняў на перагрузку аператараў: нельга перагружаць аператары над прадвызначанымі (убудаванымі) тыпамі (скажам, пераазначаць множанне цэлых лікаў тыпу
namespace Foo {
const int x=5;
typedef int** T;
void f(y) {return y*x};
double g(T);
...
}
то па-за фігурнымі дужкамі мы павінны звяртацца да T, x, f, g як Foo::T, Foo::x, Foo::f, Foo::g. Калі мы ў нейкім файле жадаем звяртацца да іх непасрэдна, мы можам напісаць using namespace Foo;
або using Foo::T;
Прасторы імён патрэбны, каб не ўзнікала накладак паміж пакетамі, якія маюць глабальныя зменныя, функцыі ці тыпы з аднолькавымі імёнамі. Адмысловым выпадкам з’яўляецца безыменная прастора імён namespace {
...
}
Усе імёны, азначаныя ў ёй, даступныя толькі ў бягучай адзінцы трансляцыі і больш нідзе.
struct Time {
int hh, mm, ss;
};
Time t1, t2;
struct S {
typedef int** T;
T x;
};
S::T y;
Аб’ектна-арыентаваныя асаблівасці мовыМова C++ дадае да Сі аб’ектна-арыентаваныя магчымасці. Яна уводзіць класы, якія забяспечваюць тры самыя важныя уласцівасці ААП: інкапсуляцыю, наследаванне і полімарфізм. Існуе два значэнні слова клас. У шырокім сэнсе клас — гэта карыстальніцкі тып, аб’яўлены з выкарыстаннем аднаго з ключавых слоў Інкапсуляцыя (абарона даных)Асноўным спосабам уладкавання інфармацыі ў мове C++ з’яўляюцца класы. У адрозненне ад тыпу структура ( З адкрытымі членамі класа можна рабіць ўсё, што заўгодна, як унутры так і звонку класа. Да закрытых жа членаў нельга звяртацца па-за класам; гэта зроблена адмыслова, каб не парушыць цэласнасць даных класа. Спроба такога звароту выкліча памылку кампіляцыі. Да такіх членаў могуць звяртацца толькі функцыі-члены класа (а таксама так званыя функцыі-сябры і функцыі-члены класаў-сяброў; пра паняцце сяброў у C++ гл. ніжэй). Апроч адкрытых і закрытых членаў класа, могуць быць яшчэ і абароненыя — гэта члены, даступныя свайму класу-ўладальніку, яго сябрам, а таксама вытворным ад яго класам (наследнікам). Такая ахова членаў называецца інкапсуляцыяй (або абаронай даных). Выкарыстоўваючы інкапсуляцыю, аўтар класа можа абараніць свае даныя ад няслушнага выкарыстання. Акрамя таго, ахоўванне ўкладзеных даных задумвалася для палягчэння сумеснай распрацоўкі класаў. Мелася на ўвазе, што пры змене спосабу захоўвання даных, калі яны аб’яўлены як абароненыя ці закрытыя, не патрабуецца адпаведных змен у класах, якія выкарыстоўваюць зменены клас. Напрыклад, калі ў старой версіі класа закрытыя ці абароненыя даныя захоўваліся ў выглядзе лінейнага спісу, а ў новай версіі — у выглядзе дрэва, не трэ будзе перапісваць ніякія функцыі, акрамя функцый-членаў класа, а таксама функцый-сяброў і функцый-членаў класаў-сяброў, а ў выпадку абароненых членаў такіх жа функцый для вытворных класаў. З іншага боку, калі гэтыя даныя былі адкрытымі, трэ будзе, увогуле кажучы, перапісваць усе функцыі, якія напрамую працуюць з гэтымі палямі: як члены любых класаў, так і функцыі, якія не з’яўляюцца членамі ніякіх класаў.
Выкарыстоўваючы ахоўванне даных, аднамерны масіў можна апісаць наступным чынам: class Array {
public:
void Alloc(int new_len);
void Free();
inline double Elem(int i);
inline void ChangeElem(int i, double x);
protected:
int len;
double* val;
};
void Array::Alloc(int new_len)
{if (len>0) Free(); len=new_len; val=new double[new_len];}
void Array::Free() {delete [] val; len=0;}
inline double Array::Elem(int i)
{assert(i>=0 && i<len ); return val[i];}
inline void Array::ChangeElem(int i, double x)
{assert(i>=0 && i<len); val[i]=x;}
І далей Array a;
a.Alloc(10);
a.ChangeElem(3, 2.78);
double b = a.Elem(3);
a.Free();
Тут масіў a мае 4 адкрытыя функцыі-члены і 2 ахаваныя палі. Апісальнік Азначэнне функцый у целе класаУ целе класа можна апісаць толькі загаловак функцыі, а можна цалкам азначыць функцыю. У апошнім выпадку яна лічыцца ўбудавальнай (або падстаўляльнай) ( class Array {
public:
void Alloc(int _len) {
if (len == 0) Free();
len = _len;
val = new double[len];
}
і гэтак далей. Аднак у прыведзеным прыкладзе не развязана важная праблема: функцыі Alloc і Free па-ранейшаму трэба выклікаць уручную. Іншая праблема гэтага прыкладу — небяспечнасць аператара прысвойвання. Каб развязаць гэтыя праблемы ў мову былі ўведзены канструктары і дэструктары. Канструктар выклікаецца кожны раз, калі ствараецца аб’ект дадзенага тыпу; дэструктар — пры знішчэнні. Пры пераўтварэннях тыпаў з удзелам асобнікаў (аб’ектаў) класаў таксама выклікаюцца канструктары і дэструктары. З канструктарамі і дэструктарам клас выглядае так: class Array {
public:
Array() : len(0), val(NULL) {}
Array(int _len) : len(_len) {val = new double[_len];}
Array(const Array& a);
~Array() { Free(); }
inline double Elem(int i);
inline void ChangeElem(int i, double x);
protected:
void Alloc(int _len);
void Free();
int len;
double* val;
};
Array::Array(const Array& a) : len(a.len)
{
val = new double[len];
for (int i=0; i<len; i++)
val[i] = a.val[i];
}
Тут Array::Array — канструктар, а Array::~Array — дэструктар. Канструктар капіравання Array::Array(const Array&) выклікаецца пры стварэнні новага аб’екта, які з’яўляецца копіяй ужо існуючага аб’екта. Зараз аб’ект класа Array нельга сапсаваць: як бы мы яго ні стваралі, што б мы ні рабілі, яго палі будуць несупярэчлівымі, таму што канструктар выклікаецца аўтаматычна. Усе небяспечныя аперацыі з указальнікамі схаваны ў закрытых функцыях-членах. Array a(5); // выклікаецца Array::Array(int)
Array b; // выклікаецца Array::Array()
Array c(a); // выклікаецца Array::Array(const Array&)
Array d=a; // тое ж самае
b=c; // адбываецца выклік аператара =
// калі ён не азначан (як у гэтым выпадку), то выклікаецца аператар прысвойвання па змаўчанні, які
// ажыццяўляе капіраванне ўсіх падаб’ектаў і пачасткавае капіраванне нестатычных членаў-дадзеных.
// як правіла канструктар капіравання і аператар прысвойвання перавызначаюцца парамі
Аператар Па змаўчанні, кожны клас мае няяўна аб’яўлены канструктар без параметраў, які будуе падаб’екты класаў-продкаў і задае палі класа, выклікаючы для іх канструктары па змаўчанні. Калі ў класе няма яўна аб’яўленага дэструктара, то клас мае няяўна аб’яўлены дэструктар. Клас можа мець колькі заўгодна канструктараў (з рознымі наборамі параметраў), але толькі адзін дэструктар (у дэструктара не можа быць параметраў). Іншыя магчымасці функцый-членаўФункцыі-члены могуць быць і аператарамі: class Array {
...
inline double &operator[] (int n)
{
return val[n];
}
І далей Array a(10);
...
double b = a[5];
Функцыі-члены (і толькі яны) могуць мець апісальнік class Array {
...
inline double operator[] (int n) const;
Такія функцыі не маюць права змяняць палі класа (акрамя палёў, пазначаных як НаследаваннеДля стварэння класаў з дадатковай функцыянальнасцю ўводзяць наследаванне. Клас-наследнік мае палі і функцыі-члены класа-продка, але не мае права звяртацца да закрытых ( Клас-наследнік можа дабаўляць свае палі і функцыі або пераазначаць функцыі-члены класа-продка. Па змаўчанні, канструктар наследніка без параметраў выклікае канструктар класа-продка, а затым канструктары тых нестатычных членаў-даных, якія з’яўляюцца асобнікамі пэўных класаў. Дэструктар працуе ў адваротным парадку. Канструктары класаў-наследнікаў даводзіцца азначаць кожны раз нанова. На шчасце, гэта можна зрабіць выклікам канструктара класа-продка. class ArrayWithAdd : public Array {
ArrayWithAdd(int n) : Array(n) {}
ArrayWithAdd() : Array() {}
ArrayWithAdd(const Array& a) : Array(a) {}
void Add(const Array& a);
};
Наследнік змяшчае больш палёў і функцый-членаў чым продак, таму, калі наследаванне адкрытае, аб’екта класа-наследніка можна выкарыстоўваць усюды, дзе выкарыстоўваюцца асобнікі (аб’екты) класа-продка, але не наадварот. Наследаванне бывае адкрытым, ахаваным і закрытым. Пры адкрытым наследаванні, адкрытыя і ахаваныя члены класа-продка захоўваюць свой узровень ахоўвання, а да закрытых не могуць звяртацца нават функцыі-члены наследніка. Ахаванае наследаванне адрозніваецца тым, што пры ім адкрытыя члены класа-продка з’яўляюцца ахаванымі членамі наследніка. Пры закрытым наследаванні ўсе члены класа-продка становяцца закрытымі членамі класа-наследніка; такім чынам, карыстальнік вытворнага класа не можа звяртацца да членаў бацькоўскага класа, нават калі яны аб’яўлены як адкрытыя. Клас-наследнік робіць іх закрытымі з дапамогай закрытага наследавання. Як правіла, адкрытае наследаванне ужываецца значна часцей за іншыя.
Клас можа быць наследнікам некалькіх класаў. Такое наследаванне называецца множным наследаваннем. Такі клас валодае палямі і функцыямі-членамі ўсіх сваіх продкаў. Напрыклад, клас FlyingCat (ЛятучыКот) можа быць наследнікам класаў Cat (Кот) і FlyingAnimal (ЛятучаяЖывёла) class Cat {
...
void Purr();
...
};
class FlyingAnimal {
...
void Fly();
...
};
class FlyingCat : public Cat, public FlyingAnimal {
...
PurrAndFly() {Purr(); Fly();}
...
};
Полімарфізм (разнастайнасць падкласаў)Полімарфізмам у праграмаванні завецца пераазначэнне наследнікам функцый-членаў базавага класа, напрыклад class Figure {
...
void Draw() const;
...
};
class Square : public Figure {
...
void Draw() const;
...
};
class Circle : public Figure {
...
void Draw() const;
...
};
У гэтым прыкладзе, якая з функцый будзе выклікана — Circle::Draw(), Square::Draw() ці Figure::Draw(), вызначаецца падчас кампіляцыі. Напрыклад, калі напісаць Figure* x = new Circle(0,0,5);
x->Draw();
то будзе выклікана Figure::Draw(), бо x — аб’ект класа Figure. Такі полімарфізм называецца статычным. Але ў C++ ёсць і дынамічны полімарфізм, калі функцыя, якую трэба выклікаць, вызначаецца падчас выканання. Для гэтага функцыі-члены павінны быць віртуальнымі. class Figure {
...
virtual void Draw() const;
...
};
class Square : public Figure {
...
virtual void Draw() const;
...
};
class Circle : public Figure {
...
virtual void Draw() const;
...
};
Figure* figures[10];
figures[0] = new Square(1, 2, 10);
figures[1] = new Circle(3, 5, 8);
...
for (int i = 0; i < 10; i++)
figures[i]->Draw();
У гэтым выпадку для кожнага элемента будзе выклікана Square::Draw() ці Circle::Draw() у залежнасці ад фігуры. Чыста віртуальнай функцыяй называецца віртуальная функцыя-член, якая аб’яўлена са апісальнікам class Figure {
...
virtual void Draw() const = 0;
);
Чыста віртуальная функцыя можа быць пакінута без азначэння, акрамя выпадку, калі неабходна яе выклікаць. Абстрактным класам называецца такі, у якога ёсць хоць адна чыста віртуальная функцыя-член. Аб’екты такіх класаў ствараць забаронена. Абстрактныя класы часта выкарыстоўваюцца як інтэрфейсы. Сябры класаФункцыі-сябры — гэта функцыі, якія не ёсць функцыямі-членамі, але маюць доступ да ахаваных і закрытых палёў і функцый-членаў класа. Яны павінны быць апісаны ў целе класа як class Matrix {
...
friend Matrix Multiply(Matrix m1, Matrix m2);
...
};
Matrix Multiply(Matrix m1, Matrix m2) {
...
}
Тут функцыя Multiply можа звяртацца да любых палёў і функцый-членаў класа Matrix. Існуюць таксама класы-сябры. Калі клас A — сябар класа B, то ўсе яго функцыі-члены могуць звяртацца да любых палёў і функцый членаў класа B. Напрыклад: class Matrix {
...
friend class Vector;
...
};
Аднак у C++ не дзейнічае правіла «сябар майго сябра — мой сябар». Па стандарце C++03 укладзены клас не мае доступу да закрытых членаў класа, які агортвае яго, і не можа быць аб’яўлен яго сябрам (апошняе вынікае з азначэння тэрміна сябар як нечлена класа). Аднак, многія пашыраныя кампілятары парушаюць абодва гэтыя правілы (відаць, з прычыны сукупнай дзіўнасці гэтых правіл). Будучае развіццёБягучы стандарт мовы быў прыняты ў 2003 годзе. Наступная версія стандарту носіць неафіцыйную назву C++0x. C++ працягвае развівацца, каб адказваць сучасным патрабаванням. Адна з груп, якія займаюцца мовай C++ у яе сучасным выглядзе і накіроўваюць камітэту па стандартызацыі C++ парады па яе паляпшэнні — гэта Boost. Напрыклад, адзін з кірункаў дзейнасці гэтай групы — удасканаленне магчымасцей мовы шляхам дабаўлення ў яе асаблівасцей метапраграмавання. Стандарт C++ не апісвае спосабы наймення аб’ектаў, некаторыя падрабязнасці апрацоўкі выключэнняў і іншыя магчымасці, спалучаныя з асаблівасцямі рэалізацыі, што прыводзіць да несумяшчальнасці аб’ектнага кода, створанага рознымі кампілятарамі. Аднак, каб зняць гэту праблему, трэцімі асобамі было створана мноства стандартаў для розных архітэктур і аперацыйных сістэм. Тым не менш (па стане на час напісання гэтага артыкула) сярод кампілятараў C++ усё яшчэ працягваецца бітва за поўную рэалізацыю стандарту C++, асабліва ў вобласці шаблонаў — часткі мовы, зусім нядаўна распрацаванай камітэтам стандартызацыі ў поўным аб’ёме. Ключавое слова exportАдной са спрэчных пунктаў у гэтым пытанні з’яўляецца ключавое слова Першым кампілятарам, які падтрымлівае Абодва гэтых кампілятара заснаваны на вонкавым інтэрфейсе EDG. Іншыя кампілятары, такія як Microsoft Visual C++ ці GCC (GCC 3.4.4), наогул не падтрымліваюць гэта ключавое слова. Хёрб Саттэр, сакратар камітэта па стандартызацыі C++, рэкамендаваў прыбраць Са спісу іншых праблем, спалучаных з шаблонамі, можна прывесці пытанні пабудовы частковай спецыялізацыі шаблонаў, якія дрэнна падтрымліваліся на працягу многіх гадоў пасля выхаду стандарту C++. Стандартная бібліятэкаУ склад стандартнай бібліятэкі C++ уваходзіць стандартная бібліятэка мовы Сі з невялікімі зменамі, якія робяць яе больш прыдатнай для мовы C++. Другім істотным складнікам бібліятэкі C++ ёсць Стандартная Бібліятэка Шаблонаў (STL). Яна дае такія важныя прылады, як тыпы-скрыні (або кантэйнеры) (напрыклад, вектары і спісы) і ітэратары (абагульненыя указальнікі), якія дазваляюць працаваць са тыпамі-скрынямі (кантэйнерамі) як з масівамі. Акрамя таго, STL дазваляе падобным чынам працаваць і з іншымі скрыневымі тыпамі (тыпамі кантэйнераў), напрыклад, слоўнікамі (асацыятыўнымі спісамі), стэкамі, чэргамі. Выкарыстоўваючы шаблоны, можна пісаць абагульненыя алгарытмы, здольныя працаваць з любымі скрыневымі тыпамі (кантэйнерамі) ці паслядоўнасцямі, вызначанымі ітэратарамі. Гэтак жа, як і ў Сі, доступ к магчымасцям бібліятэк ажыццяўляецца з дапамогай указання STL да ўключэння ў стандарт C++ была незалежнай распрацоўкай, напачатку — фірмы HP, а затым SGI. Стандарт мовы не называе яе «STL», бо гэта бібліятэка стала неад’емнай часткай мовы, аднак шмат хто і дагэтуль выкарыстоўвае гэту назву, каб адрозніваць яе ад астатняй часткі стандартнай бібліятэкі (патокі ўводу/вываду (iostream), падмноства Сі і інш.). Праект пад назвай STLport[5], заснаваны на SGI STL, ажыццяўляе сталае абнаўленне STL, IOstream і радковых класаў. Некаторыя іншыя праекты таксама займаюцца распрацоўкай асобных дастасаванняў стандартнай бібліятэкі для розных канструктарскіх задач. Кожны вытворца кампілятараў C++ абавязкова пастаўляе якую-небудзь рэалізацыю гэтай бібліятэкі, бо яна з’яўляецца вельмі важнай часткай стандарту і шырока выкарыстоўваецца. C++ не ўключае ў сябе СіНягледзячы на тое, што вялікая частка кода Сі будзе слушнай і на мове C++, C++ не ёсць надмноствам мовы Сі і не ўключае яе ў сябе. Існуе і такі код, які слушны на Сі, але няслушны для C++. Гэта адрознівае яго ад Аб’ектнага Сі, яшчэ аднаго ўдасканалення Сі для ААП, які якраз і ёсць надмноствам Сі. У прыватнасці крыніцай несумяшчальнасці з’яўляюцца новыя (адносна Сі) ключавыя словы. Так, апісанне пераменнай int try;
з’яўляецца цалкам слушным на Сі, але хібным на мове C++, бо слова Існуюць і іншыя адрозненні. Напрыклад, C++ не дазваляе выклікаць функцыю Да таго ж код, слушны на абедзвюх мовах, можа даваць розныя вынікі ў залежнасці ад таго, кампілятарам якой мовы ён апрацаваны. Напрыклад, на большасці платформ наступная праграма друкуе «C», калі кампілюецца кампілятарам Сі, і «C++» — калі кампілятарам C++. Так адбываецца з-за таго, што знакавыя канстанты ў Сі (напрыклад #include <stdio.h>
int main()
{
printf("%s\n", (sizeof('a') == sizeof(char)) ? "C++" : "C");
return 0;
}
Прыклады праграм на C++Прыклад № 1Гэта прыклад праграмы, якая нічога не робіць. Яна пачынае выконвацца і адразу завяршаецца. Яна складаецца з асноўнага патоку: функцыі int main()
{
return 0;
}
Стандарт C++ патрабуе, каб функцыя Стандарт не кажа пра тое, што насамрэч азначае вяртаймае значэнне функцыі Завяршэнне праграмы на C++ з памылкай традыцыйна пазначаецца шляхам вяртання ненулявога значэння. Прыклад № 2Гэта праграма таксама нічога не робіць, але карацейшая. int main(){}
У C++, калі выкананне праграмы даходзіць да канца функцыі Прыклад № 3Гэта прыклад праграмы Hello World, якая выводзіць гэта знакамітае паведамленне, выкарыстоўваючы стандартную бібліятэку, і завяршаецца. #include <iostream> // гэта неабходна для std::cout і std::endl
int main()
{
std::cout << "Hello, world!" << std::endl;
}
Прыклад № 4Сучасны C++ дазваляе развязваць простым спосабам і больш складаныя задачы. Гэты прыклад паказвае акрамя ўсяго іншага выкарыстанне тыпаў-скрыняў (кантэйнераў) стандартнай бібліятэкі шаблонаў (STL). #include <iostream> // для выкарыстання std::cout
#include <vector> // для std::vector<>
#include <map> // для std::map<> і std::pair<>
#include <algorithm> // для std::for_each()
#include <string> // для std::string
using namespace std; // выкарыстанне прасторы імён "std"
void display_item_count(pair< string const, vector<string> > const& person) {
// person — гэта пары двух аб’ектаў: person.first — гэта яго імя,
// person.second — гэта спіс яго прадметаў (вектар радкоў)
cout << person.first << " is carrying " << person.second.size() << " items" << endl;
}
int main()
{
// аб’яўляем слоўнік (мапу, адлюстраванне) з радковымі ключамі і дадзенымі ў выглядзе вектараў радкоў
map< string, vector<string> > items;
// Дабавім у гэту карту некалькі чалавек і дадзім ім некалькі рэчаў
items["Anya"].push_back("scarf");
items["Dimitri"].push_back("tickets");
items["Anya"].push_back("puppy");
// Перабяром усе аб’екты ў скрыні (кантэйнеры)
for_each(items.begin(), items.end(), display_item_count);
}
У гэтым прыкладзе для прастаты выкарыстоўваецца ўказанне выкарыстанай прасторы імён з дапамогай ключавых слоў #include <vector>
int main()
{
using std::vector;
vector<int> my_vector;
}
Тут дырэктыва (указанне) змешчана ў вобласць функцыі, што памяншае шанцы сутыкненняў імён (гэта і стала прычынай увядзення ў мову прастор імён). Ужыванне аб’яўленняў, якія зліваюць розныя прасторы імёнаў у адну, руйнуе сам замысел прасторы імён. Прыклад № 5Папулярныя бібліятэкі (напрыклад, boost) у спалучэнні са стандартнымі сродкамі мовы дазваляюць вельмі коратка і наглядна запісваць код. У прыведзеным ніжэй прыкладзе вылічаецца скалярны здабытак вектараў няцотных лікаў і квадратаў. У кодзе вектары значэнняў прадстаўлены STL-падобнымі паслядоўнасцямі. #include <iostream>
#include <numeric>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
int odd(int i)
{
return 2 * i + 1;
}
int square(int i)
{
return i * i;
}
typedef boost::counting_iterator <int> counter;
typedef boost::transform_iterator <int (*)(int), counter> transformer;
transformer odds(int n)
{
return transformer(counter(n), odd);
}
transformer squares(int n)
{
return transformer(counter(n), square);
}
int main()
{
using namespace std;
cout << "Enter vector length: ";
int n; cin >> n;
cout << inner_product( odds(0), odds(n), squares(0), 0 ) << endl;
}
Гэты прыклад паказвае так званы «плоскі» стыль запісу. Гэта назва звязана з тым, што алгарытмы STL дазваляюць запісваць код без цыклаў, адпаведна шырыня водступаў у адфарматаваным кодзе не дужа змяняецца. Прыхільнікі такога падыходу лічаць, што праграмісту, знаёмаму са стандартнай бібліятэкай C++, дастаткова радка з выклікам Параўнанне C++ з мовамі Java і C#Мэтай стварэння C++ было пашырэнне магчымасцей Сі, найбольш распаўсюджанай мовы сістэмнага праграмавання. Накіраваная на той жа абсяг ужытку, што і мова Сі, мова C++ пераняла ад яе ў спадчыну мноства не самых лепшых, з тэарэтычнага пункту гледжання, асаблівасцей. Пералічаныя вышэй прынцыпы, якіх прытрымліваўся аўтар мовы, прадвызначылі многія недахопы C++. У галіне прыкладнога праграмавання альтэрнатывай C++ стала мова Java. Нягледзячы на пераемнасць у адносінах да C++, Java будавалася на прынцыпова іншай аснове, яе распрацоўшчыкі не былі абмежаваны патрабаваннямі сумяшчальнасці з мовай-продкам і забеспячэння найбольшай дасягальнай эфектыўнасці, дзякуючы гэтаму яны змаглі карэнным чынам перапрацаваць мову, адмовіцца ад мноства сінтаксічных сродкаў, каб дамагчыся ідэалагічнай цэласнасці мовы. Пазней фірма Майкрасофт прапанавала мову C#, якая ўяўляе сабой яшчэ адну перапрацоўку мовы C++ у тым жа кірунку, што і Java. Пасля з’явілася мова Nemerle, у якой да сродкаў C# далучаны сродкі функцыйнага праграмавання. Яшчэ пазней з’явілася спроба аб’яднання эфектыўнасці C++ з бяспекай і хуткасцю распрацоўкі Java і C# — была прапанавана мова D, якая пакуль не атрымала шырокага прызнання. Java і C++ можна разглядаць як дзве мовы-пераемніцы Сі, распрацаваныя з розных меркаванняў, у выніку чаго іх шляхі разышліся. У гэтай сувязі цікава параўнаць гэтыя мовы (усё, сказанае ніжэй пра Java, можна з аднолькавым поспехам аднесці да моў C# і Nemerle, бо на такім узроўні разглядання гэтыя мовы адрозніваюцца толькі вонкава).
Адрозненні моў прыводзяць да разлютаваных спрэчак паміж прыхільнікамі дзвюх моў пра тое, якая мова лепшая. Спрэчкі гэтыя шмат у чым беспрадметныя, бо прыхільнікі Java лічаць, што адрозненні сведчаць на карысць Java, а прыхільнікі C++ мяркуюць адваротнае. Некаторыя довады з часам састарэлі, напрыклад, папрокі ў неэфектыўнасці Java з-за наяўнасці асяроддзя выканання, якія былі справядлівымі ў першай палове 1990-х гадоў, у выніку лавінападобнага росту прадукцыйнасці камп’ютараў і з’яўлення больш эфектыўнай тэхнікі выканання (JIT) у значнай меры страцілі актуальнасць. Мова C++, у сваю чаргу, развівалася, і шэраг яе недахопаў выпраўлены ў апошніх версіях стандарту (напрыклад, з’явіўся механізм частковай спецыфікацыі шаблонаў). Далёка не ўсе праграмісты з’яўляюцца прыхільнікамі толькі аднае з моў. Паводле меркавання большасці праграмістаў, Java і C++ не з’яўляюцца канкурэнтамі, таму што ў іх розныя вобласці ўжытку. Іншыя лічаць, што выбар мовы для большасці задач з’яўляецца пытаннем асабістага густу. Добрыя якасці і недахопы мовыПерш за ўсё, неабходна падкрэсліць, што ацэньваць добрыя якасці і, асабліва, недахопы C++ неабходна з улікам тых прынцыпаў, на якіх будавалася мова, і патрабаванняў, якія да яе першапачаткова прад’яўляліся. Добрыя якасціC++ — надзвычай магутная мова, якія мае сродкі для стварэння эфектыўных праграм амаль любога прызначэння, ад нізкаўзроўневых утыліт і драйвераў да складаных праграмных комплексаў самага рознага прызначэння. У прыватнасці:
НедахопыБольшасць сваіх недахопаў мова C++ атрымала ў спадчыну ад мовы-продка — Сі, — і выкліканы яны першапачаткова пастаўленым патрабаваннем як мага большай сумяшчальнасці з Сі. Гэта такія недахопы, як:
Да ўласных недахопаў C++ можна аднесці:
Гл. таксама
Крыніцы
Літаратура
Спасылкі
Information related to C++ |
Portal di Ensiklopedia Dunia