Słowa kluczowe i nazwy

Transkrypt

Słowa kluczowe i nazwy
Materiał uzyskany ze strony:
http://edu.pjwstk.edu.pl/wyklady/pro/scb/PRG2CPP_files/node1.html
Słowa kluczowe i nazwy
Nazwy (identyfikatory) są wprowadzane do jednostki kompilacji (pliku wraz z innymi
plikami włączonymi za pomocą #include) poprzez deklarację. Deklaracja określa własności
i sposób interpretacji nazwy (zmiennej, funkcji, itd.). Zazwyczaj (choć, jak zobaczymy, nie
zawsze) deklaracja wiąże się z definicją, czyli z przydziałem pamięci na nazwany obiekt.
Obowiązuje przy tym „zasada jednej definicji.”
W jednostce kompilacji nie może być więcej niż jednej definicji tej samej zmiennej,
funkcji, klasy, wyliczenia lub wzorca.
Zasada ta nie dotyczy jednak deklaracji, które mogą się zwykle powtarzać.
Język C++ definiuje pewne słowa kluczowe, jako identyfikatory zarezerwowane: nie mogą
pojawić się w innym znaczeniu niż nadane im w standardzie języka. Poniższa tabela
przedstawia słowa kluczowe języka C++. Nie wszystkie są rzeczywiście używane; niektóre
zarezerwowane zostały dla przyszłych zastosowań.
Tabela: Słowa kluczowe języka C++
and
and_eq
asm
auto
bitand
bitor
bool
break
case
catch
char
class
compl
const
const_cast continue
default
delete
do
double
dynamic_cast else
enum
explicit
export
extern
false
float
for
friend
goto
if
inline
int
long
mutable
namespace
new
not
not_eq
operator
or
or_eq
private
protected
public
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
while
xor
xor_eq
Legalne identyfikatory, inne niż podane tu słowa kluczowe, mogą w zasadzie zawierać
dowolną liczbę znaków alfanumerycznych (liter i cyfr) oraz znaki podkreślenia. W
szczególności nie wolno w nazwach stosować znaków walut (np. znaku dolara). Tak jak
w innych językach, pierwszy znak nazwy nie może być cyfrą.
Litery duże i małe są rozróżnialne; nazwa val_X jest inna niż np. nazwa val_x.
Jeśli nazwa składa się z kilku słów, to oddzielamy je znakami podkreślenia ( numer_klienta)
lub każde słowo, z wyjątkiem, być może, pierwszego, rozpoczynamy od litery dużej
( numerKlienta) - jest to tzw. notacja węgierska.
Zasięg i widoczność zmiennych
Zasięg (ang. scope) deklaracji to ta część programu, gdzie deklaracja jest aktywna, czyli
nazwa deklarowana może być użyta i odnosi się do tej właśnie deklaracji.
Zakres widoczności (ang. visibility) natomiast to ten fragment (fragmenty), w których nazwa
może być użyta bez żadnej kwalifikacji (nazwą klasy, przestrzeni nazw itd.).
Zakres widoczności zadeklarowanej zmiennej może być węższy niż zasięg deklaracji na
skutek przesłonięcia.
Zmienne zadeklarowane poza wszystkimi funkcjami mają zasięg od miejsca deklaracji do
końca pliku (a właściwie jednostki translacji), w szczególności obejmuje on wszystke funkcje
zdefiniowane w tym module po wystąpieniu deklaracji. Zmienne (ogólnie: nazwy)
zadeklarowane poza wszystkimi funkcjami nazywamy zmiennymi globalnymi. W
odróżnieniu od zmiennych lokalnych, definiowanych wewnątrz funkcji, są one
automatycznie inicjowane zerami odpowiedniego typu (dotyczy to również wskaźników). Ich
czas życia to okres od początku do końca działania programu.
Zmienne lokalne są deklarowane wewnątrz funkcji, a ogólniej bloku ograniczonego
nawiasami klamrowymi. Ich zasięg obejmuje część programu od miejsca deklaracji do końca
tego bloku. Parametry funkcji można uważać za zmienne lokalne zdefiniowane na samym
początku funkcji i inicjowane w trakcie wykonania wartościami argumentów wywołania.
Czasem życia niestatycznej zmiennej lokalnej jest czas od napotkania jej definicji przez
przepływ sterowania do jego wyjścia z funkcji, a ogólniej z najwęższego bloku, w którym ta
definicja wystąpiła: w tym momencie zmienne są z pamięci usuwane. W szczególności
oznacza to, że kiedy przepływ sterowania powraca do tej samej funkcji (bloku), zmienne
lokalne są tworzone na nowo i nie „pamiętają” swoich wcześniejszych wartości. Takimi
zmiennymi są też zmienne deklarowane w części inicjalizacyjnej pętli for (część w nawiasie
okrągłym przed pierwszym średnikiem) jak i zmienne deklarowane w części warunkowej
instrukcji if, while, for, switch: ich zasięgiem jest ciało danej instrukcji.
Zmienne globalne mogą być przesłonięte, jeśli wewnątrz funkcji (lub bloku) zadeklarujemy
inną zmienną o tej samej nazwie, (choć niekoniecznie tym samym typie). Wówczas nazwa tej
zmiennej w ciele funkcji odnosi się do zmiennej lokalnej. Zmienna globalna istnieje, ale jest
w zakresie funkcji (bloku) niewidoczna. Nie znaczy to, że nie mamy do niej dostępu. Do
przesłoniętej zmiennej globalnej możemy odwołać się poprzez operator zasięgu ' ::'
(„czterokropek”). Jeśli na przykład przesłonięta została zmienna o nazwie k, to do globalnej
zmiennej o tej nazwie odwołać się można poprzez nazwę kwalifikowaną ::k.
Inicjalizację, operator zasięgu i widoczność zmiennych globalnych ilustruje poniższy
program; demonstruje też deklarowanie zmiennych wewnątrz bloku: jeśli wewnątrz bloku
zasłonimy zmienną lokalną, to ta lokalna zmienna staje się w tym bloku całkowicie
niewidoczna, podczas gdy zmienna globalna o tej samej nazwie jest widoczna w dalszym
ciągu, jeśli użyjemy operatora zasięgu.
P33: przesl.cpp
Widoczność i przesłanianie zmiennych
1. #include <iostream>
2. using namespace std;
3.
4. int k;
5.
6. int main(void)
7. {
8. cout << " k: " << k << endl;
9. cout << "::k: " << ::k << endl;
10.
11.
int k = 10;
12.
13.
cout << " k: " << k << endl;
14.
cout << "::k: " << ::k << endl;
15.
16.
::k = 1;
17.
18.
cout << " k: " << k << endl;
19.
cout << "::k: " << ::k << endl;
20.
21.
{
22.
int k = 77;
23.
cout << "W bloku:" << endl;
24.
cout << " k: " << k << endl;
25.
cout << "::k: " << ::k << endl;
26.
}
27.
28.
cout << "Po bloku:" << endl;
29.
cout << " k: " << k << endl;
30.
cout << "::k: " << ::k << endl;
31. }
Zmienna k zadeklarowana w linii 4 jest zmienną globalną. Jest, zatem widoczna i w funkcji main. W
liniach 8 i 9 drukujemy wartości k - ponieważ k nie zostało przesłonięte inną zmienną, w tym miejscu
programu zarówno k, jak i ::k odnoszą się do tej samej zmiennej - zmiennej globalnej.
W linii 11 wprowadzamy lokalną dla funkcji main zmienną k. Przesłania ona globalne k; od tej pory
użycie w funkcji main nazwy k oznacza odniesienie się do zmiennej lokalnej. Tym niemniej, zmienna
globalna jest wciąż dostępna: trzeba tylko odnosić się do niej za pomocą pełnej nazwy kwalifikowanej
operatorem zakresu - widzimy to w linii 14.
Podobnie, wewnątrz funkcji można zmienić wartość zmiennej globalnej, jeśli prawidłowo się do niej
odwołujemy (linia 16).
W liniach 21-26 wprowadzamy blok wewnętrzny zanurzony w bloku, jakim jest ciało funkcji main.
Wprowadzona w tym bloku zmienna k całkowicie przesłania lokalną dla main zmienną k. Zauważmy
tu na marginesie, że takie przesłonięcie byłoby nielegalne w Javie. Wewnątrz tego zagnieżdżonego
bloku mamy dostęp wyłącznie do k z tego bloku i k globalnego. Możemy się o tym przekonać patrząc
na wynik programu
k: 0
::k: 0
k: 10
::k: 0
k: 10
::k: 1
W bloku:
k: 77
::k: 1
Po bloku:
k: 10
::k: 1
Instrukcja grupująca
Instrukcje grupujące (ang. compound statement, grouping statement) stosuje się, gdy
składnia języka wymaga wystąpienia w pewnym miejscu programu dokładnie jednej
instrukcji, a tymczasem czynności, które mają być wykonane przez program za pomocą
jednej instrukcji zapisane być nie mogą (lub prowadziłoby to do nieczytelnych konstrukcji).
Istnieje, zatem w języku możliwość potraktowania wielu instrukcji jako jednej instrukcji
złożonej (grupującej). Ma ona postać ujętej w nawiasy klamrowe sekwencji instrukcji,
z których każda może być instrukcją pustą (sam średnik), niepustą pojedynczą (a więc
zakończoną średnikiem) lub również instrukcją grupującą (ujętą w nawiasy klamrowe). Po
nawiasie klamrowym kończącym instrukcję grupującą średnika nie stawiamy. Przykładem
instrukcji grupującej jest definicja funkcji.
Pamiętać trzeba, o czym już mówiliśmy, że fragment programu ujęty w nawiasy klamrowe
tworzy blok. Zmienne zadeklarowane wewnątrz takiego bloku tworzonego przez instrukcję
grupującą są lokalne dla tego bloku: po wyjściu sterowania z takiej instrukcji zmienne
zadeklarowane wewnątrz nie są już znane (i w ogóle nie istnieją; są ze stosu usuwane). Więc
{
int i = 5;
{
int k = fun(i);
i += k;
}
cout << "i=" << i << endl;
}
jest jedną instrukcją grupującą, złożoną z trzech instrukcji, z których jedna jest również
instrukcją grupującą. Po wykonaniu tej instrukcji zmienne i i k nie istnieją i, w szczególności,
zmienne o tej nazwie mogą być zadeklarowane w dalszej części ciała funkcji, w której
instrukcja ta wystąpiła.
Operatory
Operatorami są pojawiające się w tekście programu leksemy (znak dodawania, znak
gwiazdki, znak procentu) które są interpretowane jako żądanie wywołania odpowiednich
funkcji operujących na danych określonych przez wyrażenia sąsiadujące z danym operatorem
- są to argumenty tego operatora.
Operatory generalnie dzielą się na jedno- i dwuargumentowe. Jak w większości
programowania, w C/C++ zapis operatorów dwuargumentowych jest infiksowy (wrostkowy),
czyli operator stawiany jest pomiędzy swoimi argumentami. Z kolei zapis operatorów
jednoargumentowych, z dwoma wyjątkami, jest prefiksowy (przedrostkowy), czyli operator
stawiamy przed argumentem. Istnieje w C/C++ również jeden operator trzyargumentowy:
operator selekcji (operator warunkowy).
Priorytety i wiązanie
Zapis infiksowy, wygodny i naturalny dla ludzi, prowadzi jednak do sytuacji, gdy z samego
zapisu nie wynika kolejność wykonania działań w złożonych wyrażeniach. Na przykład
w wyrażeniu
a+b/c
zmienna b może być traktowana, jako prawy argument operatora dodawania albo lewy
argument operatora dzielenia. W pierwszym przypadku obliczymy (a + b)/c, a w
drugim a⋅(b/c) otrzymując różny wynik.
Aby uniknąć tego rodzaju wieloznaczności, wprowadzono pojęcie priorytetu operatorów.
Według priorytetu operatory dzielą się na szereg grup, w ramach, których priorytety są
jednakowe. W sytuacjach, jak opisana, powyżej, gdy to samo wyrażenie może być
potraktowane, jako argument dwóch operatorów, najpierw zostanie wykonana operacja
opisywana przez ten z tych dwóch operatorów, który ma wyższy priorytet. Jeśli natomiast oba
mają ten sam priorytet, kolejność wykonywania operacji będzie określona ich wiązaniem: od
lewej do prawej dla operatorów o wiązaniu lewym i od prawej do lewej dla operatorów
o wiązaniu prawym. Aby ta reguła nie prowadziła do sprzeczności, operatory o takim samym
priorytecie muszą mieć taki sam kierunek wiązania (co w istocie zachodzi). A zatem
w wyrażeniu
a+b/c
najpierw zostanie wykonane dzielenie, gdyż ma wyższy priorytet od dodawania. Ale
w wyrażeniu
a+b-c
najpierw zostanie wykonane dodawanie, gdyż ma ten sam priorytet, co odejmowanie, a oba
operatory mają wiązanie lewe (do a dodawane jest b)
Dla
operatora
przypisania
wiązanie
jest
prawe.
Tak,
więc
w
wyrażeniu a=b=c przypisanie b=c wykonane zostanie najpierw, a jego wynik (wartość b po tej
operacji) przypisany będzie do zmiennej a. Ale np. operator wyboru składowej („kropka”) ma
wiązanie
lewe,
zatem obiekt.sklad1.sklad2 oznacza:
najpierw
wybierz
składową sklad1 obiektu obiekt, potem z wynikowego obiektu składową sklad2.
Wszystkie prefiksowe (przedrostkowe) operatory jednoargumentowe mają wiązanie prawe:
najpierw działa operator z prawej strony, czyli bliższy argumentu. Tak, więc *++p to to samo
co *(++p), natomiast ++*p to ++(*p), bo choć przedrostkowy operator inkrementacji ' ++'
i operator wyłuskania wartości (dereferencji) ' *' mają ten sam priorytet, oba mają wiązanie
prawe.
Operatory zasięgu
Operatory te, o najwyższym priorytecie, wymienione w tabeli operatorów na pozycjach 1-3,
zapisywane za pomocą symbolu „czterokropka” (' ::'). Przypomnijmy, że ::x jest nazwą
globalnej zmiennej x zadeklarowanej poza wszystkimi funkcjami i klasami. Użycie
„czterokropka” jest konieczne tylko wtedy, gdy nazwa (w naszym przypadku x) jest w danym
bloku (funkcji) nazwą innej zmiennej, lokalnej, która wobec tego przesłoniła zmienną
globalną o tej samej nazwie.
W tabeli poniżej przedstawiono wszystkie operatory języka C++.
Operatory podzielone są na 17 grup - każda grupa odpowiada operatorom o tym samym
priorytecie. Grupy wymienione są w kolejności od grupy operatorów o priorytecie
najwyższym, w dół według malejącego priorytetu.
Tabela: Operatory w języku C++
Priorytet 17
1 zasięg klasy
klasa::sklad
2 zasięg przestrzeni nazw
pnazw::sklad
3 zasięg globalny
::nazw
Priorytet 16
4 wybór składowej
obiekt.sklad
5 wybór składowej
wsk->sklad
6 wybór elementu przez indeks
wsk[wyr]
7 wywołanie funkcji
wyr(lista_wyr)
8 konstrukcja wartości
typ(lista_wyr)
9 przyrostkowe zmniejszenie
lwart- -
10 przyrostkowe zwiększenie
lwart++
11 statyczna identyfikacja typu
typeid(typ)
12 dynamiczna identyfikacja typu
typeid(wyr)
13 statyczna konwersja
static_cast<typ>(wyr)
14 dynamiczna konwersja
dynamic_cast<typ>(wyr)
15 konwersja wymuszona
reinterpret_cast<typ>(wyr)
16 konwersja uzmienniająca
const_cast<typ>(wyr)
Priorytet 15
17 pobranie rozmiaru obiektu
sizeof wyr
18 pobranie rozmiaru typu
sizeof(typ)
19 przedrostkowe zmniejszenie
- -lwart
20 przedrostkowe zwiększenie
++lwart
21 negacja bitowa
∼wyr
22 negacja logiczna
!wyr
23 minus jednoargumentowy
-wyr
24 plus jednoargumentowy
+wyr
25 wyłuskanie adresu
&lwart
26 dereferencja
*wyr
27 przydział pamięci na obiekt
new typ
28 przydział pam. na obiekt z inicjowaniem
new typ(lista_wyr)
29 lokalizujący przydział pamięci
new (lista_wyr) typ
30 jak wyżej, z inicjowaniem
new (lista_wyr) typ(lista_wyr)
31 zwolnienie pamięci
delete wsk
32 zwolnienie pamięci tablicowej
33 rzutowanie (konwersja)
delete [] wsk
(typ)wyr
Priorytet 14
34 wybór składowej przez wskaźnik
wsk->*wsk
35 wybór składowej przez wskaźnik
wsk.*wsk
Priorytet 13
36 mnożenie
wyr * wyr
37 dzielenie
wyr / wyr
38 reszta z dzielenia
wyr % wyr
Priorytet 12
39 dodawanie
wyr + wyr
40 odejmowanie
wyr - wyr
Priorytet 11
41 przesunięcie bitowe w lewo
wyr << wyr
42 przesunięcie bitowe w prawo
wyr >> wyr
Priorytet 10
43 mniejsze od
wyr < wyr
44 mniejsze lub równe
wyr <= wyr
45 większe od
wyr > wyr
46 większe lub równe
wyr >= wyr
Priorytet 9
47 równe
wyr = = wyr
48 nierówne
wyr ! = wyr
Priorytet 8
49 koniunkcja bitowa
wyr & wyr
Priorytet 7
50 bitowa różnica symetryczna
wyr ^ wyr
Priorytet 6
51 alternatywa bitowa
wyr | wyr
Priorytet 5
52 koniunkcja (iloczyn) logiczna
wyr && wyr
Priorytet 4
53 alternatywa (suma) logiczna
wyr
wyr
Priorytet 3
54 selekcja
wyr ? wyr : wyr
Priorytet 2
55 przypisanie
lwart = wyr
56 dodawanie z przypisaniem
lwart += wyr
57 odejmowanie z przypisaniem
lwart -= wyr
58 mnożenie z przypisaniem
lwart *= wyr
59 dzielenie z przypisaniem
lwart /= wyr
60 reszta z przypisaniem
lwart %= wyr
61 przesunięcie w lewo z przypisaniem
lwart << wyr
62 przesunięcie w prawo z przypisaniem
lwart >> wyr
63 iloczyn bitowy z przypisaniem
lwart &= wyr
64 alternatywa bitowa z przypisaniem
lwart |= wyr
65 różnica bitowa z przypisaniem
lwart ^= wyr
Priorytet 1
66 zgłoszenie wyjątku
throw wyr
67 operator przecinkowy
wyr , wyr
Omówienie szczegółowe można znaleźć tutaj:
http://edu.pjwstk.edu.pl/wyklady/pro/scb/PRG2CPP_files/node59.html

Podobne dokumenty