wykład z podstawy programowania, BHP z elementami ergonomii


#W procedurze umieszczonej wewnątrz zakresu tablicy instrukcja ReDim może służyć do zmiany liczby wymiarów, definiowania liczby elementów oraz definiowania górnego i dolnego ograniczenia dla każdego z wymiarów. Instrukcja ReDim może być stosowana do zmiany tablicy dynamicznej dowolnie często. Każda jednak taka operacja powoduje utratę isniejących danych w tablicy. Aby powiększyć tablicę i zachować jej dotychczasowe dane, należy użyć polecenia ReDim Preserze. Na przykład, poniższa instrukcja powiększa tablicę varTab o 10 elementów bez utraty bieżących wartości oryginalnych elementów.

#ReDim Preserze warta(UBound(VarTab)+10)

#Uwaga stosując słowo kluczowe Preerve dla tablicy dynamicznej można zmienić jedynie górne ograniczenie ostatniego wymiaru, nie można jednak zmienić liczby wymiarów. Można również używać zmiennych.

Kod programu może być umieszczony w jednym z modułów VB:

module formy

module standardowym

module klasy.

Public Z=true <= dostępna dla wszystkich procedur w projekcie Deklarowania przez Public

Modul Y=100 <= dostępna dla wszystkich procedur w module, deklarowana przez Dim lub Private w General Declaration modułu

Procedura lub funkcja X=10 <= Dostępna jedynie we wnętrzy procedury lub funkcji. Zmienna deklarowana poprzez Dim we wnętrzu procedury

Zmienne publiczne zadeklarowane w module formy muszą być poprzedzone nazwą formy gdy są wywoływane przez procedurę innej formy (frmForm1.Z)

PRZEKAZYWANIE ARGUMENTÓW

#Wszystkie argumenty są przekazywane do procedury przez odwołanie, chyba że zostanie to określone inaczej. Metoda ta jest efektywna , fyż czas przekazywania w ten sposób wszystkich argumentów jest taki sam i zajmują one tę samą wielkość pamięci (4 bajty) wewnątrz procesy niezależnie od typu danych.

#Jeżeli w deklaracji procedury zostanie dodane słowo kluczowe ByVal, wskazany argument będzie przekazywany przez wartość. Argumenty przekazywane przez wartość zajmują w procedurze od 2 do 16 bajtów, zależnie od typu danych argumentów. Większe typy danych (np. String i Wariant) są przekazywane przez wartość nieco dłużej niż małe.

Przekazanie argumentu przez wartość powoduje skopiowanie oryginalnej zmiennej. Zmiany dokonane w arugmencie wewnątrz procedury nie są odzwierciedlane w oryginalnej zmiennej.


#Ponieważ ByVal tworzy kopię argumentu, pozwala to przekazać zmienną typu Wariant do funkcji. Nie można przekazywać zmiennej typu wariant przez odwołanie, jeśli procedura deklarująca argument przyjmuje inny typ danych.

PRZEKAZYWANIE ARGUMENTÓW PRZYKŁAD

Function Silnia (ByVal MojaZm As Integer) `Deklaracja funkcji

MojaZm = MojaZm - 1

If MojaZm = 0 then

Silnia = 1

Exit Function

End If

Silnia = Silnia (MojaZm) * (MojaZm + 1)

End Function

`wywołanie funkcji Silnia dla zmiennej S.

S=5

Debug.Print Silnia(S) `wyświetla 120(5!)

Debug .Print S `wyświetla 5

Gdyby nie dodano słowa ByVal w deklaracji funkcji w tym przykładzie zwróci się zamiast 120, 0.

ARGUMENTY OPCJONALNE PROCEDYRY LUB FUNKCJI

#Argument opcjonalny musi być poprzedzony słowem kluczowym Optional. Umieszcza się go na końcu listy argumentów. Mają one zawsze typ Wariant, którego nie można zmienić. Np. - obliczanie średniej 2 lub 3:

Function Avg(licz1, licz2, Optional licz3)

Dim ileLiczb As Integer

ileLiczb = 3

If IsMissing(licz2) Then licz3 = : ileLiczb = ileLiczb - 1

Avg = (licz1 + licz2 + licz3)/ileLiczb

End Function

#Występująca tu funkcja isMissing(licz3) ustala, czy argument opcjonalny został przekazany procedurze (ma wartość ….

Funkcja MsgBox()

#Składnia

ZmiennaCalkowita = MsgBox( strWiadomość [,[intRodzzj] _ [,strTytul]])

# obowiązkowy argument - strWiadomość - zawierający treść komunikatu, do 1024 znaków. powinien być pisany w jednej linii Można go rozdzielić na pojedyncze linie za pomocą znaków Chr(13), Chr(10)

#argumenty opcjonalne:

#intRodzaj - suma wartości z tabel sterujących (sterowanie bitowe)

#strTytul - łańcuch wyświetlany na pasku nazwy

#wartości zwracane przez funkcję MsgBox() - zmienna całkowita:

1 - cbOK

2 - vbCancel (anuluj)

3 - vbAbort (przerwij)

4 - vbRetry (Ponów próbę)

5 - vbIgnore (ignoruj)

6 - vbYes (tak)

7 - vbNo (nie)

FUNKCJA MSGBOX()

•intRodzaj - suma wartości z table sterujących (sterowanie bitowe):

•VbOKonly - 0 - wyświetla przycisk OK.

•VbOKCancel - 1 - wyświetla przycisk OK. i Anuluj

•VbAbort - AbortRetryIgnore - 2 - wyświetla przerwij ponów ignoruj

• VbYesNoCancel - 3 - wyświetla tak nie anuluj

•VbYesNo - 4 - wyświetla Tak Nie

•VbRetryCancel - 5 - wyświetla Ponów Anuluj

• VbCritical - 16 - …

#Kolejność argumentów można zmienić ale wówczas należy poprzedzić je nazwą, np.:

MsgBox title: = tyt, promet: = pytanie, buttons: = przyciski

sub KomTakNie()

Dim pytanie As String, tyt As String, przyciski As Integer, _

wybPrzycisk As Integer

pytanie = “Czy chcesz zachować skoroszyt” & Chr(13) & Chr(10)

pytanie = pytanie & „pod nazwą” „Marysia.xls””” & Chr(13) & Chr(10)_
& „Jeśli tak, to przygotuj czysty dysk”

`przyciski = vbYesNo = vbQuestion + vbDefaultButton1

przyciski = 36 `+ 4096 ` przyciski = 4 + 32 + 0

tyt = „Zapisz skoroszyt”

wybPrzycisk = MsgBox(Titr:=tyt…

FUNKCJA InputBox()

złuży żeby pobierać od użytkownika dane

#Skłądnia

strZmienna = ImpetBox( strPytanie [, [str tytul] _

[,strDomyslne] [,intXpoz, intYpoz]])

#jeden obowiązkowy argument - strPytanie - zawierający traść komunikatu (max. 1024 znaki)

#argumenty opcjonalne:

• strTytul - łańcuch wyświetlany na pasku nazwy

• strDomyslne - domyślna wartość odpowiedzi, którą możńa zaakceptować lub zmienić

• intXpoz, intYpoz - dokładna pozycja okna na formularzu, w ….

INSTRUKCJA WARUNKOWA

• If TestPorównujący Then

Jedna lub wiele instrukcji

End If

• If TestPorównujący Then instrukcja

• If TestPorównujący Then

jenda lub wiele instrukcji

Else

jedna lub wiele instrukcji

End If

•Instrukcje zagnieżdżone

W przypadku instrukcji zagnieżdżonych lepiej używać struktury:

If warunek1 Then

instrukcje, gdy warunek1 jest prawdziwy

ElseIf warunek2 Then

instrukcje, gdy warunek2 jest prawdziwy

ElseIf warunek3 Then

instrukcje, gdy warunek3 jest prawdziwy

………

Else

instrukcje, gdy wszystkie warunki są fałszywe

End If

INSTRUKCJA Selekt Case

#Skłądnia

Select Case wyrażenie

Case wartość (lub ewartości oddzielone przecinkami)

Jedna lub wiele instrukcji

Case Is relacja

Jedna lub wiele instrukcji

Case wyrażenie1 To wyrażenie2

jedna lub wiele instrukcji

Case Else

jedna lub wiele instrukcji

End Select

PĘTLE

Pętle są zbiorem instrukcji które należy wykonać wielokrotnie. Program dykuje ile razy pętla ta wykona zawarty w niej blok instrukcji i jakie mają być warunki zakończenia jej działania. Pętle są przydatne np. przy wielokrotnm przetwarzaniu złożonych danych

Dwie podstawowe struktury to:

Do … loop (nie wiemy ile razy ma się wykonać)

For … Next (kiedy wiemy ile razy chcemy taką pętlę wykonać)

Pętla Do … Loop

Do

If warunek Then Exit Do

instrukcje

Loop

Wpisane w pętli instrykcje poprzedza instrukcja warunkowa. Pozostałe instrukcje są wykonywane tak długo, aż spełniony warunek narzucony w instrukcji warunkowej. Wówczas następuje opuszczenie pętli.

Pętla Do Until .. Loop

Do Until warunek pętli

instrukcje

loop

Wyjście z pętli następuje w chwili, gdy wpisany warunek przyjmuje wartość True.

Pętla Chile … Loop

Do Chile warunek pętli

jedna lub wiele instrukcji

Loop

Pętla Do Chile .. Loop to pętla, w której wpisane instrukcje powtarzane są dopóki dany warunek ma wartość True.

---------braki

OPERATORY LOGICZNE

• And If(a>b) And(c<d)

• Or If(a>b) Or(c<d)

• Not If Not(strAns = “tak”)

Nawiasy okrągłe () mogą być używane aby zmienić kolejność wykonywania działań. Działania zawarte w nawiasach zawsze są wykonywane przed działaniami poza nawiasami. Wewnątrz nawiasów obowiązuje kolejność wykonywania działań zgodna z priorytetami.

Operator Łączenia łańcuchów (&) nie jest operatorem arytmetycznym ale ma swój priorytet i występuje za wszystkimi operatorami arytmetycznymi i przed operatorami logicznymi.

Operator Like ma taki priorytet jak wszystkie operatory porówniania

Operator Is ..


TRSTOWANIE APLIKACJI

W tworzonej aplikacji zazwyczaj znajduje się wiele błędów. Błędy składniowe są łatwe do poprawienia, ponieważ Visual Basic sam je sygnalizuje. Część jest wykrywana już w czasie pisania kodu programu, a część przy próbie skomplowania. Błędy wykonania ujawniają się dopiero podczas wykonywania programu.

Najtrudniejsze do zlokalizowania są błędy logiczne, ponieważ nie są sygnalizowane przez Visual Basic. Wynikają one z błędu programisty. Dla Visual Basic są poprawionymi instrukcjami, natomiast aplikacja nie działa zgodnie z założeniami programisty.

Najlepszym sposobem na wykrycie błędów jest uruchomienie aplikacji. Visual Basic dostarcza narzędzia, które pomagają śledzić zachowanie aplikacji podczas działania. Jednym z takich narzędzi jest Debugger. Daje on możliwość śledzenia wszystkich szczegółów pracy programu i kontrolowanie wartości zminnych.

Visual Basic zapewnia szeroki asortyment narzędzi do wykrywania błędów i cech, które pomagają zlokalizować i poprawić błędy w kodzie: Tryb przerwania/edycji programu.


Tryb przerwania zatrzymuje uruchomioną aplikację, ale pozostawia jej bieżące zminne i ustawienia właściwości. Jest jakby zaprezentowaniem stanu programu w określonej chwili podczas jego działania. W trybie przerwania można zbadać i zmienić bieżące wartości i właściwości, wprowadzić znaczne modyfikacje kodu i określi jakie instrukcje aplikacji będą uruchomione jako następne. Po zakończeniu edycji, można kontynuować uruchomienie programu. Ta bardzo przydatna ch…

Wyrażenie Watch

Wyrażenia Watch umożliwiają monitorowani wartości określonych zmiennych, właściwości i wyrażeń w czasie działania programu. Wyrażenia Watch są wyświetlone w obszarze Watch okna Debug w trybie przerwania (poza wyrażeniami Watch, które pojawiają się w ich własnym okienku dialogowym). Można przerwać wykonanie programu, kiedy wyrażenie Watch ulega zmianie lub ma wartość True.

Aby dodać wyrażenie Watch do programu należy:

W czasie projektowania lub podczas trybu przerwania wybrać z menu Debug, Add Watch, aby otworzyć okienko dialogowe Add Watch.

W okienku tekstowym Expression należy wpisać zmienną, właściwość lub wyrażenie, które ma być obserwowane.

{Resume powoduje powrót do wiersza który wygenerował błąd}

Przy pomocy mechanizmów obsługi wyjątków możemy obsługiwać wyjątki w tym również możemy obsługiwać błędy które powstają prz…}

Obsługa błędów

On Error Go To etykieta

Przy pomocy Err.Raise możemy generować błędy programowe.

PRACA Z PLIKAMI

• Plik (file) to zbiór powiązanych ze sobą danych. Rozróżnia się pliki tekstowe składające się z łańcuchów znaków typu ASCII, oraz pliki binarne dostępne tylko dla niektórych programów i narzędzi systemowych. Do operacji na plikach i folderach wykorzystywane są funkcje:
# CurDir[(dysk)] - zwraca ścieżkę dla bieżącego folderu na podanym dysku lub bez podania argumentu - na dysku biężącym.

• Dir[(nazwa_ścieszki)] - pozwala sprawdzić czy dany plik lub folder istnieje.

# FileLen (nazwa_ścieżki) - sprawdza wielkości pliku w bajtach. chcąc sprawdzić wielkość kilku plików można zsumować je przy użyciu pętli Do…loop, np.:

Dim plik As String

Dim suma As Long

plik = Dir(“d;\*.*”) `pliki z rozszerzeniem.d;;, lub wszystkie pliki

Dir(„d:\*.*”)

suma = 0

Do Chile plik <>””

suma = suma + FileLen(„d;\” & plik)

plik = Dir

Loop

`Debug.Print „Suma bajtów =” & ….

#GetAtrt(nazwa_ścieżki) - sprawdzanie atrybutów pliku. Funkcja zwraca wynik typu Integer, jako jedna lub sumę stałych określających atrybuty.

Do sprawdzenia atrybutów używany jest operator and. porównujący wartości zwrócona przez funkcję GetrAttr z wartością odpowiedniej stałej.

#SetAttr nazwa_ścieżki, atrybuty - ustawienie atrybutów, np.: SetAttr

#ChDrive dysk - zmiana bieżącego dysku

# ChdDir ścieżka - zmiana bieżącego katalogu bez zmiany bieżącego dysku.

[Nie musimy pamiętać bo zawsze mamy pod ręką naszą przeglądarkę obiektów gdzie są wszystkie funkcje.]

DOSTĘP DO PLIKU

# Dostęp sekwencyjny - stosowany do plików tekstowych w których dane nie są zachowane w ustalonym porządku Posiadają trzy tryby pracy: Input - czytanie z pliku, Outpit - pisanie do nowego pliku (lub nadpisanie poprzednich wartości), oraz Appena - dopisywanie na końcu do isniejącego pliku.

#Dostęp swobodny - stosowany do plików tekstowych, w których dane zachowane są w rekordach o ustalonej wielkości i polach oddzielonych przecinkami. Mają tylko jeden tryb - Random

# Dostęp binarny - stosowany do plików graficznych i innych . Można je otworzyć tylko w trybie Binary.

Open strFilename [For Mode] As [#] intFileNumber

gdzie:

strFilename - nazwa pliku (typu string) wraz ze ściężką dostępu

Mode - operacje wykonywane w zależności od rodzaju dostępu do pliku

[#] - znak opcjonalny,

int FileNumber - liczna całkowita z zakresu 1 do 255 łącząca otwarty plik z określoną liczbą. Numer pliku nazywany jest kanałem pliku.

Kolejny wolny numer pliku zwraca funkcja FreeFile ().

[Oczywiście możemy sobie otwierać kilku plików jednocześnie]

OTWIERANIE PLIKU W RÓŻNYCH TRYBACH

• Otwieranie w trybie sekwencyjnym

Open „TESTFILE” For Input AS #1

•Otwieranie w trybie binarnym tylko do zapisu

Open TESTFILE” For Binary Avvess Write As #1

• Otwieranie w trybie swobodnym poprzedzone definicją rekordu

Type Rekord 1Define user - defined type.

ID As Integer

Name As String * 20

End Type


Dim MyRecorf As Recon ` dejkaracja

Open TESTFILE” For Random As #1 Len = Len(MyRecord)

Funkcja Len podaje liczbę bajtów potrzebnych do zapisu zmienej

• Otwieranie bez możliwości dostępu do innych procesów

Open TESTFILE” For Binary Access Read Lock Read As #1

[przy otwieraniu pliku w trybie swobodnym musimy określić jaka jest długość w bajtach pliku. czyli przy otwieraniu pliku w trybie random musimy określić koniecznie parametr określony przez wartość Len który musi być równy długości rekordu liczonym w bajtach.

Żeby się nie pomylić można użyć właśnie tej funkcji Len która działa na zmiennej MyRecord obliczając długość tego rekordu i ustawia ją jako zmienną len naszego zbioru

Te bajty są zapisywane jeden za drugim czyli ktoś kto odczytuje i nie zna struktury rekordu nie może odczytać (lub będzie miał trudność) plik

Jeżeli otworzymy plik to on przestaje być dostępny dla innych procesów ale możemy tą dostępnością sterować przy pomocy Shared (współdzielenia) Umożliwia to dwóm procesom uruchomionym jednocześnie korzystać z jednego pliku

Możemy dodatkowo blokować czyli ustawiać opcję Lock. możemy określić dla jakiego trybu ma być ten plik zamknięty.]

DOSTĘP DO PLIKU

Do zamknięcia pliku instrukcja Close

Close [#] intFIleNumber1, [#]intNumber2, ……

Close 1, 3, 5

Close ` zamyka wszystkie pliki

Do zapisu danych dowolnego typu do pliku dyskowego otwartego w trybie (Mode) Output lub Appena służy instrukcja:

Write #intFIleNumber [, lista wyrazen]

gdzie: intFileNumber - numer pliku nadany mu instrukcją Open.

Przy zapisie do pliku instrukcją write# obowiązują astępujące reguły:

• elementy znajdujące się w tej samej linii zostaną oddielone przecinkiem,

• każda dana typu string zostaje ujęta w cudzysłowy

• data i czas zapisywany jest w formacie : #yyy-mm-dd hhmm:ss#

• wartości logiczne są zapisywane w formacie : #True# #False#

• wartość Null zapisywana jest #null#, natomiast dane puste nie są zapisywane

Do czytania danych z pliku dyskowego służy instrukcja

Input #intFIleNumber [, lista wyrazen]

Line Input #intFileNumber strVariableName

Koniec pliku zwraca funkcja Eof (intFileNumber)

ZAPIS DO I ODCZYT Z PLIKU NIESEKWENCYJNEGO

•[każdy record otrzymuje swój kolejny numer sekwencyjny I przy pomocy tego numeru do którego możemy uzyskiwać dostęp przy pomocy właściwości obiektu ID i teraz przy wykonywaniu operacji zapisu (Put) operacja odczytu wykonywana przez Get

następnie musimy określić numer kanału pliku z któ®ego będziemy wykonywać proces(??)

a następnie numer rekordu z którego chcemy zapisywać lub odczytywać ]

WŁAŚCIWOŚCI I OBIEKT FileSearch

[vb może korzystać z różnych bibliotek obiektów tak jak np. Application. I jeśli chcemy uzyskać dostęp do jakiegoś obiektu to trzeba zastosować „podstawienie obiektowe”. Czyli mamy generalny obiekt Application który zawiera różne podobiekty. Funkcja FileSearch pozwala uzyskać dostęp do obiektu typu FileSearch (Application.FileSearch)

Przy pomocy tego obiektu możemy wykonywać operację wyszukania obiektów.

With fs - pozwala na wyszukiwanie obiektów na podstawie właściwośći

LookIn = ` ścieżka

FileName = ` szablon wyszukiwania

If .Execute >o then `uruchamia wyszukiwanie plików

(ogólnie instrukcja warunkowa)
End If

End With

TextStream

[jednym z elementów tej właśnie biblioteki Scripting (systemu obsługi systemu) jest element tego systemu czyli FileSystemObject” który trzeba utworzyć żeby się nim posługiwać (Create Object - pozwala na stworzenie odpowiedniego obiektu , VB odwołuje się do konkretnej biblioteki DLL) w celu wykonania poleceń takich jak zapis odczyt itp.

Set fs = CreateObject(„Scripting.FIleSstemObject”)

Set a = fs.CreateTextFile(“c:\testfile.text”, True) ` true czyli istniejący plik zostanie nadpisany

a.WriteLine(„His is a test.”)

a.Close

Właściwości

.AtEndOfLine - logiczna konie wiersza

.AtENdOfStream - logiczna koniec pliku

.Column - numer koumny….

NAPĘDY (WŁAŚCIWOŚIC DRIVES)

[jedną z „kolekcji” naszego obiektu FileSystemObject jest kolekcja napędów fs.Drives]

PLIKI I FOLDERY

EXEL

OPERACJE NA SKOROSZYTACH I ARKUSZACH

• Tworzenie nowego skoroszytu z zastosowaniem metody Add oraz powiązanie go ze zmienną obiektową

Sub AddOne()

Workbooks.Add

End Sub

Sub AddNew()

Set newBook = Work books.Add

With newBook

.Title = “”

.Subject = “”

….

• Arkusze w skoroszycie są numerowane kolejno. Aktywacja arkusza w aktywnym skoroszycie nastpjue poprzez:

Worksheets(nr_arkusza).Activate

Zbiór Worksheets jest wyłącznie zbiorem arkuszy zaiwrających dane, pozostałe arkusze np. zawierające wykresy mogą być aktywowane poleneiem

Sheets(nr_arkusza).Activate

• Arkusze mogą być również rozpoznawane za pomocą ich nazw.

OPERACJE NA KOMÓRKACH I ZAKRESACH

• Odwołanie do komórek i zakresów za pomocą stylu adresowania A1 i polecenia Range:

•Można również używać zakresu w nawiasach [] jako skrótu polecenia Range

Worksheets(„Sheet1”).[A1:B5].ClearContents (nawiasy kwadratowe działają jak Range)

W wersji polskiej używamy nazw akruszy Arkusz1 zamiast Sheet1.

• Odwołanie do pojedynczej komórki

[ funkcja Cells umożliwia dostęp do konkretnej komórki.

Ponieważ nasze zakresy są obiektami więc przy pomocy Union możemy utworzyć kolekcję obiektów

•Odwołania do wierszy i kolumn

- Rows(1) wirsz1

- Rows All wszystkie wiersze

- COlumns(1_ kolumna 1

- Columns („a”) kolumna A

- ColumnsAll wszystkie kolumny

• Odwołąnie do zakresu poprzez jego nazwę

Range(„[Zeszyt1]Arkusz1!MyRange”).Font.Italic = True

Sub ClearRange()…

• Operacje na zakresach posiadających nazwy ułatiwa operacje na komórkach zakresu z zastosowaniem For.

• Zakresowi można również przypisać zmienną obiektową:
Dim myRange As Range

Set myRange = WOrksheets(„sheet1”).Range(„A1:D5”)

myRange.Formula = “=RAND()”

myRange.Font.Bold = True

• Operowanie na komórkach z zastosowaniem przesunięcia względem komórki aktywnej lub innej:

ActiveCell.Offset(1, 3).Font.Underline = xlDouble

(przesunięcie o 1 wiersz w dół I 3 kolumny w lewo od komórki aktywnej)

Odpowiada użyciu adresów względnych przy rejestracji makra.

• Operacje na wszystkich komórkach arkusza:
Worksheets(„Arkusz1).Cells.ClearContents

• Odowanie do spójnego obszaru danych może być dokonane przy pomocy własności CurrentRegion, która wyznacza spójny zakres komórek zawierających dane otaczający komórkę aktywną.

For Each c ln ActiveCell.CurrentRegion.Cells

If Abs(c.Value)<0.01 Then c.Value = 0

next

• Zaznaczenie komórki lub zakresu dokonuje się z zastosowaniem metody Select. Wybrany element jest dostępny dzięki własności Selection.

Użycie właściwości Selection wymaga najpierw aktywacji skoroszytu i aktywacji lub wyboru arkusza, ponieważ właściwość …

•Wykonywanie operacji na większej liczbie aktywnych arkuszy wymaga użycia funkcji Array.

• Możliwe jest kopiowanie danych i formatowań z zakresu jednego arkusza z zastosowaniem metody FillAcrossSheets do pozostałych arkuszy skoroszytu.

Maria Dems

C++

KLASY

• Klasa jest typem obiektu zdefiniowanym przez użytkownika, będącym modelem obiektu rzeczywistego, opisanego zespołem liczb i zachowań.

• Definicja klasy ma postać:

class nazwa_klasy { //ciało klasy }

• Utworzenie jednego egzemplarza obiektu o nazwie obiekt_1 klasy nazwa_klasy ma postać:

nazwa_klasy obiekt_1 ;

• Mając zdefiniowany własny typ, można od niego utworzyć typy pochodne, to znaczy wskaźnik do obiektu tego typu lub przezwisko obiektu tego typu

nazwa_klasy * wsk

nazwa_klasy & przezwisko = obiekt_1;

CIAŁO KLASY

SKŁADNIKI KLASY

• Ciało klasy zawiera deklaracje składników klasy.

• Składnikiem klasy może być obiekt typu wbudowanego (np. int, float), ypu pochodnego (np. float *) lub obiekt jakiejś innej klasy , np.:

class komputer {

public: int liczba_kolor ;

float pamiec ;

char nazwa [20] ; };

• W odwołaniach do składników obiektu posługujemy się notacją:

obiekt. składnik

Referencja.składnik

Wskaźnik -> składnik

SKŁADNIKI KLASY

• Jeżeli mamy zdefiniowany obiekt klasy komputer, to:

komputer mój_komputer ; //definicja egzemplarza obiektu

komputer *wsk_1; // definicja wskaźnika

komputer & twój_komputer = mój_komputer; // defnicja regerecji

• Odwołanie do składnika liczba_kol w obiekcie mój_kompiter będzie miało postać:

mój_komputer.liczba_kol = 256; // odwołanie nazwą obiektu

wsk_1 = & mój_komputer ;

wsk_1 -> liczba_ kol = 256 // odwołanie wskaźnikiem

twój_komputer.liczba_kol = 256 //odwołanie referencją

FUNKCJE SŁADOWE

• Składniki klasy, niezależnie od miejsca zdefiniowania wewnątrz klasy, mają zakres ważności równy obszarowi całej klasy.

• W ciele klasy oprócz składników klasy mogą znajdować funkcje zwane funkcjami składowymi

class komputer {

public:

void licz(int sekundy);

int liczba_kolor ;

float pamiec ;

char nazwa[20];

void wyłącz(void);

• klasa, w przeciwieństwie do funkcji, nie ma początku i końca.

MODYFIKATORY DOSTĘPU W KLASIE

• Zamknięcie w ciele klasy zarówno składników klasy jak i funkcji składowych nazwa się enkapsulacją. Dzięki temu w momencie definicji pojedynczego egzemplarza obiektu danej klasy realizowana jest cała kapsuła.

• Ta kapsuła może być przezroczysta lub nie. Regulują to etykiety: Pivate, Protected oraz Public.

• Etykiety mogą występować w dowolnej kolejności i mogą się powtarzać.

• Jeżeli w definicji klasy nie wystąpi żadna etykieta, to domyślnie zakłada się dostęp private, aż do pojawienia się jakiejś etykiety.

• Etykiety mogą się pojawiać w dowolnym miejscu w ciele klasy wielokrotnie, ale lepiej jest wszystkie składniki o takim samym dostępie zgrupować razem.

Klasa jest typem obiektu natomiast definicja klasy nie tworzy obiektu

W definicji klasy jej składniki nie mogą mieć inicjalizatora

• Mając zdefiniowaną klasę możemy zdefiniować kilka egzemplarzy obiektów danej klasy.

FUNKCJE SKŁADOWE

• Funkcje składowe w pamięci komputera są jednokrotne, ponieważ działają one dla każdego egzemplarza obiektu identycznie.

• Funkcje składowe mają pełny dostęp do wszystkich składników swojej klasy, to znaczy zarówno do danych jak ido innych funkcji które mogą wywoływać.

• Do składnika swojej klasy funkcje składowe odwołują się przez podanie tylko nazwy, np. definiujemy klasę osoba:

class osoba {

char nazwisko[30];

int wiek ;

public : void wpisz (char *,int);

void wydrukuj (); };

FUNKCJE SKŁADOWE

• Definiujemy cztery egzemplarze obiektów klasy osoba, np.:

osoba student, asystent, adiunkt, progesor;

• Wywołanie funkcji składowej ma składnię:

Obiekt.funkcja(argumenty) ;

• Wywołanie funkcji void wpisz (char *,int) dla obiektu student ma postać

student.wpisz(„Jan Kowalski”, 21);

• Wywołanie funkcji składowej z wykorzystaniem wskaźnika:

osoba * wsk : //definicja wskaźnika

wsk = &student; //ustawienie wskaźnika na obiekcie student

wsk ->wpisz(„Jan Kowalski”, 21);

• Wywołanie funkcji składowej przy użyciu referencji:

osoba & uczeń = student; //definicja referencji

uczeń.wpisz („Jan Kowalski”, 21);

• Definicja funkcji składowych może się znaleźć w dwóch miejscach: wewnątrz samej definicji klasy lub poza ciałem klasy.

• Przy definicji funkcji składowej poza ciałem klasy:

- w definicji klasy musi być deklaracja tej funkcji,

- definicja funkcji musi być uzupełniona nazwą klasy , do której ma należeć, oraz operatorem zakresu : , gdyż w przeciwnym przypadku kompilator potraktuje tę funkcję jkao zwykłą funkcję.

DEFINICJA FUNKCJI SKŁADOWYCH WEWNĄTRZ KLASY

class osoba

{ //definicja klasy

char nazwisko[30];

int wiek

public

/**********************definicje funkcji składowych ********************/

void wpisz (char * tekst, int lata):

{ strcpy(nazwisko, napis) ;

wiek = lata

}

/******************************************************************/

void wydrukuj();

{ cout << nazwisko <<”,lat”<<wiek<<endll;

}

……….

• Przy obu sposobach definiowania funkcji składowej ma ona zakres ważności klasy i ma jednakowy dostęp do wszystkich składników swojej klasy,

DEFINICJE FUNKCJI SKŁADOWYCH

• przy definiujemy funkcji składowej wewnątrz klasy, jest ona traktowana jako funkcja typu inlie, dlatego:
- jeżeli ciało funkcji ma nie więcej niż dwie linijki, to definiujemy ją wewnątrz klasy,

- w przeciwnym przypadku definiujemy ją poza definicją klasy

• Jeżeli chcemy, żeby funkcji składowa zdefiniowana poza definicja klasy była inline, to musimy to zaznaczyć w definicji:

inline void osoba : : drukuj()

{

cout <<nazwisko <<”,lat:”<<wiek<<endl:

}

PRZESŁĄNIEANIE NAZW W KLASIE

• Odwołując się do danych składowych publicznych z zewnątrz klasy, należy je poprzedzić nazwą konkretnego egzemplarza obiektu danej klasy.

• Nazwy składników klasy mają zakres klasym a więc w obrębie klasy zasłaniają elementy o takiej samej nazwie leżące poza klasą.

• Do zasłoniętej nazwy globalnej można się dostać za pomocą operatora zakresu (: :).

• Wewnątrz klasy można również zdefiniować zmienną lokalną, która zasłoni nazwę składnika klasy, niezależnie czy jest to nazwa zmiennej czy funkcji.

PRZESYŁANIE OBKETÓW KLASY DO FUNKCJI

• W przypadku funkcji występuje zasłonięcie a nie przeładowani nazwy funkcji, bo każda funkcja ma inny zakres ważności.

• Jeśli kilka funcji składowych klasy ma tę samą nazwę i tylko tóżni się liczbą lub typem argumentów, to występuje przeładowanie funkcji składowych klasy.

• Obiekty klasy mogą być przesyłane do funkcji przez wartość (opcja domniemana) lub przez referencję.

• Przy przesyłaniu obiektów przez wartość, służy on do inicjalizacji swojej kopii wewnątrz funkcji, np. wywołujemy funkcję:

prezentacja(student);

przy czym definicja funkcji ma postać:

void prezentacja (osoba kros)

{ cout <<”Przedstawiam”;

kros.drukuj(); }

to funkcja tworzy na stosie kopiuję egzemplarza obiektu klasy osoba i nadaje jej nazwę ktos.

• Przesyłanie obiektu przez wartość można stosować w przypadku klas posiadających kilka składników.

• W przypadku dużej liczby składników klasy stosuje się przesyłanie przez referencję.

• Referencja jest przezwiskiem egzemplarza obiektu klasy. Przy przesyłaniu takiego obiektu do funkcji, ma ona dostęp do oryginału egzemplarza obiekut, któremu nadaje przezwisko kros, np.:

void prezentacja (osoba &ktos)

{ cout <<”Przedstawiam” ;

ktos.drukuj(); }

• Deklaracja funkcji będzie miała wtedy postać:

vid prezentacja (osoba &);

• Przy wywołaniu funkci składowej na rzecz konkretnego egzemplarza obiektu, do funkcji przesyłany jest wskaźnik do tego konkretnego obiektu.

• Tym adresem funkcja inicjalizuje swój własny wskaźnik his.

• Wskaźnik his pokazuje funkcji na którym konkretnie egzemplarzu obiektu danej klasy funkcja ma pracować.

SKŁADNIK STATYCZNY

• Wskaźnik this stojący przed składnikami klasy

this -> skladnik_klsy

sprawia, że operacje przeprowadzane są na składnikach konkretnego egzemplarza obiektu, dla którego funkcja została wywołana.

• Każdy obiekt danej klasy ma swój własny zestaw danych.

• Mogą istnieć sytuacje, gdy dana dotyczy nie poszczególnych egzemplarzy obiektów klasy, ale klasy jako całości. Taką daną można włączyć w obręb klasy w postaci danej statycznej.

• Składnik statyczny jest tworzony w pamięci jednokrotnie i jest wspólny dla wszystkich egzemplarzy obiektów danej klasy. Istnieje nawet wtedy, gdy jeszcze nie zdefiniowaliśmy żadnego egzemplarza obiektu klasy.

• Przed składnikiem statycznym w deklaracji w ciele klasy jest słowo static, np.:

class grupa {

public :

int x ;

static int składnik ; } ;

• Deklaracja składnika statycznego w ciele klasy nie jest jego definicją.

• Definicję składnika statycznego umieszczamy tak, by miała zakres pliku (globalny). Wtedy nie musi być poprzedzona słowem static, a jedynie konieczny jest operator zakresu, wskazujący do jakiej klasy ta dana należy.

• Może ona wówczas zwierać inicjalizację ., np.:
int grupa: :składnik = 5;

• Składnik statyczny może być też private i również wtedy może być inicjalizowany, natomiast po inicjalizacji prywatny składnik statyczny nie może być ani czytany ani zapisywany.

• Do składnika statycznego można się odnieść trzema sposobami:

- za pomocą nazwy klasy i operatora zakresu;

grupa: :składnik

- za pomocą operatora kropka (o ile istnieją już jakieś egzemplarze obiektu)

obiekt.składnik

- za pomocą wskaźnika do obiektu klasy (należy wcześniej ustawić wskaźnik na dowolny obiekt tej klasy, ponieważ dana statyczna jest wspólna dla wszystkich obiektów klasy)

grupa * wsk;

wsk -> składnik

• Składnik statyczny klasy deklarowanej globalnej zachowuje się tak, jakby miał cechę external, a więc można do niego sięgnąć z innego pliku wchodzącego w skład programu.

• Klasy deklarowane lokalnie nie mogą mieć składników statycznych

FUNKCJA SKŁADOWA STATYCZNA

• Jeżeli w klasie istnieje funkcja pracująca tylko na składnikach statycznych tej klasy, to można ją zadeklarować jako statyczna

•Funkcję składową statyczną można wywołać nie tylko na rzecz jakiegoś obiektu danej klasy, ale również na rzecz klasy, nawet jeśli żaden obiekt jeszcze nie istnieje,

obiekt1.funkcja();

klasa: :funkcja ();

• Przy wywołaniu funkcji statycznej dla konkretnego obiektu, nie jest istotne, który konkretny obiekt ją wywołuje

• Funkcja ta nie może odwołać się do żadnego zwykłego , nie statycznego składnika klasy.

• Wewnątrz funkcji składowej statycznej nie można odwołać się do wskaźnika this, bo wskazuje on na konkretny egzemplarz obiektu danej klasy, natomiast funkcja statyczna wywołana jest na rzecz dowolnego obiektu danej klasy.

• Zastosowania składników statycznych:

SŁADNIKI STATYCZNE I TYPU CONST.

• Funkcja składowa typu const nie modyfikuje danych składowych obiektu, na rzecz którego zostaje wywołana.

• Używana jest, gdy w danej klasie chcemy zdefiniować obiekt typu const, gdyż na rzecz takiego obiektu można jedynie wywoływać funkcje typu const. Ilustruje to przykład:

(funkcja składowa typi const)

#omclude <iostream.h>

class pozycja

{

int x;

int y;

public :

pozycja (int a, intb)

{ x = a;

y = b;

void drukuj (void) const ; //funkcja ta nie modyfikuje pozycji a tylko ją drukuje

void przesun (int a, int b) ; // funkcja ta modyfikuje położenie obiektu klasy pozycja

};

void pozycja: :drukuj() const

{ cout <<x<<”,”<<y<<endl; }

/**********************************************

void pozycja: :przesun (int a, int b)

{ y = a;

y = b; }

/*******************************************

main()

{ pozycja osoba1 (20, 30) ;

pozycja osoba2 (40, 80) ;

const pozycja dom (50, 50) ;

osoba1.drukuj () ; //wywołanie funkcji składowej const na rzecz zwykłego obiektu

osoba2.drukuj() ;

dom.drukuj (); //wywołanie funkcji składowej const na rzecz obiektu typu const

}

(użyty konstruktor domyślny inicjalizujący obiekty)

STRUKTURY I UNIE

• Struktura jest to klasa, w której domyślnie wszystkie składniki są public (w klasie - private).

• Definicja struktury ma postać

struci nazwa_struktury {//lista składników} ;

• Unia pozwala umieścić w tym samym miejscu w pamięci obiekty różnego typu ale tylko jeden w danym momencie.

• Rozmiar unii wynika z rozmiaru największego z obiektów do którego przechowywania może służyć.

• Definicja unii ma postać:
union pojemnik { int a;

float x;

long y;

char z; };

• W tak zdefiniowanej unii można przechowywać obiekt króregoś z wymienionych typów.

• Rozmiar uniii będzie odpowiadał rozmiarowi największego składnika a więc w tym przypadku sieof(long).

• Po zdefiniowaniu egzemplarza obiektu unii w postaci :

nazwa_uii nazwa_egzemplarza_obiektu;

np.: pojemnik kk;

do tej samej pamięci będzie można zapisać daną któregoś typi wymienionego w definicji unii.

• Do skłądnikó unii odwołujemy się analogicznie jak do składnikó klasy,:

kk.i = 5 ;

kk.zn ='t' ; //zapisanie w unii litery t, zamiast cyfry 5

• Typ danej zapisanej do unii i odczytywanej musi być taki sam.

• Do składników unii można się odnosić, analogicznie jak do składników klasy, przez wskaźnik (operatorem ->).

• Składniki unii są domyślnie publiczne, a więc unia jest bardziej zbliżona do struktury niż do klasy, z tą różnicą że składniki struktury są umieszczone w kolejnych miejscach w pamięci a unii - w tym samym.

• Unię można inicjalizować daną odpowiadającą typowi pierwszego składnika z jej listy składników.

union pojemnik { int a ; pojemnik liczba1 = {3};

…..

UNIA ANONIMOWA

• Może istnieć unia anonimowa. jest to unia

- która nie ma nazwy.

- do jej składników odnosimy się podając samą ich nazwę bez kropki, (jak do zwykłych zmiennych) np.:

union {

int a;

float x; a = 4;

long y; x = 3.14;

char z; };

ale każda z danych przechowywana jest kolejno w tym samym obszarze pamięci.

• Wszystkie składniki w unii anonimowej mają dostęp public, a więc nie można zdefiniować składnika jako private.

• W unii anonimowej nie może być funkcji składowych, gdyż są one wywoływane na rzecz konkretnego egzemplarza obiektu a w unii anonimowej nie istnieje ani nazwa unii ani nazwa jakiego ś obiektu.

• Jeśli unia nie ma nazwy, ale istnieje konkretny egzemplarza obiektu tej unii albo ma ona jakiś wskaźnik mogący na nią pokazywać to nie jest to unia anonimowa.

ZAGNIEŻDŻONA DEFINICJA KLASY

• Klasy mogą być zagnieżdżone, w postaci

class A {…………………

class B { ………………..} ;

………………..};

• Definicja klasy wewnętrznej znana jest tylko w obrębie tej klasy a więc jest lokalna dla klasy zewnętrznej.

• Obiekt klasy B może być kreowany tylko w obrębie klasy A.

• Nie moż być więc wskaźnika, który pokazywłaby z zewnątrz na obiekt klasy B.

• Definicje funkcji składowych klasy zagnieżdżonej, oprócz funkcji iline, znajdują się na zewnątrz obu klas, ponieważ funkcje nioe mogą być definiowane lokalnie wewnątrz innych funkcji i bloków. np.:

class A { //definicja klasy zewnętrznej

int k;

class B { //definicja klasy wewnętrznej

float v;

pilic:

void fun1() ;//deklarację funkcji składowych klasy wewnętrznej

void fun2(); };

………………………..};

/****************** definicje funkcji składowych klasy wewnętrznej ****************/

void A: :B : : fun1()

{……………………}

• Przedstawiona definicja oznacza że fun1 jest funkcją składową klasy wewnętrznej B, która ma definicję zagnieżdżoną w zakresie ważności klasy A.

• Klasa wewnętrzna ma zakres ważności ograniczony do klasy zewnętrznej a więc może używać zdefiniowanych w klasie zewnętrznej nazw typów oraz publicznych składników statycznych.

• Jeżeli definicja klasy znajduje się wewnątrz funkcji lub w jakimkolwiek lokalnym bloku oznaczonym dwiema klamrami to ma ona zakres lokalnym ograniczony do bloku tej funkcji.

- Funkcje składowe takiej klasy muszą być zdefiniowane wewnątrz ciała klasy a więc być inline.

- Klasa zdefiniowana wewnątrz funkcji może korzystać ze zdefiniowanych w tej funkcji:

• nazw typów,

• zmiennych statycznych,

• nazw zadeklarowanych w funkcji jako extern,

natomiast nie może używać zmiennych automatycznych funkcji.

- Klasa lokalna nie może mieć swoich składników statycznych.

• Funkcje zaprzyjaźnione z klasą, to funkcje która mimo że nie są składnikami klasy mają dostęp do wszystkich, zarówno prywatnych jak i proctected skłądników klasy.

• Funkcje te deklaruje się wewnątrz definicji klasy poprzedzone słowem kluczowych friend.

• Funkcja zaprzyjaźniona moż być przyjacielem więcej niż jednej klasy.

• Funkcja zaprzyjaźniona nie jest składnikiem klasy, z którą się przyjaźni, dlatego nie ma wskaźnika this do obiektów tej klasy, natomiast do składników klasy, z którą się przyjaźni odnosi się za pomocą kropki lub operatora ->, stosując zapis obiekt.składnik

FUNKCJE ZAPRZYJAŹNIONE

• Funkcja zaprzyjaźniona może być deklarowana w dowolnym miejscu klasy (niezależnie od słów public, private, czy protected).

• Jeżeli wewnątrz klasy zostanie umieszczona definicja funkcji zaprzyjaźnionej to:

• Funkcja zaprzyjaźniona moż być jednocześnie zwykłą funkcją lub też funkcją składową zupełnie innej klasy i wtedy może używać wskaźnika this do obiektów swojej klasy.

• Oprócz funkcji zaprzyjaźnionych mogą istnieć klasy zaprzyjaźnione, których deklarację umieszcza się w ciele klasy, która deklaruje przyjaźnń w postaci:

class pierwsza {

friend class druga ;

//ciało klasy pierwsza

};

• Wszystkie funckje składowe klasy zaprzyjaźnionej mają dostęp do prywatnych skłądnikó klasy deklarującej przyjaźń.

• Dwie klasy mogą się zaprzyjaźnić z wzajemnością, np.:

class druga {

friend class pierwsza ;

//ciało klasy druga

};

• Przyjaźń nie jest przechodnia ani dziedziczna.

KONSTRUKTORY

• Konstruktor to funkcja składowa klasy o takiej samej nazwie jak nazwa klasy służąca do instancji obiektu danej klasy.

#inclide <iostream.h>

class klasa { //w konstruktorze nie podajemy typu wyniku

public : //definicja klasy

int a;

float b;

char c;

klasa (int i, float x, char z) //konstruktor

{a = i; b = x; c = z; } ; };

void drukuj (klasa); //funkcja, której argumentem jest obiekt klasy

main ()

{klasa obiektA (2,3.5, `a') //definicja obiektu klasy: klasa

obiektB (4, 2.34, `z') ;

drukuj (obiektA); // wywołanie funkcji od obiektu klasy: klasa

drukuj (obiektB); // wywołanie funkcji z jawnym wywołaniem…

//**********************************************************************//

void drukuj (klasa sk)
{ cout <<”a =” <<sk.a<<”b = „<<sk.b<<”c = „<<sk.c<<endl:}

• Deklaracja konstruktora nie może zawierać typu nawet void.

• Podstawowe cechy konstruktora są następujące:

• Jeśli obiekt jest składnikiem unii, to jego klasa nie może mieć żadnego konstruktora.

konstruktor pozwala stworzyć obiekty różnych struktur czyli 1) obiektów lokalnych statycznych (uruchomianych przed funkcją main) ponieważ obiekt statyczny

• Konstruktor może być uruchoamiany przy:

•konstruowaniu obiektów globalnych - konstruktor uruchoamiany przed rozpoczęciem funkcji jest uruchamiany przed rozpoczęciem fukcji main.

• konstruowaniu obiektów tworzonych operatorwm new:

void funkcja1()

{ // definicja wskaźnika pokazującego na obiekt klasy klasa

klasa *wsk

//utworzenie obiektu klasy klasa

wsk = new klasa (5, 2.5, `k')}

Utrata adresu przekazywanego przez wskaźnik powoduje utratę kontaktu z obiektem.

• konstruowaniu obiektów przez jawne wywołanie konstruktora:

klasa obiektN (3, 1.5, `n');

klasa obektN = klasa (3, 1.5, `n'): //jawne wywołanie konstruktora

Po przejściu do nowej linii programu likwidowany jest obiekt nienazwany, a jedynie pozostaje obiektN, mający taką samą zawartość co obiekt nienazwany.

Konstruktor domniemany jest to konstruktor, który można wywołać bez żadnego argumentu, np.:

class obiekt { public:

obiekt (int) ; // konstruktor

obiekt (void) ; //konstruktor domniemany

obiekt (float*)

……………………….

Składnikowi klasy możemy w konstruktorze nadać wartość początkową dwoma sposobami:

class obiekt2 { const int k;

float x ;

char z

obiekt2 (float yy, int jj, char zn) ; } ; // deklaracja konstruktora

obiekt2 :: obiekt2 (float yy, int jj, char Zn) : k (jj), z (zn)

{ x = pp; } // definicja konstruktora

KONSTRUKTORY KOPIUJĄCE

klasa :: klasa ( klasa &)

Konstruktor ten służy do skonstruowania obiektu będą cego kopią innego, już istniejącego obiektu tej klasy, np.

K : : K (K&) lub

K : : K (K&, float = 23.45, int* = NULL)

Konstruktor kopiujący może być wowoływany

K obiekt_wzorcowy ; // wcześniej zdefiniowany obiekt K

………………..

K obiekt_nowy = K (obiekt_wzorcowy);

- w sposób niejawny

Konstruktor kopiujący pracuje na argumencie prześłąnym przez referencję a więc może ten obiekt zmienić. Aby temu zapobiec można umieścić w definicji takiego konstruktora słowo const.

K : : K ( const K & )

Wysłany obiekt nie musi być stały ale nie będzie zmieniony

DESTRUKTORY

Destruktor to specjalna funkcja składowa klasy, wywoływana wtedy, gdy obiekt danej klasy ma być likwidowany. Ma on nazwę taką samą jak klasa ale poprzedzoną wężykiem. Nie ma on określonego typu zwracanego i nie posiada argumentu. Destruktor może wywołać jakąś funkcję składową swojej klasy. Nie można pobrać adresu destruktora. Obiekt klasy mającej destruktor nie może być składnikiem unii.

Destruktor można wywołać jawnie, w postaci:

Obiekt ~ klasa () ;

wskaźnik -> ~ klasa () ;

Jeśli destruktor wywołujemy z wnętrza klasy, to należy użyć wskaźnika this w postaci:

this -> ~ klasa ();

Destruktor nie może być ani const, ani volatile, ale w odróżnieniu do zwykłej funkcji składowej, może pracować na takich obiektach swojej klasy.

TABLICE OBIEKTÓW

Po zdefiniowaniu klasy można tworzyć tablice obiektów danej klasy, np.

class osoba { // definicja klasy

public:

char nazwisko [15];

char imie [20] ;

int wiek ; } ;

możemy sdefiniować tablicę obiektów tej klasy w postaci :
osoba student [10] ; //definicja 10 elementowej tablicy

Do publicznych składników klasy możemy się odnosić:

student [5] . nazwisko

student [7] . imię

Można zdefiniować wskaźnik pokazujący na obiekty klasy osoba , w postaci:

osoba * wsk ;

i ustawić go na konkretny obiekt wsk = & student [9] ;

wsk ++ ; wsk -> wiek

DZIEDZICZENIE

Dziedziczenie jest to technika polegająca na definiowaniu nowej klasy przy wykorzystaniu klasy już istniejącej. Jest to tworzenie klas pochodnych na podstawie klasy bazowej.

Proces dziedziczenia może być kontynuowany, to znaczy klasa pochodna możę być klasą bazową dla innej klasy. Klasa pochodna dziedziczy z klasy bazowej wszystkie jej pola i metody umieszczone w części protected, natomiast nei ma dostępu do pól imegor zdefiniowanych w części private. Przykładowo, klasa Naukowiec jest klasą pochodną od klasy Osoba:

Osoba =>

Definicja klasy Osoba ma postać:

class Osoba

{

public :

String nazwisko, imie ;

int wiek ;

Osoba (); //konstruktor domyślny

Osoba (String a Nazwisko, String aImie, int Wiek) ;

// konstruktor

void WpiszNazwisko (String Nazwisko)

void WpiszImie (String aImie);

void WpiszWiek (int aWiek);

void wydrukuj ();

};

Użycie słowa pulbic przed nazwą klasy bazowej oznacza że publiczne składowe kalsy bazowej są również publiczne w klasie pochodnej.

(składniki publiczne w klasie bazowej muszą być publiczne w klasie pochodnej)

(bardziej dostępny nie może być mniej dostępny)

W klasie pochodnej można zdefiniować :

* dodatkowe dane składowe

* dodatkowe funkcje składowe

* składnik, który istnieje już w klasie bazowej (można go skorygować)

Wyrażenie po dwukropku jest nazywane listą pochodzenia. Na liście pochodzenia oboknazwy klasy podstawowej znajduje się specyfikator dostępu - public.

Kasa pochodna może mieć postać:
class Nauczyciel : public Osoba {

public:

char adres [25] ;

void wydrukuj ();

};

Ma ona również dostęp do wszystkich składników klasy Osoba.

Składniki oddziedziczone mają zakres klasy podstawowej, na co nakłada się zakres klasy pochodnej. Jest to zagnieżdżenie bloków np.

{ int x;

int k; // składniki oddziedziczone z klasy podstawowej

{ int x ;

int m; // składniki klasy pochodnej; składnik x tej klasy zasłania składnik x oddziedziczony

} }

Do zasłoniętego składnika klasy podstewoewej można odwołać się przy pomocy kwalifikatora zakresu np./

Nauczyciel proferor1 //definicja obiektu klasy pochodnej

profesor1.wydrukuj (); // wywołanie dunkcji z klasy pochodnej

proferor1.Osoba : : wydrukuj (); // wywołanie funkcji z klasy podstawowej

Odziedziczenie dotyczy klas a nie obiektów.

przykład:

include<iostream.h>

class ryba { //klasa podstawowa

private :

int a;

protected :

int prots ;

public:

int pubs ;

void wstaw(int m ) {a = m ; }

int czytaj() {return a ; }

};

/////////////////////////////////////////////////////

class rekin : public ryba { //klasa pochodna

float x

public :

void funk ();

};

tu definiujemy funkcję rekin która nic nie zwraca która na liście pochodzenia ma funkcję funk…

void rekin::funk()

{

x = 15.6

//a = 6 ; // dostęp d prywatnego składnika klasy podstawowej jest niemożliwy

wstaw(6) ; //dostęp za pośrednictwem funkcji składowej

cout << „\n składnik a =” <<czytaj();

prots = 77 ;

pubs = 100 ;

cout << „\n bezposr. odczytany składnik protected = „ << prots

<< „\n bezposr. odczytany składnik bubilc = „ <<pubs ;

}

/************************************************************/

main()

{

rekin wacek ;

wacek.funk();

}

innej metody nie ma

• W przypadku specyfikatora dostępu private, można w klasie pochodnej zmienić zakres dziedziczonych składników nieprywatnych, za pomocą deklaracji dostępu ale tylko na taki, jaki był w klasi podstawowej , np.

class Nauczyciel : private Osoba {

public:

Osoba : : wiek ; // deklaracja dostępu

……………….. };

• Deklaracja dostępu dotyczy składników nieprywatnych, które zostały oddziedziczone prywatnie. Nie można dziedziczyć:

- konstruktorów - należy je oddzielnie zdefiniować dla klasy pochodnej, bo konstruktory klasy podstawowej mogą być niekompletne w klasie pochodnej,

- operatorów przypisania w odniesieniu do obiektów

- destruktorów.

Dziedziczenie może być kilkustopniowe, np.:

class A {

……………………… };

class B : public A {

………………………. } ;

class C : public B {

…………………………..} ;

• Dla klasy C klasa A jest klasą podstawową pośrednio. Przy dziedziczeniu kilkupokoleniowym publicznym składniki pierwszej klasy podstawowej są dostępne dla ostatniej klasy pochodnej. W przypadku jakiegokolwiek dziedziczenia pośredniego prywatnego składniki klasy przestają być bezpośrednio dostępne dla kolejnych klas potomnych.

• Przy tworzeniu klas potomnych nie musimy znać dokładnie wszystkich funkcji składowych klasy podstawowej. Dzięki funkcji dziedziczenia można stworzyć hierarchię klas i wprowadzić relację między poszczególnymi klasami.

Przykład

Osoba =>

=>Nauczyciel =>

=> Profesor

=> Adiunkt

=> Student

Obiekty znajdujące się na dole hierarchii mogą być tak traktowane jakby były na górze hierarchii np. Funkcja składowa klasy Osoba może być wywoływana dla obiektu klasy Osoba, ale również dla obiektu klasy profesor.

WYWOŁANIE KONSTRUKTORA

• Przy konstruowaniu obiektu klasy pochodnej najpierw należy uruchomić konstruktor klasy podstawowej, później konstruktory innych klas, jeżeli obiekty tych klas są składnikami obiektu klasy pochodnej, a dopiero potem konstruktor klasy pochodnej. Konstruktor klasy pochodnej zawiera na liście inicjlailzacyjnej wywołanie konstruktora klasy podstawowej np. mamy klasę podstawową A oraz klasę pochodną B

class A {

public :

A (); //konstruktor domniemany klasy A

A (fiat) ; // konstruktor klasy A

………………..

};

class B : public A {

B() //konstruktor domniemany klasy B

};

/////////////////////////////////////definicja konstruktora klasy B

B : : B ( int x ) A()

{

// ciało konstruktora

}

• Wywołanej konstruktora na liście inicjalizacyjnej można pominąć jeśli:

- klasa podstawowa niema konstruktora

- ma konstruktory, między którymi jest konstruktor domniemany.

• Na liście inicjalizacyjnej umieszcza się tylko konstruktory klas podstawowych bezpośrednich. Nie można inicjalizować obiektów już istniejących.

• Destrukcja obiektów przebiega w odwrotnej kolejności.

DZIEDZICZENIE WIELOKROTNE

Dziedziczenie wielokrotne występuje wtedy, jeśli klasa wywodzi się od więcej niż jednej klasy podstawowej (tylko w c++). Pozwala ono na powiązanie ze sobą niezależnych od siebie typów klas, np.:

class podstawa_1 {

……………………………..};

class podstawa_2 {

……………………………….};

class pochodna : public podstawa_1, public podstawa_2 {
……………………………………………………………………..};

Lista pochodzenia klasy pochodnej może być dowolnie długa i zwierać wiele klas podstawowych.

Konstruktor klasy pochodnej przy wielokrotnym dziedziczeniu zawiera na liście inicjalizacyjnej ewentualne wywołania konstruktorów swych bezpośrednich klas podstawowych - po jednym dla każdej klasy podstawowej.

DZIEDZICZENIE WIELOKROTNE

•Przy dziedziczeniu wielokrotnym może wystąpić wieloznaczność, to znaczy sytuacja gdy klasa podstawowa_1 posiada składnik x oraz klasa podstawowa_2 też posiada składnik x. Wtedy odwołanie do nazwy x w obrębie funkcji składowej klasy pochodnej dziedziczonej z obu klas podstawowych kompilator zasygnalizuje błąd nawet jeśli oba składniki będą miały różny zakres dostępu ponieważ najpierw sprawdzana jest jednoznaczność a dopiero potem dostęp. Należy wówczas w odwołaniu zastosować operator zakresu, np.

podstawowa_1 :: x, lub podstawowa_2 :: x

• Zastosowania operatora zakresu może spowodować niejednoznaczność hierarchii klas dlatego lepiej jest w klasie pochodnej zdefiniować składnik lub funkcję składową o tej samej nazwie który zasłoni oba składniki z obu klas podstawowych. W tej funkcji można odnieść się do odpowiedniego składnika klasy podstawowej z użyciem operatora z zakresu np.:

int pochodna : : x ()

{return podstawowa_1 : : x ; }

• jeśli jednakowy składnik występuje w jednej bezpośredniej klasie podstawowej i w ninnej klasi podstawowej na wyższym poziomie hierarchii to wielonzaczność nie występuje gdyż składnik bliższy przesłoni składnik dalszy.

• Przy odnoszeniu się do odziedziczonego składnika występującego na szczycie hierarchii, wystarczy podać zakres klasy podstawowej na dowolnym poziomi hierarchii.

A {x} B C {x} D {x}

E F G

H

• Odwołując się w klasie pochodnej H do składnika x z klasy podstawowej A możemy napisać:

A : : x ; lub E : : x ;

DZIEDZICZENIE WIRTULANE

• Przy tworzeniu klasy pochodnej na liście bezpośrednich klas podstawowych każda klasa może pojawić się tylko jeden raz. Możliwe jest jednak żeby jakaś bezpośrednia klasa podstawowa wystąpiła jeszcze raz w hierarchii jako dalszy przodek, jako klasa podstawowa wirtualna ( poprzedzona słowem virtual).

A A

B C

D

• W przedstawionym schemacie w klasie pochodnej D występuje dublowanie składników z klasy A, dziedziczonych zarówno z klasy B jak przedstawiony schemat można zastąpić schematem:

A

B C

C

W tym przypadku klasy B i C dziedziczą bezpośrednio klasę A wirtualnie.

class B : public virtual A {

…………………………………} ;

class C : public virtual A {

…………………………………} ;

class D public A public B {

…………………………………};

Klasa wirtualna jest to klasa dziedziczona wirtualnie.

• Ta sama klasa może być dziedziczona wirtualnie i niewirtualne.

Wówczas w obiekcie klasy pochodnej (na samym dole hierarchii) utworzony jest jednej wspólny zestaw składników będących rezultatem wszystkich wirtualnych dziedziczeń klasy a ponadto w obiekcie tym będą również odrębne zestawy składników klasy podstawowej utworzone w wyniku dziedziczenia zwykłego.

• Wirtualne dziedziczenie klasy może być private lub public. Jeżeli chociaż jedne dziedziczenie wirtualne klasy jest public to efekt jest taki jakby wszystkie dziedziczenia tej klasy były public.

• Przy dziedziczeniu wirtualnym klasa najbardziej pochodna (tzn. taka która tworzy obiekt nie będący już podobiektem żadnego obiektu) uruchamia konstruktor klasy wirtualnej dlatego klasę dziedziczoną wirtualnie dobrze jest wyposażyć w konstruktor domniemany gdyż dzięki temu nie trzeba znać całej hierarchii dziedziczenia.

przykład:

class A { //klasa dziedziczona wirtualnie

public:

A () { } ; //konstruktor domniemany

A (int) { } ; //konstruktor zwykły

………………………} ;

class B : public virtual A {

public :

b () : A (2) { } ; //wywołanie konstruktora zwykłego klasy A (dziedziczonej bezpośrednio na liście inicjalizowanej konstruktora klasy B

…………………………} ;

class C : public virtual A {

public :

C () : A (2) { } ; //wywołanie konstruktora zwykłego klasy A (dziedziczonej bezpośrednio na liście inicjalizowanej konstruktora klasy C

• W tym przypadku wywołania konstruktora klasy A umieszczone na liście inicjalizacyjenj konstruktorów klasy B oraz C zostaną zignorowane. Jeżeli utworzymy klasę E bezpośrednio pochodną od klasy D

class E : public D {

public :

E () : D ()

{…………………..} ; };

to z listy inicjalizacyjnej konstruktora klasy E zostanie wywołany konstruktor domniemany klasy wirtualnej A ( bo nie ma na liście konstruktora zwykłego). Wszystkie inne napotkane w hierarchii wywołania konstruktora klasy A zostaną zignorowane.

• Jeżeli klasa wirtualna oraz klasa pochodna od klasy wirtualnej definiują składnik o tej samej nazwie to klasa pochodna dominuje nad klasą wirtualną i zasłania składnik klasy wirtualnej.

FUNCKJA WIRTUALNA

• Funkcja wirtualna to specjalny rodzaj funkcji składowej wywoływanej za pomocą wskaźnika lub referencji do obiektu klasy podstawowej. O tym którą wersję funkcji należy wywołać decyduje nie typ skaźnika ale to na co on pokazuje.

• Funkcja jest wirtualna jeśli:

- w definicji klasy przy deklaracji funkcji stoi słowo virtual

- w jednej z klas podstawowych danej klasy identyczna funkcja (z identyczną sygnaturą) składowa zadeklarowana jest jako virtual.

figura

kwadrat okrag romb

• Słowo virtual występuje tylko raz w klasie podstawowej i nie musi być powtarzane w definicjach tych funkcji w klasach pochodnych wszystkie funkcje o takiej samej sygnaturze w hierarchii będą wirtualne.

Funkcja wirtualna jest to funkcja wielopostaciowa, której postać jest uzależniona od tego jaki obiekt ją wywołuje a więc jeżeli przykładowo mamy funkcję rysuj zdefiniowaną dla klasy bazowej jako funkcja wirtualna i ta sama funkcja jest zaimplementowana w klasach pochodnych to w programie w zależności od obiektu jakiej klasy ta funkcja zostanie wywołana, zostanie wybrana odpowiednia wersja tej funkcji.

Funkcja w sposób „inteligętny” dostosowuje się do wywołującego ją obiektu i ta cecha nosi nazwę polimorfizmu.

Klasa abstrakcyjna jest to klasa bazowa która posiada składniki i funkcje ale nie ma instancji obiektów i jest stworzona tylko na potrzeby dziedziczenia. Klasa abstrakcyjna może zawierać funkcje wirtualne.



Wyszukiwarka