e menyaet tipa zaklyuchennogo v nih imeni-iz-opisatelya, no dlya slozhnyh opisatelej ono mozhet povliyat' na poryadok primeneniya operacij. R.8.2.1 Ukazateli V opisanii T D, v kotorom D imeet vid * spisok-specifikacij-cv opt D1 tip opisyvaemogo identifikatora est' "... spisok-specifikacij-cv ukazatel' na T". Konstrukciya spisok-specifikacij-cv otnositsya k ukazatelyu, a ne k ukazuemomu ob容ktu. Naprimer, v opisaniyah const ci = 10, *pc = &ci, *const cpc = pc; int i *p, *const cp = &i; opredelyayutsya: ci kak konstanta celoe; pc kak ukazatel' na konstantu celoe; cpc kak konstanta ukazatel' na konstantu celoe; i kak celoe; p kak ukazatel' na celoe; i cp kak konstanta ukazatel' na celoe. Posle inicializacii znacheniya ci, cpc i cp ne mogut byt' izmeneny. Znachenie pc mozhno izmenyat' tak zhe, kak i znachenie ob容kta, na kotoryj ukazyvaet cp. Privedem primery dopustimyh operacij: i = ci; *cp = ci; pc++; pc = cpc; pc = p; Nedopustimy sleduyushchie operacii: ci = 1; // oshibka ci++; // oshibka *pc = 2; // oshibka cp = &ci; // oshibka cpc++; // oshibka p = pc; // oshibka Kazhdaya iz etih operacij nedopustima ili potomu, chto ona izmenyaet znachenie ob容kta, opisannogo so specifikaciej const, ili potomu, chto delaet takoe izmenenie vozmozhnym pozdnee s pomoshch'yu ukazatelya, nastroennogo na ob容kt bez specifikacii const. Analogichna situaciya so specifikaciej volatile. Obratites' k $$R.5.17 i $$R.8.4. Nel'zya opisyvat' ukazateli na ssylki ($$R.8.2.2) ili ukazateli na bitovye polya ($$R.9.6). R.8.2.2 Ssylki V opisanii T D, v kotorom D imeet vid & spisok-specifikacij-cv opt D1 tip opisyvaemogo identifikatora est' "...spisok-specifikacij-cv ssylka na T". Tip void& nedopustim. Naprimer, vo fragmente void f(double& a) { a += 3.14; } // ... double d = 0; f(d); a opisyvaetsya kak parametr, yavlyayushchijsya ssylkoj, poetomu vyzov f(d) privedet k uvelicheniyu d na 3.14. Vo fragmente int v[20]; // ... int& g(int i) { return v[i]; } // ... g(3) = 7; opisyvaetsya: funkciya g() vozvrashchaet ssylku na celoe; poetomu operator g() = 7; prisvoit 7 chetvertomu elementu massiva v. Rassmotrim sleduyushchij programmnyj fragment: struct link { link* next; }; link* first; void h(link*& p) // `p' ssylka na ukazatel' { p->next = first; first = p; p = 0; } void k() { link* q = new link; h(q); } Zdes' p opisano kak ssylka na ukazatel' na link, poetomu vyzov h(q) ne izmenit znachenie q, ravnoe 0, sm. takzhe $$R.8.4.3. Nedopustimy ssylki na ssylki, ssylki na bitovye polya ($$R.9.6), massivy ssylok i ukazateli na ssylki. Opisanie ssylki dolzhno soderzhat' inicializator ($$R.8.4.3), za isklyucheniem teh sluchaev, kogda opisanie soderzhit yavnuyu specifikaciyu extern ($$R.7.1.1), ili yavlyaetsya opisaniem chlena klassa ($$R.9.2) pri opisanii samogo klassa, ili yavlyaetsya opisaniem parametra ili vozvrashchaemogo tipa ($$R.8.2.5), sm. takzhe $$R.3.1. R.8.2.3 Ukazateli na chleny V opisanii T D, v kotorom D imeet vid polnoe-imya-klassa :: * spisok-specifikacij-cv opt D1 tip opisyvaemogo identifikatora est' "... spisok-specifikacij-cv ukazatel' na chlen klassa polnoe-imya-klassa tipa T". Naprimer, vo fragmente class X { public: void f(int); int a; }; int X::* pmi = &X::a; void (X::* pmf)(int) = &X::f; pmi i pmf opisyvayutsya kak ukazatel' na chlen X tipa T i ukazatel' na chlen X tipa void(int) sootvetstvenno. |ti ob容kty mozhno ispol'zovat' tak: X obj; // ... obj.*pmi = 7; // prisvoit' 7 chlenu obj tipa int (obj.*pmf)(7); // vyzvat' funkciyu-chlen obj // s parametrom 7 Otmetim, chto ukazatel' na chlen nel'zya nastroit' na staticheskij chlen klassa ($$R.9.4), sm. takzhe $$R.5.5 i $$R.5.3. R.8.2.4 Massivy V opisanii T D, v kotorom D imeet vid D1 [ vyrazhenie-konstanta opt ] opisyvaetsya identifikator tipa " ... massiv T". Esli vyrazhenie-konstanta prisutstvuet ($$R.5.19), to ono dolzhno imet' celochislennyj tip i znachenie, bol'shee 0. |to vyrazhenie zadaet chislo elementov massiva. Esli znachenie vyrazheniya-konstanty est' N, to massiv imeet N elementov s indeksami ot 0 do N-1. Massiv mozhno obrazovyvat' iz: odnogo iz osnovnyh tipov (za isklyucheniem void), ukazatelya, ukazatelya na chleny, klassa, perechisleniya ili iz drugogo massiva. Esli podryad idut neskol'ko specifikacij "massiv ...", obrazuetsya mnogomernyj massiv, prichem vyrazhenie-konstanta, zadayushchee granicy massiva, mozhet otsutstvovat' tol'ko dlya pervogo massiva. Takoe umolchanie polezno v sluchae parametrov funkcii tipa massiv, a takzhe kogda massiv yavlyaetsya vneshnim, a ego opredelenie, s kotorym svyazano rezervirovanie pamyati, nahoditsya v drugom meste. Pervoe vyrazhenie-konstanta mozhet byt' propushcheno i v tom sluchae, esli za opisatelem sleduet spisok-inicializatorov ($$R.8.4). Togda razmer massiva opredelyaetsya chislom elementov, privedennyh v inicializatore ($$R.8.4.1). V opisanii float fa[17], *afp[17]; opisany massiv chisel tipa float i massiv ukazatelej na chisla tipa float, a v opisanii static int x3d[3][5][7]; opisan staticheskij trehmernyj massiv celyh razmera 3x5x7. Strogo govorya, x3d yavlyaetsya massivom iz treh elementov, kazhdyj iz kotoryh est' massiv iz pyati massivov, a kazhdyj iz poslednih yavlyaetsya massivom iz semi celyh. V vyrazhenii dopustimo poyavlenie lyubogo iz sleduyushchih vyrazhenij: x3d, x3d[i], x3d[i][j], x3d[i][j][k]. Esli v vyrazhenii uchastvuet identifikator tipa massiv, to, isklyuchaya sluchai operanda v operaciyah sizeof ili & i inicializatora dlya ssylki ($$R.8.4.3), ego tip preobrazuetsya v ukazatel' na pervyj element massiva. Nesmotrya na eto preobrazovanie, massivy ne yavlyayutsya izmenyaemymi adresami. Esli ne schitat' sluchaj ispol'zovaniya massiva pri opisanii klassa ($$R.13.4.5), operaciya indeksacii opredelyaetsya tak, chto E1[E2] sovpadaet s *((E1) + (E2)). S uchetom pravil preobrazovaniya tipov dlya operacii +, esli E1 est' massiv, a E2 celoe, to E1[E2] ukazyvaet na E2-element iz E1. Poetomu, nesmotrya na svoj asimetrichnyj vid, indeksaciya - kommutativnaya operaciya. Analogichnoe pravilo dejstvuet i dlya mnogomernyh massivov. Esli E - n-mernyj massiv razmera ixjx...xk, to v vyrazhenii on preobrazuetsya v ukazatel' na (n-1)-mernyj massiv razmera jx...xk. Esli k etomu ukazatelyu yavno ili neyavno v rezul'tate indeksacii primenyaetsya operaciya *, ukazuemyj (n-1)-mernyj massiv sam nemedlenno preobrazuetsya v ukazatel'. Naprimer, rassmotrim opisanie int x[3][5]; Zdes' opisan massiv iz 3x5 celyh. Esli v vyrazhenii poyavlyaetsya x, to ono preobrazuetsya v ukazatel' na pervyj massiv iz pyati celyh. Esli v vyrazhenii poyavlyaetsya x[i], chto ekvivalentno *(x+i), v nachale x preobrazuetsya v ukazatel', kak bylo skazano vyshe, zatem x+i preobrazuetsya k tipu x, dlya chego neobhodimo i umnozhit' na razmer ob容kta, na kotoryj ukazyvaet x, t.e. na razmer pyati celyh. Zatem proishodit slozhenie i primenyaetsya kosvennost', posle chego poluchim massiv (iz pyati celyh), kotoryj v svoyu ochered' preobrazuetsya v ukazatel' na pervoe iz celyh. Esli est' eshche odna indeksaciya, process povtoryaetsya, i na etot raz my poluchim v rezul'tate celoe. Iz vsego etogo sleduet, chto massivy V S++ hranyatsya po strokam (poslednij indeks izmenyaetsya bystree vsego), a znachenie pervogo indeksa iz opisaniya pozvolyaet vychislit' razmer pamyati, neobhodimoj dlya massiva, odnako pri vychislenii indeksnogo vyrazheniya pervyj indeks roli ne igraet. R.8.2.5 Funkcii V opisanii T D, v kotorom D imeet vid D1 (spisok-opisanij-parametrov ) spisok-specifikacij-cv opt opisyvaemyj identifikator imeet tip "...spisok-specifikacij-cv funkciya s parametrami tipa spisok-opisanij-parametrov vozvrashchayushchaya T". spisok-opisanij-parametrov: spisok-opisanij-param opt ... opt spisok-opisanij-param , ... spisok-opisanij-param: opisanie-parametra spisok-opisanij-param , opisanie-parametra opisanie-parametra: specifikacii-opisaniya opisatel' specifikacii-opisaniya opisatel' = vyrazhenie specifikacii-opisaniya abstraktnyj-opisatel' opt specifikacii-opisaniya abstraktnyj-opisatel' opt = vyrazhenie Esli spisok-opisanij-parametrov zavershaetsya ellipsisom (...), pro chislo parametrov izvestno tol'ko to, chto ono bol'she ili ravno chisla zadannyh parametrov, esli spisok parametrov pust, to funkciya parametrov ne imeet. Spisok parametrov void ekvivalenten pustomu spisku parametrov. Ne schitaya etogo sluchaya, void ne mozhet byt' tipom parametra (hotya tipy, poluchaemye iz void, takie kak void*, dopustimy). R.8.3 Opredeleniya funkcij Opredeleniya funkcij imeyut vid opredelenie-funkcii: specifikacii-opisaniya opt opisatel' inicializator-ctor telo-funkcii telo-funkcii: sostavnoj-operator Konstrukciya opisatel' iz opredeleniya-funkcii dolzhna soderzhat' opisatel' vida D1 ( spisok-opisanij-parametrov ) spisok-specifikacij-cv opt v sootvetstvii s opredeleniyami iz $$R.8.2.5 Formal'nye parametry otnosyatsya k oblasti vidimosti samogo bol'shogo bloka tela-funkcii. Privedem primer polnogo opredeleniya funkcii. int max( int a, int b, int c) { int m = (a > b) ? a : b; return (m > c) ? m : c; } Zdes' int predstavlyaet specifikacii-opisaniya, max(int a, int b, int c) - opisatel', a { /* ... */ } - telo-funkcii. Konstrukciya inicializator-ctor ispol'zuetsya tol'ko v konstruktorah, sm. $$R.9.3.1 i $$R.12.6. Konstrukciya spisok-specifikacij-cv mozhet uchastvovat': v opisanii nestaticheskoj funkcii-chlena, v opredelenii nestaticheskoj funkcii-chlena ili v opisanii ukazatelya na funkciyu-chlen, sm. $$R.9.3.1. Ona otnositsya k tipu funkcii. Otmetim, chto neispol'zuemym formal'nym parametram imena mozhno ne davat', naprimer, void print(int a, int) { printf("a = %d\n",a); } R.8.4 Inicializatory Za opisatelem mozhet idti nachal'noe znachenie opisyvaemogo identifikatora. inicializator: = vyrazhenie-prisvaivaniya = { spisok-inicializatorov , opt } ( spisok-vyrazhenij ) spisok-inicializatorov: vyrazhenie-prisvaivaniya spisok-inicializatorov , vyrazhenie-prisvaivaniya { spisok-inicializatorov , opt } Avtomaticheskie, registrovye, staticheskie i vneshnie peremennye mozhno inicializirovat' proizvol'nymi vyrazheniyami, soderzhashchimi konstanty i opisannye ranee peremennye i funkcii. int f(int); int a = 2; int b = f(a); int c(b); Ukazatel' tipa const T*, t.e. ukazatel' na konstantu T, mozhet inicializirovat'sya ukazatelem tipa T*, no inicializaciya dlya ukazatelej v obratnom poryadke nezakonna. Ob容kty tipa T mozhno inicializirovat' ob容ktami tipa T nezavisimo ot ispol'zovaniya specifikacij const ili volatile v tipah inicializiruemoj peremennoj ili inicializatora, naprimer, int a; const int b = a; int c = b; const int* p0 = &a; const int* p1 = &b; int* p2 = &b; // oshibka: ukazatel' bez const // nastraivaetsya na ob容kt const int *const p3 = p2; int *const p4 = p1; // oshibka: ukazatel' bez const // nastraivaetsya na ob容kt const const int* p5 = p1; Zdes' prichina obeih oshibok odna: esli dopustit' podobnuyu inicializaciyu, ona pozvolit izmenyat' s pomoshch'yu ukazatelya bez sootvetstvuyushchej specifikacii znachenie chego-to, chto bylo opisano kak const. Na vyrazheniya dlya standartnyh znachenij parametrov nakladyvaetsya bol'she ogranichenij, sm. $$R.8.2.6. Inicializaciya ob容ktov klassov s pomoshch'yu konstruktorov opisyvaetsya v $$R.12.6.1. Kopirovanie ob容ktov klassov opisyvaetsya v $$R.12.8. Poryadok inicializacii staticheskih ob容ktov opredelyaetsya v $$R.3.4 i $$R.6.7. Garantiruetsya, chto peremennye staticheskogo klassa pamyati ($$R.3.5), kotorye ne byli inicializirovany, v kachestve nachal'nogo znacheniya poluchat 0, privedennyj k nuzhnomu tipu. To zhe spravedlivo dlya staticheskih chlenov ob容ktov klassa. Nachal'nye znacheniya avtomaticheskih i registrovyh peremennyh, kotorye ne byli inicializirovany, neopredeleny. Esli inicializator otnositsya k ukazatelyu ili ob容ktu arifmeticheskogo tipa, on sostoit iz odnogo vyrazheniya (vozmozhno v skobkah). V kachestve nachal'nogo znacheniya ob容kta beretsya znachenie vyrazheniya, proishodyat takie zhe preobrazovaniya tipa, kak i v sluchae prisvaivaniya. Zametim, chto poskol'ku () ne yavlyaetsya inicializatorom, opisanie X a(); zadaet ne ob容kt a tipa klass X, a yavlyaetsya opisaniem funkcii bez parametrov, vozvrashchayushchej X. Inicializator dlya staticheskogo chlena prinadlezhit oblasti vidimosti chlena klassa, naprimer, int a; struct X { static int a; static int b; }; int X::a = 1; int X::b = a; // X::b = X::a R.8.4.1 Agregat Agregatom nazyvaetsya massiv ili ob容kt tipa klass ($$R.9), ne imeyushchij konstruktorov ($$R.12.1), chastnyh ili zashchishchennyh chlenov ($$R.11), bazovyh klassov ($$R.10) i virtual'nyh funkcij ($$R.10.2). Esli agregat inicializiruetsya, to inicializatorom dolzhen byt' spisok-inicializatorov, kotoryj sostoit iz zaklyuchennogo v figurnye skobki spiska, razdelennogo zapyatymi, inicializatorov dlya chlenov agregata. Inicializatory idut v vozrastayushchem poryadke indeksov ili chlenov agregata. Esli agregat soderzhit vlozhennye agregaty, eto pravilo primenyaetsya rekursivno dlya chlenov vlozhennyh agregatov. Esli inicializatorov v spiske men'she, chem chlenov agregata, to on dopolnyaetsya nulevymi znacheniyami sootvetstvuyushchih tipov. Naprimer, v sleduyushchem fragmente struct S { int a; char* b; int c; } S ss = { 1, "asdf" }; ss.a inicializiruetsya znacheniem 1, ss.b - "asdf", a ss.c - 0. Krome togo, agregat, yavlyayushchijsya klassom, mozhno inicializirovat' ob容ktom etogo klassa ili klassa, yavlyayushchegosya obshchim proizvodnym ot nego ($$R.12.8). Figurnye skobki razbirayutsya sleduyushchim obrazom. Esli spisok-inicializatorov nachinaetsya levoj figurnoj skobkoj, to spisok inicializatorov, razdelennyh zapyatymi, zadaet znacheniya chlenam agregata, prichem schitaetsya oshibkoj, esli inicializatorov bol'she, chem chlenov. Inache, esli spisok-inicializatorov ili vlozhennyj agregat ne nachinaetsya levoj figurnoj skobkoj, to iz spiska ispol'zuetsya takoe chislo elementov, kotoroe nuzhno dlya inicializacii chlenov tekushchego agregata; vse ostavshiesya elementy ispol'zuyutsya dlya inicializacii chlenov sleduyushchego agregata, v kotoryj vlozhen tekushchij agregat. Naprimer, v opredelenii int x[] = { 1, 3, 5 }; massiv x inicializiruetsya kak odnomernyj massiv iz treh elementov, poskol'ku razmer massiva ne ukazan, i privedeno tri inicializatora. Privedem primer inicializacii s polnoj skobochnoj strukturoj. float y[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7}, }; Zdes' znacheniya 1, 3, 5 inicializiruyut pervuyu stroku massiva y[0], t.e. y[0][0], y[0][1] i y[0][2]. Analogichno, sleduyushchie dve stroki inicializiruyut y[1] i y[2]. Inicializatory privedeny ne polnost'yu, poetomu y[3] inicializiruetsya nulyami. Tochno takogo zhe rezul'tata mozhno dostich' s pomoshch'yu takoj inicializacii: float y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7, }; Poslednij (samyj pravyj) indeks izmenyaetsya bystree vsego. V poslednem primere inicializator dlya y nachinaetsya levoj figurnoj skobkoj, no dlya y[0] skobki ne zadano, poetomu iz spiska ispol'zuetsya tri elementa, takzhe po tri posledovatel'nyh elementa ispol'zuetsya dlya y[1] i y[2]. V sleduyushchem primere float y[4][3] = { { 1 }, { 2 }, { 3 }, { 4 } }; inicializiruetsya pervyj stolbec y (kotoryj rassmatrivaetsya kak dvumernyj massiv), a ostal'nye stolbcy prinimayut znachenie 0. Inicializaciya massiva ob容ktov tipa klass s pomoshch'yu konstruktorov opisyvaetsya v $$R.12.6.1. Inicializator dlya ob容dineniya bez konstruktora dolzhen byt' ili otdel'nym vyrazheniem tipa ob容dineniya, ili zaklyuchennym v figurnye skobki, inicializatorom pervogo chlena ob容dineniya, naprimer, union u { int a; char* b; }; u a = { 1 }; u b = a; u c = 1; // oshibka u d = { 0, "asdf" }; // oshibka u e = { "asdf" }; // oshibka CHislo inicializatorov ne dolzhno prevyshat' chisla chlenov ili elementov, kotorye inicializiruyutsya. Naprimer, sleduyushchaya inicializaciya oshibochna: char cv[4] = { 'a', 's', 'd', 'f', 0 }; // oshibka R.8.4.2 Simvol'nye massivy Massiv simvolov (nevazhno, znakovyh ili bezznakovyh) mozhno inicializirovat' strokoj-literalom: simvoly stroki posledovatel'no inicializiruyut elementy massiva. Sleduyushchee opredelenie daet primer simvol'nogo massiva, elementy kotorogo inicializiruyutsya strokoj: char msg[] = "Syntax error on line %s\n"; Zametim, chto poskol'ku '\n' zadaet odin simvol, i poskol'ku dobavlyaetsya zavershayushchij simvol '\0', sizeof(msg) ravno 25. Nel'zya zadavat' bol'she inicializatorov, chem est' elementov v massive, poetomu sleduyushchij primer oshibochen: zdes' net mesta dlya podrazumevayushchegosya simvola konca stroki ('\0'): char cv[4] = "asdf"; // oshibka R.8.4.3 Ssylki Peremennaya, opisannaya kak T&, t.e. "ssylka na tip T" ($$R.8.2.2), dolzhna inicializirovat'sya ob容ktom tipa T ili ob容ktom, kotoryj mozhno preobrazovat' k tipu T, naprimer, void f() { int i; int& r = i; // `r' ssylaetsya na `i' r = 1; // `i' prinimaet znachenie 1 int* p = &r; // `p' ukazyvaet na `i' int& rr = r; // `rr' ssylaetsya na to, na chto ssylalos' `r', // t.e. na `i' }; Ssylku posle inicializacii nel'zya izmenyat' tak, chtoby ona oboznachala drugoj ob容kt. Otmetim, chto inicializaciya ssylki traktuetsya sovsem ne tak, kak prisvaivanie ssylke. Peredacha parametra ($$R.5.2.2) i operaciya vozvrata znacheniya funkcii ($$R.6.6.3) schitayutsya inicializaciej. Inicializator dlya ssylki mozhno opuskat' tol'ko v opisanii parametra ($$R.8.2.5), v opisanii vozvrashchaemogo funkciej tipa, v opisanii chlena klassa pri opisanii samogo klassa ($$R.9.2) i tam, gde yavno ispol'zovana specifikaciya extern, naprimer, int& r1; // oshibka: net inicializacii extern int& r2; // normal'no Esli inicializator dlya ssylki na tip T yavlyaetsya adresom tipa T ili tipom, proizvodnym ot T ($$R.10), dlya kotorogo T sluzhit dostupnym bazovym tipom ($$R.4.6), ssylka budet oboznachat' znachenie, zadannoe inicializatorom. Inache, v tom i tol'ko tom sluchae, kogda ssylka oboznachaet ob容kt so specifikaciej const, budet sozdan ob容kt tipa T i proinicializirovan znacheniem, zadannym inicializatorom. Teper' ssylka igraet rol' imeni etogo ob容kta, naprimer, double d = 1.0; double& rd = d; // rd ssylaetsya na `d' const double& rcd = d; // rcd ssylaetsya na `d' double& rd2 = 1; // oshibka: nesootvetstvie tipa const double& rcd2 = 1;// rcd2 ssylaetsya na vremennyj ob容kt // so znacheniem `1' Ssylku na volatile T mozhno inicializirovat' ob容ktom tipa volatile T ili prosto T, no ne const T. Ssylku na const T mozhno inicializirovat' const T, prosto T ili chem-to, chto mozhno preobrazovat' v tip T, no ne volatile T. Ssylku na tip T (bez const ili volatile) mozhno inicializirovat' tol'ko ob容ktom tipa T. Vremya zhizni vremennogo ob容kta, sozdannogo pri opisannoj inicializacii, opredelyaetsya tekushchej oblast'yu vidimosti, v kotoroj on byl sozdan ($$R.3.5). Otmetim, chto ssylku na klass B mozhno inicializirovat' ob容ktom klassa D pri uslovii, chto V yavlyaetsya odnoznachno opredelennym i dostupnym bazovym klassom dlya D (togda govoryat, chto "D est' B"), sm. $$R.4.7. R.9 klassy Klass est' tip. Ego imya ispol'zuetsya kak imya-klassa ($$R.9.1), t.e. stanovitsya zarezervirovannym slovom v ego oblasti vidimosti. imya-klassa: identifikator Dlya obrazovaniya konstrukcii imya-klassa ispol'zuyutsya specifikacii-klassa i specifikacii-slozhnogo-tipa ($$R.7.1.6). Ob容kt klassa sostoit iz posledovatel'nosti (vozmozhno pustoj) chlenov. specifikaciya-klassa: zagolovok-klassa { spisok-chlenov opt } zagolovok-klassa: sluzhebnoe-slovo-klassa identifikator opt spec-bazovyh opt sluzhebnoe-slovo-klassa imya-klassa spec-bazovyh opt sluzhebnoe-slovo-klassa: class struct union Imya klassa mozhno ispol'zovat' v kachestve konstrukcii imya-klassa dazhe v spiske-chlenov samogo etogo klassa. Obychno specifikaciyu-klassa nazyvayut opisaniem klassa. Klass schitaetsya opredelennym, kak tol'ko poyavitsya specifikaciya-klassa, nesmotrya na to, chto ego funkcii-chleny mogut byt' eshche neopredeleny. Ob容kty pustogo klassa imeyut nenulevoj razmer. Ob容kty tipa klass mozhno prisvaivat', peredavat' v kachestve parametrov funkcij i poluchat' v kachestve znacheniya, vozvrashchaemogo funkciej (za isklyucheniem ob容ktov teh klassov, dlya kotoryh kopirovanie ogranicheno, sm. $$R.12.8). Drugie vozmozhnye operacii, takie, kak sravnenie na ravenstvo, mogut opredelyat'sya pol'zovatelem, sm. $$R.13.4. Strukturoj nazyvaetsya klass, opisannyj so sluzhebnym-slovom-klassa struct; ee chleny i bazovye klassy ($$R.10) schitayutsya obshchimi po opredeleniyu ($$R.11). Ob容dineniem nazyvaetsya klass, opisannyj so sluzhebnym-slovom-klassa union; ego chleny schitayutsya obshchimi po opredeleniyu, i v lyuboj moment vremeni ob容dinenie soderzhit tol'ko odin chlen ($$R.9.5). R.9.1 Imena klassa Opisanie klassa porozhdaet novyj tip. Naprimer, nizhe opisyvayutsya tri peremennye treh razlichnyh tipov: struct X { int a; }; struct Y { int a; }; X a1; Y a2; int a3; Otsyuda sleduet, chto takie prisvaivaniya privodyat k nesootvetstviyu tipov: a1 = a2; // oshibka: Y prisvaivaetsya X a1 = a3; // oshibka: int prisvaivaetsya X Nizhe opisyvaetsya peregruzka ($$R.13) funkcii f(), a ne prosto povtornoe opisanie toj zhe funkcii: int f(X); int f(Y); Po toj zhe prichine nel'zya dvazhdy opredelyat' klass, eto vidno iz primera nizhe, gde dvazhdy opredelen S: struct S { int a; }; struct S { int a; }; // oshibka, povtornoe opredelenie Opisanie klassa vklyuchaet imya klassa v tu oblast' vidimosti, vnutri kotoroj ono proizoshlo, i zakryvaet lyuboj klass, ob容kt, funkciyu ili drugoe opisanie etogo imeni v ob容mlyushchej oblasti vidimosti ($$R.3.2). Esli imya klassa opisano v takoj oblasti vidimosti, gde uzhe byl opisan ob容kt s takim zhe imenem, funkciya ili element perechisleniya, to obrashchat'sya k klassu mozhno tol'ko s pomoshch'yu konstrukcii specifikaciya-slozhnogo-tipa ($$R.7.1.6), naprimer: struct stat { // ... }; stat gstt; // prosto `stat' ispol'zuetsya dlya // opredeleniya peremennoj int stat(struct stat*); // pereopredelenie `stat' kak funkcii void f() { struct stat* ps; // nuzhen prefiks struct // dlya zadaniya struktury stat // ... stat(ps); // vyzov stat() // ... } Konstrukciya specifikaciya-slozhnogo-tipa vmeste so sluzhebnym-slovom-klassa, no bez opisaniya ob容kta ili funkcii takzhe mozhet sluzhit' dlya zadaniya imeni klassa, kak i opisanie klassa, odnako v etom sluchae klass ne schitaetsya opredelennym, naprimer: struct s { int a; }; void g() { struct s; // skryvaet global'nuyu strukturu `s' s* p; // ispol'zuetsya lokal'naya struktura `s' struct s { char* p; }; // opisanie lokal'noj struktury `s' } Takie pravila pozvolyayut klassam ssylat'sya drug na druga pri ih opisanii, primer, class vector; class matrix { // ... friend vector operator*(matrix&, vector&); }; class vector { // ... friend vector operator*(matrix&, vector&); }; Opisanie friend (druzhestvennye funkcii) obsuzhdaetsya v $$R.11.4, a funkciya operator v $$R.13.4. Esli klass, ukazannyj kak drug, poka eshche ne opisan, ego imya schitaetsya prinadlezhashchim toj zhe oblasti vidimosti, v kotoroj nahoditsya imya klassa, soderzhashchego opisanie friend ($$R.11.4). V opisanii ob容ktov ili funkcij mozhno takzhe ispol'zovat' konstrukciyu specifikaciya-slozhnogo-tipa ($$R.7.1.6). Ee ispol'zovanie otlichaetsya ot opisaniya klassa tem, chto esli klass, ch'e imya ukazano v specifikacii, nahoditsya v tekushchej oblasti vidimosti, to imya iz etoj specifikacii budet ssylat'sya na nego, naprimer: struct s { int a; } void g() { struct* s p = new s; // obrashchenie k global'noj `s' p->a = 1; } Imya schitaetsya opisannym srazu zhe posle poyavleniya ego identifikatora v opisanii. Otsyuda sleduet, chto v opisanii class A * A; A v nachale zadaetsya, kak imya klassa, a zatem ono pereopredelyaetsya kak imya ukazatelya na ob容kt etogo klassa, poetomu dlya oboznacheniya etogo klassa sleduet ispol'zovat' specifikaciyu-slozhnogo tipa class A. Takoe "tryukachestvo" s imenami mozhet vyzvat' nedoumenie, i luchshe ego izbegat'. Konstrukciya imya-typedef ($$R.7.1.3) oboznachaet klass i schitaetsya imenem-klassa, sm. takzhe $$R.7.1.3. R.9.2 CHleny klassa spisok-chlenov: opisanie-chlena spisok-chlenov opt specifikaciya-dostupa : spisok-chlenov opt opisanie-chlena: specifikacii-opisaniya opt spisok-opisatelej-chlenov opt ; opredelenie-funkcii ; opt utochnennoe-imya ; spisok-opisatelej-chlenov: opisatel'-chlena spisok-opisatelej-chlenov , opisatel'-chlena opisatel'-chlena: opisatel' specifikaciya-chistoj opt identifikator opt : vyrazhenie-konstanta specifikaciya-chistoj: = 0 S pomoshch'yu konstrukcii spisok-chlenov mozhno opisat' dannye, funkcii, klassy, elementy perechisleniya ($$R.7.2), bitovye polya, druzej ($$R.11.4) i imena tipov ($$R.7.1.3, $$R.9.1). Krome togo, spisok-chlenov mozhet soderzhat' opisaniya, ustanavlivayushchie dostup k imenam chlenov, sm. $$R.11.3. Nikakoj chlen ne mozhet byt' dvazhdy opisan v spiske-chlenov. Spisok-chlenov opredelyaet vse mnozhestvo chlenov dannogo klassa, t.e. nel'zya dobavit' eshche odin chlen v kakom-libo drugom opisanii. Otmetim, chto odno imya mozhet oboznachat' neskol'ko funkcij-chlenov pri uslovii, chto ih tipy dostatochno otlichayutsya drug ot druga ($$R.13). Ukazhem, chto opisatel'-chlena ne mozhet soderzhat' inicializatora ($$R.8.4). Inicializaciya chlena vozmozhna s pomoshch'yu konstruktora, sm. $$R.12.1. CHlen ne mozhet imet' specifikaciyu auto, extern ili register. Konstrukciya specifikacii-opisaniya mozhet otsutstvovat' tol'ko v opisanii funkcii. Konstrukciya spisok-opisatelej-chlenov mozhet opuskat'sya tol'ko posle konstrukcij specifikaciya-klassa, specifikaciya-perechisleniya ili specifikaciya-opisaniya, esli poslednyaya imeet vid friend specifikaciya-slozhnogo-tipa. Konstrukciya specifikaciya-chistoj ispol'zuetsya tol'ko pri opisanii virtual'noj funkcii ($$R.10.2). Esli chleny yavlyayutsya ob容ktami klassov, to eti klassy dolzhny byt' ranee opisany. V chastnosti, klass C1 ne mozhet soderzhat' ob容kt klassa C1, no mozhet soderzhat' ukazatel' ili ssylku na klass C1. Esli v tipe nestaticheskogo chlena ispol'zuetsya massiv, to vse razmery vseh indeksov massiva dolzhny byt' ukazany. Privedem prostoj primer opisaniya klassa: struct tnode { char tword[20]; int count; tnode *left; tnode *right; }; Zdes' klass soderzhit massiv iz dvadcati simvolov, celoe i dva ukazatelya na tu zhe strukturu. Posle poyavleniya takogo opisaniya sleduyushchee: tnode s, *sp; zadaet s kak ob容kt tipa tnode i sp kak ukazatel' na tnode. S uchetom etih opisanij s->count oboznachaet chlen count struktury, na kotoruyu ukazyvaet sp; s.left oboznachaet ukazatel' left na podderevo struktury s; s.right->tword[0] oboznachaet pervyj simvol chlena tword poddereva struktury s, na kotoruyu ukazyvaet right. Nestaticheskie chleny klassa, predstavlyayushchie dannye i opisannye podryad i bez ispol'zovaniya specifikacii-dostupa, razmeshchayutsya vnutri ob容kta tipa klass tak, chto pozzhe opisannye chleny imeyut bol'shie adresa. Poryadok razmeshcheniya takih chlenov, esli ih opisanie peremezhaetsya opisaniyami so specifikaciej-dostupa, zavisit ot realizacii ($$R.11.1). Prinyatye v realizacii pravila vyravnivaniya mogut privesti k tomu, chto dva sosednih chlena ne budut raspolagat'sya srazu drug za drugom. K etomu zhe mogut privesti pravila vydeleniya pamyati dlya virtual'nyh funkcij ($$R.10.2) i virtual'nyh bazovyh klassov ($$R.10.1); sm. takzhe $$R.5.4. Funkciya-chlen ($$R.9.3), imya kotoroj sovpadaet s imenem klassa, yavlyaetsya konstruktorom ($$R.12.1). Imya staticheskogo chlena dannyh, elementa perechisleniya, chlena bezymyannogo ob容dineniya ili vlozhennogo tipa ne mozhet sovpadat' s imenem klassa. R.9.3 Funkcii-chleny Funkciya, opisannaya kak chlen (bez specifikacii friend $$R.11.4), nazyvaetsya funkciya-chlen i vyzyvaetsya v sootvetstvii s sintaksisom chlena klassa ($$R.5.2.4), naprimer: struct tnode { char tword[20]; int count; tnode *left; tnode *right; void set(char*, tnode* l, tnode *r); }; Zdes' set yavlyaetsya funkciej-chlenom i mozhet vyzyvat'sya tak: void f(tnode n1, tnode n2) { n1.set("abc",&n2,0); n2.set("def",0,0); } Schitaetsya, chto opredelenie funkcii-chlena prinadlezhit oblasti vidimosti ee klassa. |to oznachaet, chto v funkcii-chlene (esli ona nestaticheskaya, $$R.9.4) mozhno neposredstvenno ispol'zovat' imena chlenov ee klassa. V staticheskoj funkcii-chlene mozhno neposredstvenno ispol'zovat' imena tol'ko staticheskih chlenov, elementov perechisleniya i vlozhennyh tipov. Esli opredelenie funkcii-chlena nahoditsya vne opisaniya klassa, ee imya sleduet utochnit' imenem klassa s pomoshch'yu operacii ::, naprimer: void tnode::set(char* w, tnode* l, tnode* r) { count = strlen(w)+1; if (sizeof(tword)<=count) error("tnode string too long"); strcpy(tword,w); left = 1; right = r; } Oboznachenie tnode::set ukazyvaet, chto funkciya set yavlyaetsya chlenom i nahoditsya v oblasti vidimosti klassa tnode. Imena chlenov tword, count, left i right otnosyatsya k chlenam togo ob容kta, s imenem kotorogo vyzyvalas' Poetomu v vyzove n1.set("abc",&n2,0) tword oboznachaet n1.tword, a v vyzove n2.set("def",0,0) tword oboznachaet n2.tword. Funkcii strlen, error i strcpy dolzhny byt' opisany gde-to v programme. CHleny mozhno opredelyat' ($$R.3.1) vne opisaniya klassa; esli v opisanii klassa oni byli opisany, no ne opredeleny, ih ne sleduet opisyvat' zanovo, sm. $$R.3.3. Posle opredeleniya klassa funkcii-chleny etogo klassa mozhno ispol'zovat' pri opisanii druzej. Vsyakaya vyzyvaemaya v programme funkciya-chlen dolzhna imet' v tochnosti odno opredelenie. Rezul'tat vyzova nestaticheskoj funkcii-chlena ($$R.9.4) klassa X, kogda ona vyzyvaetsya ne s ob容ktom klassa X, neopredelen. R.9.3.1 Ukazatel' this V nestaticheskoj ($$R.9.3) funkcii-chlene sluzhebnoe slovo this oboznachaet ukazatel' na ob容kt, s kotorym eta funkciya vyzyvalas'. V funkcii-chlene klassa X tip this est' X *const, esli tol'ko funkciya-chlen ne opisana so specifikaciej const ili volatile; dlya etih sluchaev this imeet tip const X *const ili volatile X *const sootvetstvenno. Esli funkciya opisana s ukazaniem const i volatile, to tip this budet const volatile X *const, sm. takzhe $$R.18.3.3. Privedem primer: struct s { int a; int f() const; int g() { return a++; } int h() const { return a++; } // oshibka }; int s::f() const { return a; } Operaciya a++ v tele funkcii s::h oshibochna, poskol'ku s ee pomoshch'yu delaetsya popytka izmenit' ob容kt (chast' ego), s kotorym vyzyvalas' funkciya s::h(). |to nedopustimo dlya funkcii-chlena, opisannoj so specifikaciej const, t.k. this yavlyaetsya ukazatelem na const, inymi slovami, *this imeet specifikaciyu const. Funkciya-chlen const (t.e. funkciya-chlen, opisannaya so specifikaciej const) mozhet vyzyvat'sya kak dlya ob容ktov const, tak i dlya ob容ktov bez specifikacii const, togda kak funkciya-chlen bez specifikacii const mozhet vyzyvat'sya tol'ko dlya ob容ktov bez specifikacii const, naprimer: void k(s& x, const s& y) { x.f(); x.g(); y.f(); y.g(); // oshibka } Zdes' vyzov y.g() yavlyaetsya oshibkoj, t.k. y est' const, a s::g() - funkciya-chlen bez specifikacii const, kotoraya mozhet izmenyat' (i izmenyaet) ob容kty, dlya kotoryh ona vyzyvalas'. Analogichno, tol'ko funkciya-chlen volatile (t.e. funkciya-chlen, opisannaya so specifikaciej volatile) mozhet vyzyvat'sya dlya ob容ktov so specifikaciej volatile. Funkciya-chlen mozhet byt' odnovremenno const i volatile. Dlya ob容ktov const ili volatile mogut vyzyvat'sya konstruktory ($$R.12.1) i destruktory ($$R.12.4). Konstruktory ($$R.12.1) i destruktory ($$R.12.4) nel'zya opisyvat' so specifikaciyami const ili volatile. R.9.3.2 Funkcii-chleny so specifikaciej inline Funkciyu-chlen mozhno opredelit' ($$R.8.3) v opisanii klassa, v takom sluchae ona schitaetsya podstanovkoj (inline, $$R.7.1.2). Opredelyat' funkciyu v opisanii klassa - eto ekvivalentno tomu, chtoby opisyvat' funkciyu i opredelyat' ee so specifikaciej inline srazu zhe posle opisaniya klassa. Schitaetsya, chto takoj perenos opredeleniya funkcii proishodit posle preprocessornoj obrabotki do stadii sintaksicheskogo analiza i kontrolya tipov. Poetomu programmnyj fragment int b; struct x { char* f() { return b; } char* b; }; ekvivalenten int b; struct x { char* f(); char* b; }; inline char* x::f() { return b; } // perenos Zdes' v funkcii x::f() ispol'zuetsya x::b, a ne global'noe b. Funkcii-chleny mozhno opredelyat' dazhe v opisanii lokal'nyh ili vlozhennyh klassov, gde takoj perenos budet sintaksicheski nezakonnym. Lokal'nye klassy obsuzhdayutsya v R.9.8, a vlozhennye klassy v $$R.9.7. R.9.4 Staticheskie chleny Dlya chlena klassa, predstavlyayushchego dannye ili funkciyu, mozhno pri opisanii klassa zadat' specifikaciyu static. Dlya staticheskogo chlena, predstavlyayushchego dannye, v programme sushchestvuet tol'ko odin ekzemplyar, kotorym vladeyut vse ob容kty etogo klassa. Staticheskij chlen ne yavlyaetsya chast'yu ob容kta klassa. Staticheskie chleny global'nogo klassa podlezhat vneshnemu svyazyvaniyu ($$R.3.3). Opisanie staticheskogo chlena, predstavlyayushchego dannye, v opisanii klassa ne schitaetsya opredeleniem. Opredelenie dolzhno byt' dano v drugom meste, sm. takzhe. $$R.18.3. Staticheskaya funkciya-chlen ne imeet ukazatel' this, poetomu dlya dostupa k nestaticheskim chlenam svoego klassa ona dolzhna ispol'zovat' operacii . ili ->. Staticheskaya funkciya-chlen ne mozhet byt' virtual'noj. Nedopustimy staticheskie i nestaticheskie funkcii-chleny s odnim imenem i odinakovymi tipami parametrov. Staticheskie chleny lokal'nogo klassa ($$R.9.8) ne podlezhat svyazyvaniyu i ne mogut opredelyat'sya vne opisaniya klassa. Otsyuda sleduet, chto lokal'nye klassy ne mogut imet' staticheskih chlenov, predstavlyayushchih dannye. K staticheskomu chlenu mem klassa c1 mozhno obrashchat'sya kak c1::mem ($$R.5.1), t.e. nezavisimo ni ot kakogo ob容kta. K nemu takzhe mozhno obrashchat'sya s pomoshch'yu operacij dostupa k chlenam . i ->. Esli k staticheskomu chlenu proishodit obrashchenie s pomoshch'yu operacij dostupa, vyrazheniya, stoyashchie sleva ot . ili -> ne ekvivalentny. Staticheskij chlen mem sushchestvuet dazhe, esli ne sozdano ni odnogo ob容kta klassa c1. V primere nizhe run_chain, idle i drugie chleny sushchestvuyut dazhe, esli ne bylo sozdano ni odnogo ob容kta klassa process: class process { static int no_of_process; static process* run_chain; static process* running; static process* idle; // ... public: // ... int state(); static void reshedule(); // ... }; Zdes' k funkcii reshedule mozhno obratit'sya bez ukazaniya ob容kta klassa process takim obrazom: void f() { process::reshedule(); } Staticheskie chleny global'nyh klassov inicializiruyutsya tochno tak zhe kak global'nye ob容kty, no oblast' ih vidimosti - fajl, naprimer: void process::reshedule() { /* ... */ }; int process::no_of_process = 1; process* process::running = get_main(); process* process::run_chain = process::running; Staticheskie chleny podchinyayutsya obychnym pravilam dostupa k chlenam klassa ($$R.11), za isklyucheniem togo, chto ih mozhno inicializirovat' v fajlovoj oblasti vidimosti. V tipe staticheskogo chlena ne uchastvuet imya klassa, tak tip process::no_of_process est' int, a tip &process::reshedule() - void(*)(). R.9.5 Ob容dineniya Ob容dinenie mozhno predstavit' kak strukturu, vse chleny imeyut nulevoe smeshcheniya, a razmer ee dostatochno velik, chtoby vmeshchat' lyuboj iz ee chlenov. V lyuboj moment vremeni ob容dinenie mozhet soderzhat' tol'ko odin chlen. V ob容dinenii mogut byt' funkcii-chleny (v tom chisle konstruktory i destruktory), no ne virtual'nye funkcii ($$R.10.2). Ob容dinenie ne mozhet imet' bazovyh klassov i ne mozhet samo ispol'zovat'sya v kachestve bazovogo klassa. CHlenom ob容dineniya ne mozhet byt' ob容kt klassa s konstruktorom ili destruktorom, a takzhe s opredelennoj pol'zovatelem operaciej prisvaivaniya ($$R.13.4.3). Ob容dinenie ne mozhet soderzhat' staticheskih chlenov, predstavlyayushchih dannye. Ob容dinenie vida union { spisok-chlenov } nazyvaetsya bezymyannym ob容dineniem, ono opredelyaet ob容kt bez imeni (i bez tipa). Imena vseh chlenov bezymyannogo ob容dineniya dolzhny otlichat'sya ot drugih imen v toj oblasti vidimosti, v kotoroj opisano ob容dinenie; ih mozhno ispol'zovat' v etoj oblasti vidimosti neposredstvenno, bez obychnyh operacij dostupa k chlenam ($$R.5.2.4). Privedem primer: void f() { union { int a; char* p; }; a = 1; // ... p = "Jennifer"; // ... } Zdes' a i p ispol'zuyutsya kak obychnye peremennye (ne chleny), no poskol'ku oni vhodyat v odno ob容dinenie, ih adresa sovpadayut. Global'nye bezymyannye ob容dineniya mozhno opisat' so specifikaciej static. Bezymyannye ob容dineniya ne dolzhny soderzhat' chastnyh ili zashchishchennyh chlenov ($$R.11), a takzhe funkcij-chlenov. Esli opisany ob容kty ob容dineniya ili ukazateli na nego, to ono ne schitaetsya bezymyannym, naprimer, union { int aa; char* p; } obj, *ptr=&obj; aa = 1; // oshibka ptr->aa = 1; // normal'no Zdes' prisvaivanie prostomu imeni aa nezakonno, t.k. imya chlena ne privyazano ni k kakomu ob容ktu. Inicializaciya ob容dinenij, ne imeyushchih konstruktorov, opisyvaetsya v $$R.8.4.1. R.9.6 Bitovye polya Konstrukciya opisatel'-chlena, imeyushchaya vid, identifikator opt : vyrazhenie-konstanta zadaet bitovoe pole, dlina kotorogo otdelyaetsya ot ego imeni dvoetochiem. Razmeshchenie bitovyh polej v ob容kte klassa zavisit ot realizacii. Polya upakovyvayutsya v nekotorye adresuemye elementy pamyati. Na odnih mashinah polya mogut vyhodit' za granicy etih elementov, na drugih - net. Vyravnivanie bitovyh polej tozhe opredelyaetsya realizaciej. Na odnih mashinah znacheniya pomeshchayutsya v bitovye polya sprava nalevo, na drugih - sleva napravo. CHtoby ustanovit' zadannoe raspolozhenie polej s pomoshch'yu dopolneniya nulyami, ispol'zuyut bezymyannye bitovye polya. Osobyj sluchaj, kogda ispol'zuetsya bezymyannoe pole nulevoj dliny. Ono zadaet vyravnivanie sleduyushchego bitovogo polya po granice elementa pamyati, ispol'zuemogo pri razmeshchenii polej. Bezymyannoe pole ne yavlyaetsya chlenom i ne mozhet inicializirovat'sya. Bitovye polya dolzhny imet' celochislennyj tip ($$R.3.6.1). Ih interpretaciya zavisit ot togo, schitaetsya li znachenie polya s obychnym tipom int (t.e. bez yavnogo ispol'zovaniya signed ili unsigned) znakovym ili bezznakovym. Operaciya vzyatiya adresa & ne primenima k bitovym polyam, tak chto ne mozhet byt' ni ukazatelej na bitovye polya, ni ssylok na nih. R.9.7 Vlozhennye opisaniya klassov Klass mozhno opisat' v opisanii drugogo klassa. Takoj klass nazyvayut vlozhennym. Imya vlozhennogo klassa lokal'no po otnosheniyu k ob容mlyushchemu klassu. Vlozhennyj klass nahoditsya v oblasti vidimosti ob容mlyushchego klassa. Esli ne schitat' yavnogo ispol'zovaniya ukazatelej, ssylok ili imen ob容ktov, to v opisaniyah vlozhennogo klassa dopustimy tol'ko imena tipov, staticheskih chlenov i elementov perechisleniya iz ob容mlyushchego klassa. int x; int y; class enclose { public: int x; static int s; class inner { void f(int i) { x = i; // oshibka: prisvaivanie enclose::x s = i; // normal'no: prisvaivanie enclose ::s ::x = i; // normal'no: prisvaivanie global'nomu x y = i; // normal'no: prisvaivanie global'nomu y } void g(enclose* p, int i) { p->x = i; // normal'no: prisvaivanie enclose ::x } }; }; inner* p = 0; // oshibka: `inner' vne oblasti vidimosti Funkcii-chleny vlozhennogo klassa ne imeyut osobyh prav dostupa k chlenam ob容mlyushchego klassa, oni podchinyayutsya obychnym pravilam dostupa ($$R.11). Analogichno, funkcii-chleny ob容mlyushchego klassa ne imeyut osobyh prav dostupa k