Podstawy
programowania
obiektowego
Ćwiczenia laboratoryjne nr 1
Temat: Wstęp do programowania obiektowego
Prowadzący:
mgr inż. Dariusz Rataj
Koszalin 2001
Podstawy programowania obiektowego
Skrócony spis treści:
Część 1 - Programowanie obiektowe w języku C++
Część 2 - Programowanie obiektowe w środowisku Borland C++Builder
1. Programowanie obiektowe w języku C++
1.1. Cel programowania obiektowego
Programowanie obiektowe jest próbą "przeniesienia" rzeczywistości na platformę maszyn liczących zwanych
komputerami. Człowiek w życiu codziennym postrzega przedmioty (obiekty) rzeczywiste w sposób intuicyjny nie
zwracając uwagi na szczegóły zachowania czy stanu przedmiotu. W programowaniu strukturalnym programista jest
zmuszony do znajomości wielu parametrów symulowanego obiektu. Celem programowania obiektowego jest
uzyskanie możliwości wydawania poleceń dla symulowanego obiektu rzeczywistego bez konieczności zagłębiania się
w szczegóły jego konstrukcji czy stanu.
1.2. Przykład symulacji obiektu rzeczywistego
W tej części przedstawiony zostanie prosty przykład opisu obiektu rzeczywistego - samochodu. Widząc samochód
jadący ulicą przeciętny człowiek zwróci uwagę jedynie na ogólne cechy pojazdu, np.: wielkość (duży, mały), kolor
itd. Jadąc samochodem "wydajemy polecenia": przyspiesz, zwolnij, zatrzymaj itd. Opis obiektu rzeczywistego na
poziomie języka programowania powinien umożliwić wydawanie tego typu poleceń. Każdy obiekt rzeczywisty
posiada trzy elementy: tożsamość (nazwa), stan lub cechy obiektu, zachowanie (działania na obiekcie).
Przykładowy samochód jest oczywiście obiektem rzeczywistym złożonym z wielu podzespołów, części i możemy
opisać go bardzo szczegółowo. W wielu zastosowaniach wystarczy nam jednak opis tylko niektórych cech obiektu.
Takie podejście do opisu (pewne cechy są istotne inne są bez znaczenia) określane są w teorii obiektowej mianem
abstrakcji. Programista operuje jedynie na pewnym poziomie abstrakcji niezbędnym do zrealizowania celu
oprogramowania, np. inaczej będzie wyglądał opis obiektu programisty piszącego grę "wyścigi samochodowe", a
inaczej opis do celów symulacji wypadków wykonany dla firmy produkującej samochody. Poniżej przedstawiony
został prosty przykład opisu obiektowego (obiektu - samochodu) demonstrujący zasady tworzenia symulacji
obiektu rzeczywistego.
Obiekt rzeczywisty
Definicja typu
obiektowego
Opis obiektu
(Zgodnie ze składnią języka
rzeczywistego
programowania C++)
class samochod {
1. Tożsamość (nazwa) - samochód
2. Stan obiektu (cechy opisujące obiekt): public:
- Marka char marka[20];
- Model char model[20];
- Kolor
int kolor;
- Pozycja (współrzędne x i y)
int pozX, pozY;
3. Zachowanie (działania na obiekcie):
- Nazwanie marki
samochod();
- Nazwanie modelu
void ustawMarke(char *s);
- Zmiana koloru
void ustawModel(char *s);
- Przesunięcie samochodu - zmiana
void ustawKolor(int k);
położenia (pozycji)
void przesun(int x, int y);
};
Prezentowany przykład ogranicza się tylko do elementarnych cech samochodu: marka, model, kolor, pozX (pozycja
X), pozY (pozycja Y) i czterech czynności: ustawMarke, ustawModel, ustawKolor, przesun operujących na cechach.
W terminologii programowania obiektowego cechy opisujące stan obiektu będziemy nazywać polami obiektu (lub
zmiennymi składowymi obiektu) natomiast czynności nazwiemy metodami (lub procedurami i funkcjami
składowymi obiektu).
Strona 2
Podstawy programowania obiektowego
Po zdefiniowaniu obiektu możemy wykorzystać obiekt w programie głównym. Na początek należy zdefiniować
zmienną obiektową klasy samochod:
samochod car1; // deklaracja obiektu (utworzenie instancji obiektu)
Następnie w ciele programu głównego możemy wywołać wcześniej zdefiniowane funkcje i procedury obiektu.
Przykładowy program główny symuluje jazdę samochodu po ekranie monitora (kursory: góra, dół, prawo, lewo).
Pełny kod programu definiującego i wykorzystującego obiekt samochod:
#include
#include
#include
#include
class samochod {
public:
// pola (zmienne)
char marka[20];
char model[20];
int kolor;
int pozX, pozY;
// metody (funkcje)
samochod(); // konstruktor
void ustawMarke(char *s); // ustawienie marki samochodu
void ustawModel(char *s); // ustawienie marki samochodu
void ustawKolor(int k); // ustawienie koloru samochodu
void przesun(int x, int y); // przesuniecie po ekranie
};
samochod::samochod()
{
pozX = 0; pozY = 0;
}
void samochod::ustawMarke(char *s)
{
strcpy(marka, s); // kopiowanie parametru do zmiennej marka
cout << "Marka:" << marka << endl;
}
void samochod::ustawModel(char *s)
{
strcpy(model, s); // kopiowanie parametru do zmiennej model
cout << "Model:" << model << endl;
}
void samochod::ustawKolor(int k)
{
kolor = k; // zmiana zmiennej kolor
textcolor(k); // zmiana koloru znaku na ekranie
cout << "Kolor(nr):" << kolor << endl;
}
void samochod::przesun(int x, int y)
{
pozX += x; pozY += y; // zmiana zmiennych pozX i pozY
if (pozX > 80) pozX=1;
if (pozY > 25) pozY=1;
Strona 3
Podstawy programowania obiektowego
if (pozX < 1 ) pozX=80;
if (pozY < 1 ) pozY=25;
gotoxy(pozX, pozY); // przesuniecie kursora
cprintf("%c", 'X');
}
void main()
{
int key;
clrscr();
samochod car1; // utworzenie obiektu typu samochod
car1.ustawMarke("Audi");
car1.ustawModel("A4");
car1.ustawKolor(RED);
car1.przesun(40,12);
do {
key = getch(); // pobranie kodu klawisza
switch (key) {
case 72: car1.przesun(0,-1); break; // kody kursorow: gora
case 80: car1.przesun(0,1); break; // dol
case 77: car1.przesun(1,0); break; // prawo
case 75: car1.przesun(-1,0); break; // lewo
}
} while (key != 27); // rozne od Esc
textcolor(WHITE);
clrscr();
}
2. Programowanie obiektowe w C++ Builder
2.1. Środowisko programowania pod Windows - C++ Builder
Nowoczesne środowiska programowania pod system Windows takie jak Borland C++ Builder
umożliwiają stworzenie programu okienkowego wykorzystującego gotowe obiekty zdefiniowane
w środowisku graficznym systemu operacyjnego lub w samym środowisku C++Builder. W większości
prostych zastosowań nie będzie konieczne "ręczne" definiowanie własnych obiektów tak jak ma to
miejsce w programowaniu strukturalnym. Większość mozolnej pracy (tworzenie plików, okien,
obiektów kontrolnych itp.) wykonuje za nas środowisko programowania. Proces tworzenia aplikacji
Windows w tego typu środowiskach można ująć w kilku podstawowych etapach:
a) Utworzenie projektu (nazwanie projektu, wskazanie katalogu w którym przechowywane będą
wszystkie pliki składające się na projekt). Na tym etapie tworzone jest (automatycznie) główne
okno aplikacji i główne pliki zródłowe aplikacji.
b) Dodanie obiektów kontrolnych do głównego okna aplikacji (menu, napisy, pola tekstowe,
przyciski itp.).
c) Utworzenie okien dodatkowych posiadających również obiekty kontrolne, które należy
zdefiniować (podobnie jak w głównym oknie aplikacji: patrz pkt. 2 i 3). Okna dodatkowe
najczęściej są aktywowane przez okno główne aplikacji (są aktywowane w metodach obsługi
zdarzeń obiektów kontrolnych), np.: zdarzenie "kliknięcie na przycisku" w głównym oknie aplikacji
spowoduje uruchomienie (aktywowanie) okna dodatkowego.
d) Zdefiniowanie odpowiednich "zdarzeń" i przypisanie ich do obiektów kontrolnych, np.
zdefiniowanie metody (funkcji, procedury), która zostanie wykonana po kliknięciu na przycisku.
e) Skompilowanie i uruchomienie (jeżeli nie ma błędów) oraz przetestowanie działania aplikacji.
Strona 4
Podstawy programowania obiektowego
2.2. Przykład prostej aplikacji w CBuilder - "Ankieta"
Program "Ankieta" będzie umożliwiał przeprowadzenie prostej ankiety osobowej (np. ucznia, studenta)
zawierającej pytania o imię, nazwisko, wiek i klasa. Po wypełnieniu ankiety użytkownik może
wygenerować podsumowanie wykorzystujące dane z ankiety. Podsumowanie zostanie umieszczone w
dodatkowym oknie aplikacji a następnie zapisane do pliku o nazwie wybranej przez użytkownika. Do
zapisania pliku o wybranej nazwie i w wybranym katalogu na dysku można użyć standardowego
obiektu SaveDialog z grupy obiektów Dialogs.
Okno dodatkowe aplikacji
Okno główne aplikacji
Okno zapisu do pliku (okno
standardowe z grupy Dialogs)
a) Utworzenie projektu
Z menu górnego wybieramy polecenie File - New Application. Następnie polecenie File - Save
Project as.... Otworzy się okno dialogowe w którym wybieramy katalog naszego projektu i nazwę
plików (pliku zródłowego Unit1.cpp - plik okna głównego aplikacji; pliku projektu Project1.bpr). Po
wykonaniu tych czynności utworzy się puste okno główne aplikacji gotowe do edycji o nazwie Form1.
Strona 5
Podstawy programowania obiektowego
b) Dodanie obiektów kontrolnych do głównego okna aplikacji
Dodawane obiekty kontrolne możemy wybrać z podręcznego menu obiektów. W głównym oknie
aplikacji "Ankieta" użyjemy obiektów kontrolnych z grupy Standard:
- Label (tekst statyczny).
- Edit (pole tekstowe służące do wprowadzania krótkich tekstów).
- Button (graficzny przycisk)
Label Edit Button
c) Utworzenie okien dodatkowych - okno "Wynik ankiety"
Aby dodać okno do aplikacji wybieramy polecenie File - New Form. Utworzy się nowy obiekt okna o
nazwie Form2 (plik zródłowy Unit2.cpp). Będzie to drugie okno aplikacji - "Wynik ankiety". W drugim
oknie ("Wynik ankiety") aplikacji użyjemy obiektów kontrolnych z grupy Standard:
- GroupBox (ramka grupująca obiekty).
- Memo (pole tekstowe służące do wprowadzania dłuższych tekstów złożonych z kilku linii tekstu).
- Button (graficzny przycisk) x 2.
Memo Button GroupBox
Dodatkowo w tym oknie dodamy standardowe okno SaveDialog z grupy Dialogs (poszukać tego
obiektu). Obiekt ten (okno dialogowe zapisu do pliku) będzie nazywał się SaveDialog1.
Dodajemy także przycisk (Button) "Zamknij".
d) Zdefiniowanie zdarzeń i przypisanie ich do obiektów kontrolnych
- zdarzenia w głównym oknie aplikacji
W oknie głównym aplikacji (obiekt Form1 - "Ankieta") zdefiniujemy jedno zdarzenie - kliknięcie na
przycisku "Zapisz do pliku". W tym celu klikamy na przycisku "Zapisz do pliku" - w oknie Object
Inspector pojawią się właściwości obiektu Button. Przechodzimy do zakładki Events (zdarzenia) i
klikamy dwa razy na zdarzeniu OnClick (kliknięcie na obiekcie). Środowisko programistyczne powinno
utworzyć automatycznie metodę obsługi zdarzenia OnClick o nazwie Button1Click. Teraz definiujemy
tą metodę wpisując wewnątrz fragment kodu w języku C++:
Form1->Memo1->Text = Edit1->Text +" nazywa się "+ Edit2->Text +", ma "+
Edit3->Text +" lat i chodzi do klasy " + Edit4->Text;
Form2->ShowModal();
- Pierwsze polecenie zmienia pole Text obiektu Memo1 okna Form2. W tym poleceniu składamy
tekst obiektu Memo1 odczytując dane (tekst) z pól Edit okna głównego. Każdy obiekt typu Edit
posiada pole Text przechowujące dane wpisane do obiektu, np.: Edit1->Text przechowuje tekst
wpisany w obiekcie Edit1 (imię ankietowanego).
- Drugie polecenie uaktywnia drugie okno w trybie modalnym.
Wszystkie okna systemu Windows mogą pracować w dwóch podstawowych trybach:
- Modalnym (aktywacja procedurą ShowModal),
- Standardowym lub niemodalnym (aktywacja procedurą Show),
Strona 6
Podstawy programowania obiektowego
- zdarzenia w oknie "Wynik ankiety"
W oknie dodatkowym aplikacji (obiekt Form2 - "Wynik ankiety") zdefiniujemy jedno zdarzenie -
kliknięcie na przycisku "Podsumowanie". W tym celu klikamy na przycisku "Podsumowanie" - w oknie
Object Inspector pojawią się właściwości obiektu Button. Przechodzimy do zakładki Events
(zdarzenia) i klikamy dwa razy na zdarzeniu OnClick (kliknięcie na obiekcie). Środowisko
programistyczne powinno utworzyć automatycznie metodę obsługi zdarzenia OnClick o nazwie
Button1Click. Teraz definiujemy tą metodę wpisując wewnątrz fragment kodu w języku Delphi:
if (SaveDialog1->Execute()) Memo1->Lines->SaveToFile(SaveDialog1->FileName);
Obiekt SaveDialog posiada metodę Execute, która uruchamia okno dialogowe wyboru pliku na
dysku. Po zakończeniu działania okna w polu (zmiennej) FileName przechowywana jest pełna
(z pełną ścieżką dostępu) nazwa wybranego pliku. Metoda SaveToFile zapisuje tekst obiektu Memo
do wybranego pliku.
W oknie "Wynik ankiety" znajduje się (patrz: punkt c) przycisk "Zamknij". Dla tego przycisku
definiujemy pole (właściwość) ModalResult równe mrOk. MrOk jest jednym z kilku poleceń okna
otwartego w trybie modalnym i powoduje "potwierdzenie" działań wykonanych w oknie. W naszym
przykładzie spowoduje zamknięcie okna.
e) Skompilowanie, uruchomienie i przetestowanie aplikacji
Po wykonaniu wszystkich wyżej opisanych działań możemy skompilować i uruchomić aplikację. W tym
celu wybieramy polecenie z menu górnego Run - Run. Następnie należy sprawdzić czy wszystkie
zaprogramowane działania wykonują się poprawnie:
- wypełniamy ankietę,
- klikamy przycisk "Podsumowanie",
- klikamy przycisk "Zapisz do pliku" okna "Wynik ankiety",
- wybieramy katalog i podajemy nazwę pliku do którego chcemy zapisać dane - polecenie "Zapisz"
okna SaveDialog,
- teraz można pozamykać okna i zakończyć działanie aplikacji,
- korzystając z dowolnego edytora tekstowego systemu Windows (np. Notatnik) sprawdzamy: czy
został poprawnie utworzony plik tekstowy i czy zawiera poprawny tekst wynikowy ankiety.
2.3. Zadanie do samodzielnego wykonania - "Prosta przeglądarka
graficzna"
Utworzyć program (aplikację) Windows:
Obiekt
Image
Menu górne
obiekt typu
Menu
Grafika
umieszczona
w obiekcie
Image
Strona 7
Podstawy
programowania
obiektowego
Ćwiczenia laboratoryjne nr 2
Temat: Konstruktory, destruktory, funkcje zaprzyjaznione
Prowadzący:
mgr inż. Dariusz Rataj
Koszalin 2001
Podstawy programowania obiektowego ćw nr 2
Spis treści:
1. Konstruktor przeciążony, destruktor obiektu
2. Hermetyzacja - ukrywanie informacji
1. Konstruktor przeciążony, destruktor obiektu
Dla każdej klasy mamy możliwość utworzenia kilku konstruktorów. Może to być konstruktor
bezparametrowy i konstruktor z parametrami. Jeżeli klasa nie posiada zdefiniowanego
konstruktora to kompilator automatycznie doda konstruktor bezparametrowy. Możemy
także samodzielnie zdefiniować działanie konstruktora bezparametrowego. Przykład 1
definiuje klasę Plik otwierającą plik dyskowy do zapisu. Zdefiniowany został konstruktor
bezparametrowy - tworzący plik o nazwie wbudowanej (default.txt) oraz konstruktor
z parametrem - nazwą pliku dyskowego.
Deklaracja zmiennej obiektowej
Plik plik1("proba.txt"); // konstruktor z parametrem - nazwa pliku
wywoła konstruktor z parametrem i utworzy plik dyskowy o nazwie proba.txt.
Deklaracja zmiennej obiektowej
Plik plik2; // konstruktor bezparametrowy - plik default.txt
wywoła konstruktor bezparametrowy i utworzy plik dyskowy o nazwie wbudowanej
default.txt.
Kompilator automatycznie decyduje jaki konstruktor ma być wywołany w zależności od typu
parametrów w deklaracji obiektu.
Konstruktory w przykładzie 1 wykonują operację otwarcia pliku dyskowego. W takiej
sytuacji programista ma obowiązek zadbać o to aby plik ten został zamknięty przed
zakończeniem programu. Operację tą wykonuje destruktor (~Plik). Destruktor jest
wywoływany automatycznie w sytuacji gdy obiekt jest zwalniany (kończy się czas życia
obiektu - w tym przykładzie kończy się program). Dzięki zastosowaniu destruktora
programista nie musi pamiętać (zdarza się zapomnieć:-) o zamknięciu pliku przed
zakończeniem programu. Destruktor powinien również zwalniać pamięć rezerwowaną
dynamicznie w czasie działania programu, zamykać połączenia sieciowe itp.
Przykład 1. Definicja klasy Plik, utworzenie dwóch plików dyskowych
#include
class Plik
{
private:
FILE* plik; // zmienna plikowa
Public:
Plik(); // konstruktor bezparametrowy
Plik(char *NazwaPliku); // konstruktor z parametrem - nazwa pliku
~Plik(); // destruktor
void zapisz(char *line); // metoda zapisujaca linie tekstu do pliku
};
// konstruktor tworzy plik o nazwie wbudowanej default.txt
Plik::Plik()
{
if ((plik = fopen("default.txt", "wt")) == NULL)
{
fprintf(stderr, "Nie moge otworzyc pliku!!!.\n");
}
}
Strona 2
Podstawy programowania obiektowego
// konstruktor tworzy plik o nazwie podanej jako parametr
Plik::Plik(char *NazwaPliku)
{
if ((plik = fopen(NazwaPliku, "wt")) == NULL)
{
fprintf(stderr, "Nie moge otworzyc pliku!!!.\n");
}
}
void Plik::zapisz(char *text)
{
fprintf(plik, text); // zapis lini do pliku
fprintf(plik, "\n"); // przejscie do nastepnej linii
printf("Zapisano do pliku: %s\n\r", text);
}
// destruktor zamyka plik
Plik::~Plik()
{
if (plik) fclose(plik);
}
void main()
{
Plik plik1("proba.txt"); // konstruktor z parametrem - nazwa pliku
Plik plik2; // konstruktor bezparametrowy - plik default.txt
plik1.zapisz("--------- plik proba.txt ------------"); // zapis do 1 pliku
plik1.zapisz("proba zapisu tekstu");
plik1.zapisz("---------- koniec zapisu -------------");
plik2.zapisz("--------- plik default.txt ----------"); // zapis do 2 pliku
plik2.zapisz("proba zapisu tekstu");
plik2.zapisz("---------- koniec zapisu -------------");
}
2. Hermetyzacja - ukrywanie informacji
Projektant-programista ma możliwość ukrycia najbardziej niepewnych części projektu
i przez to zmniejszenia niebezpieczeństwa ewentualnych przeróbek (zmniejszenia wpływu
na pozostałe moduły projektu). W systemach obiektowych przyjęto formalny podział praw
dostępu do interfejsu (warstwy zewnętrznej):
" obszar publiczny (public) widzialny dla wszystkich innych elementów projektu,
" obszar chroniony (protected) widzialny tylko dla podklas danej klasy (niewidzialny
dla innych klas i funkcji),
" obszar prywatny (private) widzialny dla danej klasy i klas, funkcji
zaprzyjaznionych.
Możemy dopuścić funkcję do obszaru prywatnego klasy przez deklarację klasy jako funkcję
zaprzyjaznioną. Funkcja zaprzyjazniona nie jest funkcją składową klasy. W przykładzie 2
zdefiniowane zostały dwie funkcje zaprzyjaznione: odejmij i porownaj.
Przykład 2. Definicja klasy zespolona, demonstracja działań na liczbach zespolonych
#include // cin, cout
#include // fabs, sqrt
#include
#define TRUE 1
#define FALSE 0
// deklaracja klasy (interfejs klasy)
class zespolona
{
Strona 3
Podstawy programowania obiektowego ćw nr 2
public:
zespolona(); // konstruktor
zespolona(double r, double i = 0); // konstruktor
void ustaw(double r, double i); // ustawienie wartosci
void drukuj();
void czytaj();
double modul();
double rzecz() { return re; }
double uroj() { return im; }
zespolona sprzez();
zespolona dodaj(zespolona z);
// funkcje zaprzyjaznione z klasa
friend zespolona odejmij(zespolona z1, zespolona z2);
friend int porownaj(zespolona z1, zespolona z2);
// pola prywatne
private:
double re, im;
};
// definicja metod
zespolona::zespolona()
{
re = 0; im = 0;
}
zespolona::zespolona(double r, double i)
{
re = r; im = i;
}
void zespolona::ustaw(double r, double i)
{
re = r; im = i;
}
void zespolona::drukuj()
{
cout << '(' << re << ", " << im << ')';
}
void zespolona::czytaj()
{
cout << "re = "; cin >> re;
cout << "im = "; cin >> im;
}
double zespolona::modul()
{
return (sqrt(re*re+im*im));
}
zespolona zespolona::sprzez()
{
return zespolona(re, -im);
}
zespolona zespolona::dodaj(zespolona z)
{
return zespolona(re+z.re, im+z.im);
}
// funkcje zaprzyjaznione odejmij i porownaj
zespolona odejmij(zespolona z1, zespolona z2)
{
return zespolona(z1.re-z2.re, z1.im-z2.im);
}
int porownaj(zespolona z1, zespolona z2)
{
if ( fabs(z1.re-z2.re) < 1e-10 && fabs(z1.im-z2.im) < 1e-10 )
return TRUE;
else
return FALSE;
}
Strona 4
Podstawy programowania obiektowego
int main()
{
zespolona z1, z2, z3(1), z4(2, 3);
zespolona z5 = z4; // inicjalizacja
clrscr();
cout << "z1 = "; z1.drukuj(); cout << "\tz1" << endl;
cout << "z2 = "; z2.drukuj(); cout << "\tz2" << endl;
cout << "z3 = "; z3.drukuj(); cout << "\tz3(1)" << endl;
cout << "z4 = "; z4.drukuj(); cout << "\tz4(2, 3)" << endl;
cout << "z5 = "; z5.drukuj(); cout << "\tz5 = z4" << endl << endl;
z1.czytaj();
z2.ustaw(3, -4);
z3 = z1.sprzez();
z4 = z1.dodaj(z2);
z5 = odejmij(z1, z2);
cout << "z1 = "; z1.drukuj(); cout << "\tz klawiatury" << endl;
cout << "z2 = "; z2.drukuj(); cout << "\tustaw(3, -4)" << endl;
cout << "z3 = "; z3.drukuj(); cout << "\tsprzezona do z1" << endl;
cout << "z4 = "; z4.drukuj(); cout << "\tz1 + z2" << endl;
cout << "z5 = "; z5.drukuj(); cout << "\tz1 - z2" << endl << endl;
z1 = z2; // podstawienie
cout << "z1 = "; z1.drukuj(); cout << "\tz1 = z2" << endl;
cout << "Re(z1) = " << z1.rzecz() << endl;
cout << "Im(z1) = " << z1.uroj() << endl;
cout << "|z1| = " << z1.modul() << endl << endl;
if ( porownaj(z1, z2) == TRUE )
cout << "z1 jest rowne z2" << endl;
else
cout << "z1 jest rozne od z2" << endl;
cout << endl << "Nacisnij dowolny klawisz...";
getch();
return 0;
}
Zadania do wykonania na zajęciach i w domu:
1. Zdefiniuj klasę pilka. Klasa powinna zawierać:
" Pole prywatne a typu całkowitego - promień koła.
" Pole prywatne kolor typu całkowitego - kolor koła.
" Konstruktor bezparametrowy inicjujący wartości początkowe pól (wybrać dowolne).
" Konstruktor z parametrami promień i kolor.
" Metodę publiczną powierzchnia - obliczającą pole powierzchni koła.
" Metodę publiczną ustawPromien - zmieniającą promien koła.
" Metodę publiczną ustawKolor - zmieniającą kolor koła.
Zdefiniuj funkcję zaprzyjaznioną porownaj - porównującą czy dwa koła mają takie same
powierzchnie i kolor.
2. Zdefiniuj klasę prostokat. Klasa powinna zawierać:
" Pola prywatne a, b typu całkowitego - dlugość boków prostokąta.
" Konstruktor bezparametrowy inicjujący wartości początkowe pól (wybrać dowolne).
" Konstruktor z parametrami długość i wysokość prostokąta.
" Metodę publiczną powierzchnia - obliczającą pole powierzchni prostokąta.
" Metodę publiczną dajDlugosc - zwracającą długość prostakąta.
" Metodę publiczną dajWysokosc - zwracającą wysokość prostakąta.
Zdefiniuj funkcję zaprzyjaznioną jestKwadrat - porównującą boki prostokąta (czy jest kwadratem).
3. Zdefiniuj klasę punkt. Klasa powinna zawierać:
" Pola prywatne x, y typu całkowitego - współrzędne punktu.
" Konstruktor bezparametrowy inicjujący wartości początkowe pól (wybrać dowolne).
" Konstruktor z parametrami: współrzędne punktu.
" Metodę publiczną dajX - zwracającą wsp. x.
" Metodę publiczną dajY - zwracającą wsp. y.
Zdefiniuj funkcję zaprzyjaznioną porównaj - porównującą współrzędne dwóch punktów (czy punkty
się nakładają).
Strona 5
Podstawy
programowania
obiektowego
Ćwiczenia laboratoryjne nr 3
zajęcia zaplanowane na 4 godziny
Temat: Operatory przeciążone, funkcje operatorowe
Prowadzący:
mgr inż. Dariusz Rataj
Koszalin 2001
Podstawy programowania obiektowego ćw nr 2
Spis treści:
1. Przeciążanie operatorów
2. Funkcje operatorowe składowe klasy
3. Funkcje operatorowe zaprzyjaznione
4. Przykłady
1. Przeciążanie operatorów
Przeciążanie operatora oznacza zdefiniowanie nowego działania operatora dla definiowanej
klasy. W języku C++ mamy możliwość przedefiniowania działania (przeciążenia) prawie
wszystkich operatorów. Wyjątkami są operatory:
. .* ?: :: sizeof
Tworząc nową definicję działania operatora nie zmieniamy jego działania dla typów
standardowych, np.: definiując operator + dla nowotworzonej klasy, działanie tego
operatora dla liczb typu int lub float pozostanie niezmienione. Aby zdefiniować działanie
operatora należy utworzyć funkcję operatorową.
W naszym ćwiczeniu zajmiemy się definicjami podstawowych operatorów dwu
i jednoargumentowych. Funkcje operatorowe możemy zdefiniować jako funkcje składowe
klasy lub jako funkcje zaprzyjaznione klasy (znane z ćwiczenia nr 2).
2. Funkcje operatorowe składowe klasy
- operatory dwuargumentowe
Operator dwuargumentowy, zdefiniowany jako funkcja składowa klasy, po lewej stronie
zawsze ma argument typu definiowanej klasy. W naszym przykładzie będzie to typ
zespolona.
Przykład:
Deklaracja w nagłówku klasy
Typ zwracany
symbol
przez operator
operatora
zespolona operator + (zespolona z);
Słowo kluczowe Prawy argument
"operator" operatora
(typ identyfikator)
Definicja metody
zespolona zespolona::operator + (zespolona z)
{
zespolona z1(re+z.re, im+z.im);
return z1;
}
zasady stosowania:
Strona 2
Podstawy programowania obiektowego
- stosujemy wtedy, gdy lewy argument jest tego samego typu co klasa, np. w operatorach
+ , -, *, /, =, = =,
- definicja metody operatorowej poza klasą posiada identyfikator klasy: zespolona:: , tak
samo jak każda inna metoda klasy.
- operatory jednoargumentowe
Deklaracja w nagłówku klasy
zespolona operator * ();
Definicja metody
zespolona zespolona::operator * ()
{
return zespolona(re, -im);
}
3. Funkcje operatorowe zaprzyjaznione
Tak zdefiniowany operator po prawej i lewej stronie ma argumenty dowolnego typu.
Przykład:
Deklaracja w nagłówku klasy
prawy argument
operatora
Typ zwracany symbol
(typ identyfikator)
przez operator operatora
friend ostream& operator << (ostream& o, zespolona z);
Słowo kluczowe Słowo kluczowe lewy argument
"friend" - metoda "operator" operatora
zaprzyjazniona (typ identyfikator)
Definicja metody
ostream& operator << (ostream& o, zespolona z)
{
return o << '(' << z.re << ")+(j" << z.im << ')';
}
zasady stosowania:
- stosujemy wtedy, gdy lewy argument jest innego typu (może być ten sam typ) co klasa,
np. w operatorach << ,>>. Przeważnie prawy argument jest tego samego typu co
definiowana klasa,
- deklaracja metody operatorowej w nagłówku klasy posiada słowo kluczowe friend
informujące, że jest to metoda zaprzyjażniona (nie jest metodą składową klasy!). W
definicji metody to słowo nie występuje.
Strona 3
Podstawy programowania obiektowego ćw nr 2
- przeważnie typ zwracany przez metodę operatorową jest taki sam jak typ lewego
argumentu (możemy przyjąć to jako zasadę). W naszym przykładzie typ ostream&
(referencja na ostream).
4. Przykłady
Przykład 1. Definicja klasy osoba. Klasa zawiera trzy pola prywatne: nazwisko, imie, pesel typu
tekstowego (tablica znaków), dwie funkcje operatorowe zaprzyjaznione: operator wyjścia << i
operator wejścia >>.
#include // cin, cout, ostream, istream
class osoba
{
private:
char nazwisko[30], imie[20], pesel[12];
public:
osoba();
// operator wyjscia drukuje dane na konsoli
friend ostream& operator <<(ostream& out, osoba& o);
// operator wejscia pobiera dane z konsoli
friend istream& operator >>(istream& in, osoba& o);
};
osoba::osoba()
{
nazwisko[0] = 0; // pierwszy znak tablicy = 0 -> tekst pusty
imie[0] = 0;
pesel[0] = 0;
}
ostream& operator << (ostream &out, osoba& o) // op.wyjscia
{
out << o.nazwisko << " ";
out << o.imie << " ";
out << o.pesel << " ";
return out;
}
istream& operator >> (istream &in, osoba& o) // op.wyjscia
{
in >> o.nazwisko >> o.imie >> o.pesel;
return in;
}
void main()
{
osoba o; // deklaracja obiektu osoba
cout << "\n podaj nazwisko, imie i pesel\n";
cin >> o; // wprowadzenie danych do obiektu
cout << o; // wyprowadzenie danych na ekran
}
Strona 4
Podstawy programowania obiektowego
Przykład 2. Definicja klasy Plik umożliwiającą wyprowadzenie zawartości pliku na ekran. Klasa zawiera
jedno pole prywatne plik typu FILE * (struktura opisująca strumień - plik dyskowy), funkcję
operatorową zaprzyjaznioną definiującą operator wyjścia << .
#include // FILE, fopen, fclose, ...
#include // cout, cin, ostream
class Plik
{
private:
FILE* plik;
public:
Plik(char *NazwaPliku); // konstruktor otwiera plik dyskowy
~Plik(); // destruktor zamyka plik dyskowy
// operator wyjscia drukuje plik na konsoli
friend ostream& operator <<(ostream& out, Plik & pl);
};
Plik::Plik(char *NazwaPliku)
{
if ((plik = fopen(NazwaPliku, "rt")) == NULL)
{
fprintf(stderr, "Nie moge otworzyc pliku!!!.\n");
}
}
Plik::~Plik()
{
if (plik) fclose(plik);
}
ostream & operator << (ostream &out, Plik &pl) // op.wyjscia
{
char ch;
fseek(pl.plik, 0, SEEK_SET); // na poczatek pliku
do
{
ch = fgetc(pl.plik);
out << ch;
}
while (ch != EOF);
return out;
}
void main()
{
Plik p("autoexec.bat");
cout << p;
}
Strona 5
Podstawy programowania obiektowego ćw nr 2
Przykład 3. Definicja klasy zespolona. Przykład ten jest rozszerzeniem przykładu z ćwiczenia nr 2
o szereg operatorów jedno i dwuargumentowych. Funkcje operatorowe zostały zdefiniowane jako
składowe klasy lub jako funkcje zaprzyjaznione. Przykład do samodzielnej analizy.
#include // cin, cout, istream, ostream
#include // fabs, sqrt
#include // clrscr, getch
typedef enum BOOL { FALSE = 0, TRUE };
// deklaracja klasy (interfejs klasy)
class zespolona
{
private:
double re, im;
public:
zespolona() { re = 0; im = 0; }
zespolona(double r, double i = 0): re(r), im(i) { }
void ustaw(double r, double i) { re = r; im = i; }
// przeciazone operatory
zespolona operator * ();
zespolona operator + (zespolona z);
friend zespolona operator - (zespolona z1, zespolona z2);
zespolona& operator += (zespolona z);
friend ostream& operator << (ostream &os, zespolona z);
friend istream& operator >> (istream &is, zespolona &z);
friend BOOL operator == (zespolona z1, zespolona z2);
};
// definicja klasy (implementacja klasy), tzn. definicje funkcji
// skladowych klasy i funkcji zaprzyjaznionych z klasa
zespolona zespolona::operator * ()
{
return zespolona(re, -im);
}
zespolona zespolona::operator + (zespolona z)
{
return zespolona(re+z.re, im+z.im);
}
zespolona operator - (zespolona z1, zespolona z2)
{
return zespolona(z1.re-z2.re, z1.im-z2.im);
}
zespolona& zespolona::operator += (zespolona z)
{
re += z.re; im += z.im;
return *this;
}
ostream& operator << (ostream &os, zespolona z)
{
return os << '(' << z.re << ", " << z.im << ')';
}
istream& operator >> (istream &is, zespolona &z)
{
cout << "re = "; is >> z.re;
cout << "im = "; is >> z.im;
return is;
}
BOOL operator == (zespolona z1, zespolona z2)
Strona 6
Podstawy programowania obiektowego
{
if ( fabs(z1.re-z2.re) < 1e-10 && fabs(z1.im-z2.im) < 1e-10 )
return TRUE;
else
return FALSE;
}
int main()
{
zespolona z1, z2, z3(1), z4(2, 3);
zespolona z5 = z4; // inicjalizacja
clrscr();
cout << "z1 = " << z1 << "\tz1" << endl; // operator << (cout, z1);
cout << "z2 = " << z2 << "\tz2" << endl;
cout << "z3 = " << z3 << "\tz3(1)" << endl;
cout << "z4 = " << z4 << "\tz4(2, 3)" << endl;
cout << "z5 = " << z5 << "\tz5 = z4" << endl << endl;
cout << "Podaj z1:" << endl;
cin >> z1; // operator >> (cin, z1);
z2.ustaw(3, -4);
z3 = *z1; // z3 = z1.operator * ();
z4 = z1 + z2; // z4 = z1.operator + (z2);
z5 = z1 - z2; // z5 = operator - (z1, z2);
cout << "z1 = " << z1 << "\tz klawiatury" << endl;
cout << "z2 = " << z2 << "\tustaw(3, -4)" << endl;
cout << "z3 = " << z3 << "\tsprzezona do z1" << endl;
cout << "z4 = " << z4 << "\t= z1 + z2" << endl;
cout << "z5 = " << z5 << "\t= z1 - z2" << endl << endl;
z4 = z1 + 2; // nie mozna: z4 = 2 + z1;
cout << "z4 = " << z4 << "\t= z1 + 2" << endl;
z4 = z1 - 2; // mozna: z4 = 2 - z1;
cout << "z4 = " << z4 << "\t= z1 - 2" << endl;
z5 = z1 + z2 + 2 - 1 - *z1 + z1 + z2 - 1.5;
cout << "z5 = " << z5;
cout << "\t= z1 + z2 + 2 - 1 - *z1 + z1 + z2 - 1.5" << endl;
z1 = z2; // podstawienie
cout << "z1 = " << z1 << "\tz1 = z2" << endl;
z1 += z2; // z1.operator += (z2);
cout << "z1 = " << z1 << "\tz1 += z2" << endl;
if (z1 == z2) // if ( operator == (z1, z2) )
cout << "z1 jest rowne z2" << endl;
else
cout << "z1 jest rozne od z2" << endl;
cout << endl << "Nacisnij dowolny klawisz...";
getch();
return 0;
}
Strona 7
Podstawy programowania obiektowego ćw nr 2
Zadania do wykonania na zajęciach i w domu:
1. Utwórz klasę wektor - jednowymiarową tablicę wartości typu float. Klasa powinna zawierać:
" pole prywatne p - wskaznik na początek tablicy wartości typu float,
" konstruktor z parametrem typu int - rozmiarem tablicy tworzący dynamicznie tablicę (new) o
odpowiednim rozmiarze,
" destruktor zwalniający pamięć zarezerwowaną przez konstruktor,
" funkcję operatorową >>, tak aby można było wprowadzać dane z klawiatury do wektora,
" funkcję operatorową <<, tak aby można było wyprowadzać dane z wektora na ekran.
2. Utwórz klasę wektor - jednowymiarową tablicę wartości typu int. Klasa powinna zawierać:
" pole prywatne tab - wskaznik na początek tablicy wartości typy int,
" konstruktor z parametrem typu int - rozmiarem tablicy tworzący dynamicznie tablicę (new) o
odpowiednim rozmiarze,
" destruktor zwalniający pamięć zarezerwowaną przez konstruktor,
" funkcję operatorową >>, tak aby można było wprowadzać dane z klawiatury do wektora,
" funkcję operatorową <<, tak aby można było wyprowadzać dane z wektora na ekran.
3. Dla przykładu nr 2 (klasa Plik) rozszerzyć możliwości klasy o funkcje:
" konstruktor przeciążony tworzący nowy plik dyskowy,
" funkcje operatorową >>, tak aby można było wprowadzać dane z klawiatury do nowego pliku
dyskowego,
" funkcję operatorową =, tak aby można było przypisać zawartość pliku,
" funkcję operatorową +, tak aby można było dodawać zawartości dwóch plików. Wraz z
operatorem = otrzymamy możliwość wykonania działania:
void main()
{
Plik plik1("pl1.txt"), plik2("pl2.txt"), plik1("pl2.txt");
plik1 = plik2 + plik3;
}
4. Dla przykładu nr 2 (klasa Plik) rozszerzyć możliwości klasy o funkcje:
" konstruktor przeciążony tworzący nowy plik dyskowy,
" funkcje operatorowe <<, tak aby można było wykonać działanie:
void main()
{
float f = 2.34;
int i = 5;
char tekst[] = "Hallo - to tekst";
Plik plik1("pl1.txt");
plik1 << f; // zapis do pliku wartości typu float
plik1 << i; // zapis do pliku wartości typu int
plik1 << tekst; // zapis do pliku tekstu z tablicy
}
Uwaga!!! Konieczne jest zdefiniowanie trzech oddzielnych operatorów << dla każdego typu danych.
5. Utwórz klasę okrag - obiekt graficzny. Klasa powinna zawierać:
" pola prywatne r - promień, x - wsp. x środka, y - wsp. y środka,
" konstruktor z parametrami: promien, wsp. x i y środka,
" metodę rysuj rysującą okrag w trybie graficznym systemu DOS,
" funkcje operatorową ++ przesuwającą okrąg o 1 punkt w prawo,
" funkcje operatorową -- przesuwającą okrąg o 1 punkt w lewo.
" funkcje operatorową + dodającą dwa okręgi (działanie dodawania można przyjąć dowolne),
" funkcje operatorową = umożliwiającą przypisanie,
" funkcje operatorową == porównującą dwa okręgi.
Strona 8
Podstawy
programowania
obiektowego
Ćwiczenia laboratoryjne nr 4
Temat: Dziedziczenie, metody wirtualne
Prowadzący:
mgr inż. Dariusz Rataj
Koszalin 2001
Podstawy programowania obiektowego ćw nr 2
Spis treści:
1. Dziedziczenie, klasy bazowe i pochodne
2. Metody wirtualne
1. Dziedziczenie, klasy bazowe i pochodne
Dziedziczenie oznacza możliwość tworzenia nowych klas na podstawie klas już istniejących.
Inaczej mówiąc, dziedziczenie polega na przejmowaniu właściwości jednej klasy (klasy
bazowej) przez inna klasę (klasę pochodną), np. możemy utworzyć klasę bazową
samochod i klasy pochodne ciezarowka i osobowy. Klasa samochod powinna posiadać
atrybuty (pola i metody) wspólne dla wszystkich samochodów a klasy ciezarowka i osobowy
atrybuty specyficzne dla konkretnego rodzaju samochodu. Klasy pochodne rozszerzają
możliwości klasy bazowej. Rozwijając przykład można by utworzyć klasy pochodne klas
ciezarowka i osobowy i utworzyć bardziej szczegółowy podział np. klasy klasa_S,
klasa_rodzinny, klasa_Maluch, TIR, dzwig itd.
samochod
osobowy ciezarowka
klasa_S klasa_rodzinny klasa_Maluch dzwig TIR
Rys.1. Hierarchia dziedziczenia - drzewo klas samochodów
W sytuacji gdy klasa pochodna jest klasą bazową dla innych klas mówimy o dziedziczeniu
wielokrotnym. W języku C++ dziedziczenie możemy zrealizować umieszczając w nagłówku
klasy, po dwukropku, listy nazw klas bazowych oddzielonych przecinkami, np.:
class A {...};
class B: A {...}; // klasa B dziedziczy po klasie A
class C: B {...}; // klasa C dziedziczy po klasie B
Umieszczając po dwukropku więcej niż jedną klasę:
class A {...};
class B {...};
class C: A, B {...}; // klasa C dziedziczy po klasie A i klasie B
klasa pochodna dziedziczy komponenty po dwóch (lub więcej) klasach.
Przed nazwą klasy bazowej możemy umieścić modyfikator prawa dostępu: public
i private. Modyfikator public uczyni z publicznych i chronionych komponentów klasy
bazowej publiczne i chronione komponenty klasy pochodnej. Modyfikator private uczyni
z publicznych i chronionych komponentów klasy bazowej prywatne komponenty klasy
pochodnej. Komponenty prywatne klasy bazowej nie będą dostępne dla klasy pochodnej,
np.:
class A {...};
class B {...};
class C: public A, private B {...}; // C dziedziczy po klasie A i klasie B
Strona 2
Podstawy programowania obiektowego
Komponenty publiczne i chronione klasy A będą publicznymi i chronionymi komponentami
klasy C. Komponenty publiczne i chronione klasy B będą komponentami prywatnymi klasy C
(nie będą dostępne dla klas pochodnych klasy C). Dziedziczenie po kilku klasach nazywamy
dziedziczeniem wielobazowym.
2. Metody wirtualne
Metody wirtualne pozwalają na odwoływanie się do nieistniejących jeszcze metod klas
pochodnych, które zamierzamy utworzyć w przyszłości. W przykładzie poniżej (patrz:
Przykład 1) klasa bazowa osoba posiada metodę czysto wirtualną (bez definicji działania
metody) drukuj. Jest to metoda która istnieje tylko w celu nadpisania w klasach
pochodnych. Klasy pochodne pracownik i student nadpisują metodę wirtualną drukuj
definiując jej działanie odpowiednio dla każdej klasy. W programie głównym deklarowany
wskaznik ktos na zmienną obiektową typu osoba jest inicjowany dynamicznie przez
wywołanie konstruktora klasy pracownik a potem student.
osoba *ktos = new pracownik("Ewa Grabowska", 30, 10);
ktos->drukuj();
delete ktos;
ktos = new student("Marek Jankowski", 20, 2);
ktos->drukuj();
delete ktos;
Po każdym zainicjowaniu obiektu wywoływana jest metoda drukuj. Metoda jest wywoływana
na rzecz klasy osoba - pozornie!!! - w rzeczywistości wywoływane są odpowiednie metody
wirtualne drukuj klas pracownik i student. Dzieje się tak dzięki zadeklarowaniu metody
drukuj jako metody wirtualnej - w przeciwnym przypadku wywołanie drukuj powodowałoby
próbę wywołania metody składowej klasy osoba (która nie ma definicji tylko deklarację).
Metody wirtualne stosowane są przede wszystkim w celu rozszerzania możliwości
klas w przyszłości. W strukturach gdzie klasa bazowa posiada wiele klas pochodnych jest to
często jedyna metoda na uporządkowanie pracy ze złożonym systemem obiektów.
Przykładowo, znane wszystkim obiekty kontrolne systemu Windows (TButton, TLabel,
TMemo, TList itd.) dziedziczą po klasie TWinControl (dziedziczenie wielokrotne). Wszystkie
te obiekty posiadają inną reprezentacje graficzną. Przy każdym rysowaniu okna aplikacji
Windows wywoływana jest metoda rysująca dla wszystkich obiektów kontrolnych - metoda
Repaint klasy TWinControl. Ponieważ jest to metoda wirtualna i każda klasa pochodna
TWinControl ją nadpisuje, każdy z obiektów jest rysowany inaczej.
Metody wirtualne są praktyczną realizacją polimorfizmu w programowaniu
obiektowym (polimorfizm - wielopostaciowość). O metodach wirtualnych można powiedzieć
że są to metody, które mają wiele postaci (definicji).
Strona 3
Podstawy programowania obiektowego ćw nr 2
Przykład 1. Definicja klasy bazowej osoba. Klasa zawiera pola chronione: nazwisko, wiek; metodę
czysto wirtualną drukuj. Klasy pochodne pracownik i student posiadają pola specyficzne odpowiednio
dla pracownika i studenta: stazpracy i rokstudiow. Jednocześnie metoda wirtualna drukuj została
nadpisana w obydwu klasach pochodnych.
#include // clrscr, getch
#include // cout
#include // strcpy
// klasa bazowa abstrakcyjna
class osoba
{
public:
osoba(char *nazw, int w);
virtual void drukuj() = 0; // funkcja czysto wirtualna
protected:
char nazwisko[20];
int wiek;
};
// klasa pochodna - pracownik
class pracownik : public osoba
{
public:
pracownik(char *nazw, int w, int staz);
virtual void drukuj();
private:
int stazpracy;
};
// klasa pochodna - student
class student : public osoba
{
public:
student(char *nazw, int w, int rok);
virtual void drukuj();
private:
int rokstudiow;
};
// definicje metod - klasa osoba
osoba::osoba(char *nazw, int w)
{
strcpy(nazwisko, nazw);
wiek = w;
}
// definicje metod - klasa pracownik
pracownik::pracownik(char *nazw, int w, int staz) : osoba(nazw, w)
{
stazpracy = staz;
}
void pracownik::drukuj()
{
cout << "Nazwisko: " << nazwisko << ", ";
cout << "wiek: " << wiek << ", ";
cout << "staz pracy: " << stazpracy << endl;
}
// definicje metod - klasa student
student::student(char *nazw, int w, int rok) : osoba(nazw, w)
{
rokstudiow = rok;
}
void student::drukuj()
{
cout << "Nazwisko: " << nazwisko << ", ";
cout << "wiek: " << wiek << ", ";
cout << "rok studiow: " << rokstudiow << endl;
}
// program glowny
void main()
Strona 4
Podstawy programowania obiektowego
{
clrscr();
// wskaznik na obiekt klasy bazowej abstrakcyjnej
osoba *ktos = new pracownik("Ewa Grabowska", 30, 10);
// dynamiczne wywolywanie funkcji wirtualnej drukuj
ktos->drukuj();
delete ktos;
ktos = new student("Marek Jankowski", 20, 2);
ktos->drukuj();
delete ktos;
cout << endl << "Nacisnij dowolny klawisz...";
getch();
}
Zadania do wykonania na zajęciach i w domu:
1. Utworzyć prosty system grafiki wektorowej rysujący różnego rodzaju obiekty graficzne. Większość
obiektów graficznych możemy wpisać w prostokąt (okrąg, elipsa, linia, prostokąt itd.). System
powinien definiować:
" klasę bazową dla obiektów graficznych - graphObject, posiadającą pola chronione x, y -
współrzędne lewego rogu prostokąta; pola chronione height i width (wysokość i szerokość
prostokąta); metodę czysto wirtualną rysuj(); pola definiujące kolor itp.;
" klasy pochodne klasy graphObject: linia, elipsa, okrag, prostokat. Klasy powinny nadpisywać
metodę rysuj() klasy bazowej i odpowiednio rysować obiekt wpisany w prostokąt.
Program testujący zadeklaruje tablicę wskazników na zmienne typu graphObject:
graphObject* obiekty[20];
a następnie utworzy obiekty graficzne i narysuje, np. tak:
for (int i = 0; i<20; i+=4)
{
obiekty[i] = new linia(...); // parametry zależne od konstruktora
obiekty[i+1] = new elipsa(...);
obiekty[i+2] = new okrag(...);
obiekty[i+3] = new prostokat(...);
}
for (int i = 0; i<20; i++) obiekty[i]->rysuj();
....
for (int i = 0; i<20; i++) delete obiekty[i];
Obiekty graficzne można zainicjować inaczej wg uznania. Gdy rozszerzymy możliwości klas o ruch
po ekranie, możliwośc skalowania obiektów to BDZIE TO!!!
2. Zrealizować strukturę klas jak w punkcie 1 instrukcji (klasa bazowa samochod, pochodne ...).
3. Utworzyć klasę bazową Button (klawisz, przycisk) i klasy pochodne graphButton i textButton. W
zależności od trybu pracy programu (graficzny, tekstowy) przycisk Button będzie miała inną
reprezentację (graficzną lub tekstową).
Strona 5
Wyszukiwarka
Podobne podstrony:
Podstawy Programowania 04 Programowanie Obiektowe
Informatyka Programowanie Obiektowe podstawy
PROZE 3 Podstawy języka, cd programowanie obiektowe
zestawy cwiczen przygotowane na podstawie programu Mistrz Klawia 6
Podstawy Programowania Wersja Rozszerzona
Visual C 6 0 Podstawy programowania
matlab podstawy programowania
JP SS 2 algorytmy i podstawy programowania
Podstawy programowania II 2
podstawy programowania 5
Podstawy programowania 11 2013
podstawa programowa
Programowanie Obiektowe Ćwiczenia 5
podstawa programowa
Podstawy Programowania
więcej podobnych podstron