Wykład 3

Transkrypt

Wykład 3
Programowanie obiektowe w C++
Wykład 2
dr Lidia Stępień
Akademia im. Jana Długosza
w Częstochowie
L. Stępień (AJD)
POwCPP
1 / 32
Programowanie proceduralne
Problem dzielony jest na mniejsze fragmenty, zwane modułami.
Programista decyduje jakie chce mieć funkcje(procedury).
Wybiera najlepsze algorytmy.
Projektuje struktury do przechowywania danych.
L. Stępień (AJD)
POwCPP
2 / 32
Programowanie obiektowe
Zdecyduj, jakie chcesz mieć klasy; dla każdej klasy dostarcz pełny
zbiór operacji; korzystając z mechanizmu dziedziczenia jawnie wskaż,
co jest wspólne.
Cechy języka programowania obiektowego:
abstrakcyjne typy danych (klasy)
hermetyzacja danych (ukrywanie)
dziedziczenie
polimorfizm
L. Stępień (AJD)
POwCPP
3 / 32
Hermetyzacja (ang. encapsulation)
Kapsułkowanie, enkapsulacja - ograniczenie dostępności danych i funkcji
wewnętrznych klas i obiektów, udostępnianie ich jedynie za pomocą
specjalnych funkcji nazywanych metodami.
Polimorfizm
Wielopostaciowość - możliwość istnienia wielu metod o tej samej nazwie,
powiązana z możliwością wyboru konkretnej metody podczas wykonywania.
L. Stępień (AJD)
POwCPP
4 / 32
Dziedziczenie
Jedna klasa obiektów może być zdefiniowana jako szczególny
przypadek innej ogólniejszej klasy, a definicje metod i pól danych klasy
ogólniejszej umieszczane są automatycznie w klasie szczególnej.
Klasa ogólna nazywana jest klasą bazową a klasa szczególna klasą
pochodną.
Klasy pochodne mogą definiować swoje własne metody i pola danych,
które mogą przesłaniać dziedziczone metody i pola danych.
Klasa może dziedziczyć właściwości więcej niż jednej klasy dziedziczenie wielorakie.
L. Stępień (AJD)
POwCPP
5 / 32
Programowanie zorientowane obiektowo
Klasy
Definicja klasy tworzy nowy typ danych.
Klasy są opisami obiektów. Obiekty mogą przechowywać dane oraz
wykonywać określone przez programistę zadania.
Szkielet definicji klasy:
class NazwaKlasy {
// treść klasy
};
Na treść klasy składają się definiowane pola i metody.
Pola służą do przechowywania danych.
Metody służą do wykonywania różnych operacji na danych.
L. Stępień (AJD)
POwCPP
6 / 32
Obiekty w C++
Obiekt: abstrakcyjny byt reprezentujący lub opisujący pewną rzecz lub
pojęcie obserwowane w świecie rzeczywistym.
Obiekt przechowuje pewne informacje na swój temat (atrybuty).
Obiekt charakteryzuje się pewnym zakresem zachowań. Można
poprosić obiekt o wykonanie pewnej operacji na samym sobie.
Przykłady:
Klasa zmienna;
Klasa* wskaznik;
wskaznik = new Klasa(argumenty);
Klasa* wskaznik = new Klasa(argumenty);
L. Stępień (AJD)
POwCPP
7 / 32
Pola klas
Pola są składowymi klasy, definiowanymi w jej wnętrzu (inaczej „w
ciele klasy”).
Po utworzeniu zmiennej typu klasowego (obiektu), do jej pól należy
odwoływać się za pomocą operatora wyboru składowej oznaczanego
znakiem kropki ’.’.
zmienna.pole
Po utworzeniu obiektu przy pomocy operatora new, do pól obiektu
należy odwoływać się za pomocą operatora wyboru składowej,
oznaczanego symbolem ’->’.
wskaznik->pole
L. Stępień (AJD)
POwCPP
8 / 32
Metody klas
Metody:
Operacje wykonywane na obiektach. Są wykonywane na skutek wysłania do
obiektu komunikatu, który wywołuje określoną metodę (operację). Metody
noszą również nazwę funkcji składowych.
Metody definiowane są w ciele klasy.
Każda metoda może przyjmować argumenty oraz zwracać wynik.
Argumenty metody to dane, które można jej przekazać.
Metoda może mieć dowolną liczbę argumentów (w szczególności 0)
umieszczonych w nawiasie okrągłym za jej nazwą, oddzielonych
przecinkami.
Metoda, która nie ma argumentów, ma puste nawiasy okrągłe.
Metoda może zwracać wynik przez zastosowanie instrukcji return.
Jeżeli metoda nic nie zwraca, jako zwracany typ należy zastosować
słowo void.
L. Stępień (AJD)
POwCPP
9 / 32
Odwołanie do metod klasy
Po utworzeniu obiektu do jego metod należy odwoływać się:
za pomocą operatora wyboru składowej kropiki ’.’:
Klasa zmienna;
zmienna.metoda(argumenty);
za pomocą operatora wyboru składowej oznaczonego symbolem ’->’,
o ile obiekt został utworzony przy użyciu operatora new:
Klasa* wskaznik = new Klasa(argumenty);
wskaznik->metoda(argumenty);
L. Stępień (AJD)
POwCPP
10 / 32
Modyfikatory dostępu
W języku C++ dostęp do składowych klasy jest określany za pomocą słów
kluczowych (modyfikatorów dostepu):
private: składowe nie są dostępne dla klienta klasy (aplikacji
korzystającej z klasy), dostęp do tych składowych mają tylko
metody klasy,
public: składowe są dostępne dla klienta klasy, nie ma ograniczeń
dostępu,
protected: wykorzystywane podczas dziedziczenia, dostęp do nich
mają metody klasy lub metody klas potomnych.
Uwaga
Domyślnie, jeżeli przed pierwszą składową klasy nie występuje żadne
okreslenie, dostęp jest prywatny, co oznacza, że dostęp do tej składowej
mają tylko metody definiowanej klasy.
L. Stępień (AJD)
POwCPP
11 / 32
Przykład 1 - definicja klasy
class Baton {
public: //metody
void setNazwa(string nazwaBatonu) { nazwa = nazwaBatonu; }
void setIlosc(int iloscBatonu) { ilosc = iloscBatonu; }
void setCena(float cenaBatonu) { cena = cenaBatonu; }
void wypisz() {
cout << nazwa << ", " << ilosc << " szt., ";
cout << cena << "zl" << endl;
}
private://pola
string nazwa;
int ilosc;
float cena;
};
L. Stępień (AJD)
POwCPP
12 / 32
Przykład 1 - obiekty klasy
int main() {
Baton baton1;
baton1.setNazwa("Mars");
baton1.setIlosc(14);
baton1.setCena(3.15);
baton1.wypisz();
Baton baton2;
baton2.setNazwa("Prince Polo");
baton2.setIlosc(100);
baton2.setCena(1.95);
baton2.wypisz();
}
L. Stępień (AJD)
POwCPP
13 / 32
Przykład 2 - deklaracja metod w definicji klasy
class Baton {
public: //metody
void setNazwa(string nazwaBatonu);
void setIlosc(int iloscBatonu);
void setCena(float cenaBatonu);
void wypisz();
private://pola
string nazwa;
int ilosc;
float cena;
};
L. Stępień (AJD)
POwCPP
14 / 32
Przykład 2 - definicja metod klasy Baton
void Baton::setNazwa(string nazwaBatonu) {
nazwa = nazwaBatonu;
}
void Baton::setIlosc(int iloscBatonu) {
ilosc = iloscBatonu;
}
void Baton::setCena(float cenaBatonu) {
cena = cenaBatonu;
}
void Baton::wypisz() {
cout << nazwa << ", " << ilosc << " szt., ";
cout << cena << "zl" << endl;
}
L. Stępień (AJD)
POwCPP
15 / 32
Przykład 3 - inicjalizacja pól w ciele klasy tylko w C++11
class Baton {
public: //metody
void setNazwa(const string& nazwaBatonu);
void setIlosc(int iloscBatonu);
void setCena(float cenaBatonu);
void wypisz();
private://pola
string nazwa = "";
int ilosc = 0;
float cena = 0.00;
};
int main(){
Baton baton1;
baton1.wypisz();
}
L. Stępień (AJD)
POwCPP
16 / 32
Przykład 4 - Baton.h
#ifndef BATON_H
#define BATON_H
#include <string>
using namespace std;
class Baton {
public: //metody
void setNazwa(const string& nazwaBatonu);
void setIlosc(int iloscBatonu);
void setCena(float cenaBatonu);
void wypisz();
private://pola
string nazwa;
int ilosc;
float cena;
};
#endif
L. Stępień (AJD)
POwCPP
17 / 32
Przykład 4 - Baton.cpp
#include <iostream>
#include "Baton.h"
void Baton::setNazwa(string nazwaBatonu) {
nazwa = nazwaBatonu;
}
void Baton::setIlosc(int iloscBatonu) {
ilosc = iloscBatonu;
}
void Baton::setCena(float cenaBatonu) {
cena = cenaBatonu;
}
void Baton::wypisz() {
cout << nazwa << ", " << ilosc << " szt., ";
cout << cena << "zl" << endl;
}
L. Stępień (AJD)
POwCPP
18 / 32
Przykład 4 - main.cpp
#include <iostream>
#include <string>
#include "Baton.h"
using namespace std;
int main() {
Baton baton1;
baton1.setNazwa("Mars");
baton1.setIlosc(14);
baton1.setCena(3.15);
baton1.wypisz();
}
L. Stępień (AJD)
POwCPP
19 / 32
Konstruktor klasy
Konstruktor gwarantuje poprawną inicjalizację obiektu.
Jest on automatycznie wywoływany przez kompilator, w miejscu, w
którym tworzony jest obiekt, zanim jeszcze klient klasy będzie mógł
podjąć jakiekolwiek działania związane z obiektem.
Konstruktor może posiadać argumenty określające sposób tworzenia
obiektu.
L. Stępień (AJD)
POwCPP
20 / 32
Konstruktory klas
Konstruktor to specjalna metoda, która jest wywoływana podczas
tworzenia obiektu.
Musi mieć nazwę zgodną z nazwą klasy.
Konstruktor nigdy nie zwraca żadnego wyniku, ale nie występuje przed
nim słowo void.
Konstruktor może być bezargumentowy, jak też może przyjmować
argumenty, które zostaną wykorzystane, bezpośrednio lub pośrednio,
np. do zainicjalizowania pól obiektu.
Każda klasa może mieć kilka konstruktorów, różniących się
przyjmowanymi argumentami - przeciążanie konstruktora.
Jeśli w klasie występuje tylko jeden konstruktor i przyjmuje on
argumenty, to przy tworzeniu obiektu należy je podać.
L. Stępień (AJD)
POwCPP
21 / 32
Konstruktory klasy
Jeśli nie zdefiniuje się żadnego własnego konstruktora inicjującego, to
kompilator automatycznie stworzy własny domyślny (czyli bez
parametrów) konstruktor inicjujący. Konstruktor domyślny stworzony
przez kompilator nie przypisuje wartości początkowych składowym
klasy.
Konstruktor domyślny to konstruktor, który może zostać wywołany
bez podawania argumentów.
Zdefiniowanie choć jednego własnego konstruktora spowoduje, że
kompilator przyjmie, że klasa ma własne konstruktory i nie utworzy
swojego konstruktora domyślnego. Jeśli potrzebny jest konstruktor bez
parametrów, trzeba go samemu utworzyć.
W ciele konstruktora (tak jak w każdej innej metodzie) można
wywoływać inne metody.
Podobnie jak w funkcjach i metodach, także w konstruktorach można
zadeklarować wartości domyślne argumentów.
L. Stępień (AJD)
POwCPP
22 / 32
Przykład 5 - Baton.h
#ifndef BATON_H
#define BATON_H
#include <string>
using namespace std;
class Baton {
public: //metody
Baton(const string& nazwaBatonu);
void setNazwa(const string& nazwaBatonu);
void setIlosc(int iloscBatonu);
void setCena(float cenaBatonu);
void wypisz();
private://pola
string nazwa;
int ilosc = 0;
float cena = 0;
};
#endif
L. Stępień (AJD)
POwCPP
23 / 32
Przykład 5 - Baton.cpp
#include <iostream>
#include "Baton.h"
Baton::Baton(const string& nazwaBatonu) {
nazwa = nazwaBatonu;
}
...
L. Stępień (AJD)
POwCPP
24 / 32
Przykład 5 - main.cpp
#include <iostream>
#include <string>
#include "Baton.h"
using namespace std;
int main() {
Baton baton1("Mars");
baton1.setIlosc(14);
baton1.setCena(3.15);
baton1.wypisz();
Baton baton2 = Baton("Mars1");
baton2.setIlosc(4);
baton2.setCena(2.15);
baton2.wypisz();
Baton* baton3 = new Baton("Mars2");
baton3->wypisz();
}
L. Stępień (AJD)
POwCPP
25 / 32
this
Wywołana funkcja składowa klasy (metoda) otrzymuje niejawnie adres
obiektu, na rzecz którego została wywołana. Adres ten jest
przechowywany w zmiennej wskaźnikowej o nazwie this. („Który
obiekt? Ten (this) obiekt.”)
Odwołanie do pól i metod obiektu do którego this się odwołuje,
odbywa się za pomocą operatora wyboru składowej oznaczanego
symbolem ’->’.
Umożliwia to m.in. stosowanie w metodach i konstruktorach
argumentów o nazwach identycznych z nazwami pól klasy.
L. Stępień (AJD)
POwCPP
26 / 32
Przykład 5 - Baton.h
#ifndef BATON_H
#define BATON_H
#include <string>
using namespace std;
class Baton {
public: //metody
Baton(const string& nazwa="");
Baton(const string& nazwa, int ilosc, float cena);
...
private://pola
string nazwa;
int ilosc = 0;
float cena = 0;
};
#endif
L. Stępień (AJD)
POwCPP
27 / 32
Przykład 5 - Baton.cpp
#include <iostream>
#include "Baton.h"
Baton::Baton(const string& nazwa) {
this->nazwa = nazwa;
}
Baton::Baton(const string& nazwa, int ilosc, float cena) {
this->nazwa = nazwa;
this->ilosc = ilosc;
this->cena = cena;
}
...
L. Stępień (AJD)
POwCPP
28 / 32
Metody stałe
Metody, które nie zmieniają wartości pól obiektu mogą, a wręcz powinny
być deklarowane jako const.
class Baton {
public: //metody
...
void wypisz() const;
...
};
void Baton::wypisz() const {
cout << nazwa << ", " << ilosc << " szt., ";
cout << cena << "zl" << endl;
}
L. Stępień (AJD)
POwCPP
29 / 32
Zalecanym sposobem inicjalizacji pól obiektu jest zastosowanie listy
inicjalizacyjnej.
Lista inicjalizacyjna zaczyna się dwukropkiem umieszczonym za
nawiasami zawierającymi argumenty.
Po dwukropku występuje lista argumentów oddzielonych przecinkami,
a po każdym argumencie podaje się w nawiasach wartości początkowe
argumentów.
class Baton {
public:
...
Baton(const string& nazwa, int ilosc = 0, float cena = 0.0);
...
};
Baton::Baton(const string& nazwa, int ilosc, float cena)
:nazwa(nazwa),ilosc(ilosc),cena(cena){}
L. Stępień (AJD)
POwCPP
30 / 32
Destruktory klas
Destruktor jest to specjalna metoda automatycznie wywoływana
podczas usuwania obiektu danej klasy, co ma miejsce, gdy:
kończy się zasięg deklaracji obiektu,
usuwany jest obiekt tymczasowy (patrz wykład 3),
do wskaźnika obiektu zastosowano operator delete.
Celem destruktora jest zakończenie istnienia obiektu danej klasy w
sposób przewidywalny i uporządkowany.
Jeśli nie zdefiniuje się własnego destruktora, to kompilator
automatycznie stworzy własny domyślny destruktor.
Destruktor definiowany przez użytkownika ma taką samą nazwę jak
klasa poprzedzoną znakiem tyldy (∼), jest funkcją bez określonego
typu wyniku. Do destruktora nie przekazujemy żadnych argumentów.
W klasie można zdefiniować tylko jeden destruktor.
L. Stępień (AJD)
POwCPP
31 / 32
Przykład 6 - Destruktor
class Baton {
public:
Baton(const string& nazwa, int ilosc = 0, float cena = 0.0);
~Baton();
...
};
Baton::~Baton() {
cout << "Destruktor" << endl;
}
L. Stępień (AJD)
POwCPP
32 / 32

Podobne dokumenty