zmp

background image

Zaawansowane metody

programowania

Źródła:

J. Grębosz

- Symfonia C++

J. Grębosz

- Pasja C++

N.M. Josuttis - C++. Biblioteka standardowa. Podręcznik programisty

Podręcznik C++

- http://pl.wikibooks.org/wiki/C++

C++ bez cholesterolu - http://www.intercon.pl/~sektor/cbx/

background image

Klasa

... to inaczej typ.

Definiując klasy tworzymy własne typy danych wykorzystywanych
w programach.

Klasa posiada składniki, którymi mogą być

- dane
- funkcje

... czyli definiuje zbiór określonych danych oraz wykonywanych na
nich operacji

==> ENKAPSULACJA

background image

Klasa

Etykiety określające dostęp do składników klasy

private:

deklarowane za tą etykietą składniki (dane i funkcje) są
dostępne tylko z wnętrza klasy

protected:

składniki są traktowane jako prywatne z tą różnicą, że
widoczne są także przez klasy wywodzące się z danej klasy

public:

składniki są dostępne bez ograniczeń; najczęściej są nimi
funkcje wywoływane z zewnątrz

background image

Klasa

class

Car

{

private

:

std::

string

brand

;

protected

:

std::

string

model

;

public

:

std::

string

color

;

void

setBrand(std::

string

b);

std::

string

getBrand();

};

background image

Klasa

class

Car

{

private

:

std::

string

brand

;

protected

:

std::

string

model

;

public

:

std::

string

color

;

void

setBrand(std::

string

b);

std::

string

getBrand();

};

// implementacja

int

main() {

Car

c;

c.

brand

=

"Audi"

;

c.

model

=

"A6"

;

c.

color

=

"black"

;

}

background image

Klasa

class

Car

{

private

:

std::

string

brand

;

protected

:

std::

string

model

;

public

:

std::

string

color

;

void

setBrand(std::

string

b);

std::

string

getBrand();

};

// implementacja

int

main() {

Car

c;

// źle

c.

brand

=

"Audi"

;

// źle

c.

model

=

"A6"

;

// OK

c.

color

=

"black"

;

}

background image

Klasa

class

Car

{

private

:

std::

string

brand

;

std::

string

color

;

protected

:

std::

string

model

;

public

:

void

setBrand(std::

string

b);

std::

string

getBrand();

void

setColor(std::

string

c);

std::

string

getColor();

};

Dobre praktyki

- dane składowe

niewidoczne,

- dostęp do nich

za pomocą

publicznych metod

background image

Klasa

class

Car

{

private

:

std::

string

brand

;

std::

string

color

;

protected

:

std::

string

model

;

public

:

void

setBrand(std::

string

b) {

brand

= b;

}
std::

string

getBrand() {

return

brand

;

}

void

setColor(std::

string

c) {

color

= c;

}
std::

string

getColor() {

return

color

;

}

};

Definicja funkcji

wewnątrz

definicji klasy

Jeśli już to tylko

dla „krótkich”

funkcji (1-2 linie

implementacji)

background image

Klasa

class

Car

{

private

:

std::

string

brand

;

std::

string

color

;

protected

:

std::

string

model

;

public

:

void

setBrand(std::

string

b);

std::

string

getBrand();

void

setColor(std::

string

c);

std::

string

getColor();

};

void

Car::setBrand(std::

string

b) {

brand

= b;

}

std::

string

Car::getBrand() {

return

brand

;

}

void

Car::setColor(std::

string

c) {

color

= c;

}

std::

string

Car::getColor() {

return

color

;

}

Definicja klasy

Definicja funkcji

background image

Klasa

class

Car

{

private

:

std::

string

brand

;

std::

string

color

;

protected

:

std::

string

model

;

public

:

void

setBrand(std::

string

b);

std::

string

getBrand();

void

setColor(std::

string

c);

std::

string

getColor();

};

Przestrzeń nazw std::

using

namespace

std;

class

Car

{

private

:

string

brand

;

string

color

;

protected

:

string

model

;

public

:

void

setBrand(

string

b);

string

getBrand();

void

setColor(

string

c);

string

getColor();

};

background image

Klasa

int

main() {

Car

samochod;

samochod.setBrand(

"Opel"

);

cout << samochod.getBrand() << endl;

// ?

}

Tworzenie obiektów

background image

Klasa

int

main() {

Car

samochod;

samochod.setBrand(

"Opel"

);

cout << samochod.getBrand() << endl;

// Opel

Car

& osobowy = samochod; // referencja

cout << osobowy.getBrand() << endl;

// ?

}

Tworzenie obiektów

background image

Klasa

int

main() {

Car

samochod;

samochod.setBrand(

"Opel"

);

cout << samochod.getBrand() << endl;

// Opel

Car

& osobowy = samochod; // referencja

cout << osobowy.getBrand() << endl;

// Opel

osobowy.setBrand(

"Ford"

);

cout << samochod.getBrand() << endl;

// ?

}

Tworzenie obiektów

background image

Klasa

int

main() {

Car

samochod;

samochod.setBrand(

"Opel"

);

cout << samochod.getBrand() << endl;

// Opel

Car

& osobowy = samochod; // referencja

cout << osobowy.getBrand() << endl;

// Opel

osobowy.setBrand(

"Ford"

);

cout << samochod.getBrand() << endl;

// Ford

}

Tworzenie obiektów

background image

Klasa

int

main() {

Car

samochod;

samochod.setBrand(

"Opel"

);

Car

* cPtr;

cPtr = &samochod;

cout << cPtr->getBrand() << endl;

// ?

}

Tworzenie obiektów

background image

Klasa

int

main() {

Car

samochod;

samochod.setBrand(

"Opel"

);

Car

* cPtr;

cPtr = &samochod;

cout << cPtr->getBrand() << endl;

// Opel

cPtr->setBrand(

"VW"

);

cout << samochod.getBrand() << endl;

// ?

}

Tworzenie obiektów

background image

Klasa

int

main() {

Car

samochod;

samochod.setBrand(

"Opel"

);

Car

* cPtr;

cPtr = &samochod;

cout << cPtr->getBrand() << endl;

// Opel

cPtr->setBrand(

"VW"

);

cout << samochod.getBrand() << endl;

// VW

}

Tworzenie obiektów

background image

Klasa

int

main() {

Car

samochod;

samochod.setBrand(

"Opel"

);

// ...

}

Referencje i wskaźniki

// referencja

Car

& osobowy = samochod;

cout << osobowy.getBrand()

<< endl;

// wskaźnik

Car

* cPtr;

cPtr = &samochod;

cout << cPtr->getBrand()

<< endl;

background image

Klasa

int

main() {

Car

samochod;

samochod.setBrand(

"Opel"

);

// ...

}

Referencje i wskaźniki

// referencja

Car

& osobowy = samochod;

cout << osobowy.getBrand()

<< endl;

// wskaźnik

Car

* cPtr;

cPtr = &samochod;

cout << cPtr->getBrand()

<< endl;

// błąd

Car

& osobowy;

osobowy = samochod;

background image

Klasa

int

main() {

Car

* cPtr =

new

Car;

cPtr->setBrand(

"Citroen"

);

cout << cPtr->getBrand() << endl;

delete

cPtr;

}

Dynamiczne tworzenie obiektów

background image

Klasa

int

main() {

Car

* cPtr =

new

Car;

cPtr->setBrand(

"Citroen"

);

cout << cPtr->getBrand() << endl;

delete

cPtr;

int

n = 5;

Car

* tab =

new

Car[n];

// ...

delete

[] tab;

}

Dynamiczne tworzenie obiektów

background image

Klasa

int

main() {

Car

* cPtr =

new

Car;

cPtr->setBrand(

"Citroen"

);

cout << cPtr->getBrand() << endl;

delete

cPtr;

int

n = 5;

Car

* tab =

new

Car[n];

// ...

delete

[] tab;

}

Dynamiczne tworzenie obiektów

Tu warto sprawdzić, czy
przypadkiem nie zabrakło pamięci:

if (tab == NULL) {

// hmm... i co tu robić?

}

background image

Klasa

int

main() {

Car

* cPtr =

new

Car;

cPtr->setBrand(

"Citroen"

);

cout << cPtr->getBrand() << endl;

delete

cPtr;

int

n = 5;

Car

* tab =

new

Car[n];

// ...

delete

[] tab;

}

Dynamiczne tworzenie obiektów

Jeśli uciekło nam

z głowy,

a prowadzący jeszcze tego

nie podkreślił...

W języku C++

zmienne (obiekty)

można deklarować

w (prawie) dowolnym

miejscu w programie,

a nie jedynie

na początku bloku

jak to miało miejsce

w C

background image

Klasa

Odejdźmy od samochodów...

Stwórzmy klasę, która będzie

przechowywać takie

informacje jak nazwisko

delikwenta, jego wiek oraz

fakt bycia (lub nie) palaczem...

background image

Klasa

class

Person

{

string

name

;

int

age

;

bool

smoker

;

public

:

// gettery

string

getName();

int

getAge();

bool

isSmoker();

// settery

// ...

};

Odejdźmy od samochodów...

Stwórzmy klasę, która będzie

przechowywać takie

informacje jak nazwisko

delikwenta, jego wiek oraz

fakt bycia (lub nie) palaczem...

background image

Klasa

class

Person

{

string

name

;

int

age

;

bool

smoker

;

public

:

// gettery

string

getName();

int

getAge();

bool

isSmoker();

// settery

// ...

};

int

main() {

Person

p;

cout << p.getName() << endl;

// ?

cout << p.getAge() << endl;

// ?

cout << p.isSmoker() << endl;

// ?

}

background image

Klasa

class

Person

{

string

name

;

int

age

;

bool

smoker

;

public

:

// gettery

string

getName();

int

getAge();

bool

isSmoker();

// settery

// ...

};

int

main() {

Person

p;

cout << p.getName() << endl;

//

cout << p.getAge() << endl;

// 4072576

cout << p.isSmoker() << endl;

// 48

}

trochę bez sensu...

background image

Klasa

class

Person

{

string

name

;

int

age

;

bool

smoker

;

public

:

Person();

// ...

};

Person::Person() {

age

= 18;

smoker

=

true

;

}

konstruktor

background image

Klasa

class

Person

{

string

name

;

int

age

;

bool

smoker

;

public

:

Person();

// ...

};

Person::Person() {

age

= 18;

smoker

=

true

;

}

int

main() {

Person

p;

cout << p.getName() << endl;

//

cout << p.getAge() << endl;

// 18

cout << p.isSmoker() << endl;

// 1

}

jest lepiej...

background image

Klasa

class

Person

{

string

name

;

int

age = 18

;

bool

smoker = true

;

public

:

// ...

};

Tak nie można!

Inicjalizować składowe dane klasy można tylko w ciele konstruktora lub

na liście inicjalizacyjnej (o tym później)

background image

Klasa

class

Person

{

string

name

;

int

age

;

bool

smoker

;

public

:

Person();

Person(

int

a,

bool

s);

};

Person::Person() {

age

= 18;

smoker

=

true

;

}

// można wprowadzić własne

Person::Person(

int

a,

bool

s) {

age

= a;

smoker

= s;

}

Nadawanie danym składowym wartości w chwili tworzenia obiektów

background image

Klasa

Można pozbyć się konstruktora:

Person();

i pozostawić tylko ten drugi:

Person::Person(

int

a,

bool

s);

nie tracąc poprzedniej funkcjonalności...

...pod warunkiem następującej definicji konstruktora:

Person::Person(

int

a = 18,

bool

s =

false

) {

age

= a;

smoker

= s;

}

background image

Klasa

int

main() {

Person

p1;

// wiek: 18, palacz: nie

Person

p2(21,

true

);

// wiek: 21, palacz: tak

Person

p3(30);

// wiek: 30, palacz: nie

Person

p4(

true

);

// wiek: 1, palacz: nie

}

Przy tak zdefiniowanym konstruktorze:

Person::Person(

int

a = 18,

bool

s =

false

) {

age

= a;

smoker

= s;

}

background image

Klasa

class

Person

{

string

name

;

int

age

;

bool

smoker

;

// dalsze składniki ...

};

Abstrahując...

int

main() {

Person

p;

p.age = 20;

// czy mogę tak?

}

background image

Klasa

class

Person

{

string

name

;

int

age

;

bool

smoker

;

public

:

// brak konstruktorów

// publiczne metody

};

Automatycznie zostanie wygenerowany

domyślny konstruktor (nie przyjmujący

parametrów) nie inicjalizujący żadnych

danych składowych.

Person::Person() {}

I jeszcze ważna uwaga...

background image

Klasa

class

Person

{

string

name

;

int

age

;

bool

smoker

;

public

:

Person::Person(

int

a,

bool

s);

};

Person::Person(

int

a,

bool

s) {

age

= a;

smoker

= s;

}

I jeszcze ważna uwaga...

Jeśli w klasie został zdefiniowany jakiś konstruktor przyjmujący parametry,

domyślny konstruktor (bezargumentowy) nie zostanie automatycznie

wygenerowany. Innymi słowy, w programie nie stworzymy obiektu w ten sposób:

Person

p;

background image

Klasa

class

Person

{

string

name

;

int

age

;

bool

smoker

;

public

:

Person();

Person(

int

a,

bool

s);

};

Person::Person(

int

a,

bool

s) {

age

= a;

smoker

= s;

}

Person::Person() {}

I jeszcze ważna uwaga...

Chcąc mieć taką możliwość (i dane składowe zainicjalizować później za pomocą

metod), należy jawnie zadeklarować bezargumentowy konstruktor. Teraz można:

Person

p;

background image

Klasa

class

Totolotek

{

private

:

int

n

;

int

*

tablicaLiczb

;

public

:

Totolotek(

int

ile);

~Totolotek();

int

* pokazLiczby() {

return

tablicaLiczb

;

}

private

:

void

losuj();

};

Skoro był konstruktor to i powinien... destruktor?

Totolotek::Totolotek(

int

ile) {

n

= ile;

tablicaLiczb

=

new

int

[

n

];

srand

(

time

(NULL));

losuj();

}

Totolotek::~Totolotek() {

delete

[]

tablicaLiczb

;

}

void

Totolotek::losuj() {

for

(

int

i = 0; i <

n

; i++) {

*(

tablicaLiczb

+ i) =

rand

();

}

}

background image

Klasa

Składniki statyczne

Statyczne dane składowe są wspólne dla wszystkich obiektów danej klasy.

Zmiana wartości danych statycznych dowolnego obiektu określonej klasy jest od

razu widoczna przez wszystkie inne obiekty tej klasy.

background image

Klasa

class

Towar

{

private

:

string

nazwa

;

static

float

cena

;

public

:

Towar(

string

n);

void

ustawCene(

float

nowaCena);

float

podajCene();

};

Składniki statyczne

Towar::Towar(

string

n) {

nazwa

= n;

}

void

Towar::ustawCene(

float

nowaCena) {

cena

= nowaCena;

}

void

Towar::podajCene() {

return

cena

;

}

float

Towar::cena

= 5;

Sklep –

wszystko po 5zł

Nadać wartość można w momencie inicjalizacji

background image

Klasa

Składniki statyczne

int

main() {

Towar

t1(

"kubek"

);

Towar

t2(

"ksiazka"

);

Towar

t3(

"flakon"

);

t1.ustawCene(4.50);

cout << t3.podajCene() << endl;

// 4.50

}

Sklep –

wszystko po 5zł

Statyczne dane składowe są wspólne dla wszystkich obiektów danej klasy.

Zmiana wartości danych statycznych dowolnego obiektu określonej klasy jest od

razu widoczna przez wszystkie inne obiekty tej klasy.

background image

Klasa

Składniki statyczne

int

main() {

Towar

::ustawCene(5.50);

Towar

t1(

"kubek"

);

Towar

t3(

"flakon"

);

cout << t3.podajCene()

<< endl;

// 5.50

t1.ustawCene(4.50);

cout << t3.podajCene()

<< endl;

// 4.50

}

Sklep –

wszystko po 5zł

Statyczne funkcje składowe

class

Towar

{

private

:

string

nazwa

;

static

float

cena

;

public

:

Towar(

string

n);

static

void

ustawCene(

float

nowaCena);

float

podajCene();

};

background image

Klasa

Składniki statyczne - przykład

class

Book

{

private

:

string

title

;

static

int

count

;

// ...

public

:

Book();

static

int

getCounter();

// ...

};

int

Book::count

;

Book::Book() {

count

++;

}

int

Book::getCounter() {

return

count

;

}

- konieczna deklaracja obiektu (zmiennej)

statycznego (podobnie jak globalnego)

- statyczna zmienna int jest

inicjalizowana zerem (podobnie jak

zmienna globalna)

background image

Klasa

Składniki statyczne - przykład

int

main() {

for

(

int

i = 0; i < 100; i++) {

Book

b;

}
cout <<

Book

::getCounter()

<< endl;

// 100

}

class

Book

{

private

:

string

title

;

static

int

count

;

// ...

public

:

Book();

static

int

getCounter();

// ...

};

int

Book::count

;

Book::Book() {

count

++;

}

int

Book::getCounter() {

return

count

;

}

- konieczna deklaracja obiektu (zmiennej)

statycznego (podobnie jak globalnego)

- statyczna zmienna int jest

inicjalizowana zerem (podobnie jak

zmienna globalna)

background image

Klasa

Dane składowe const

/**

* Klasa definiujaca

* operacje na kole

*/

class

Kolarz

{

private

:

const

double

pi

;

public

:

Kolarz();

double

podajPole(

double

r);

double

podajObwod(

double

r);

};

double

Kolarz::podajPole(

double

r) {

return

pi

* r * r;

}

double

Kolarz::podajObwod(

double

r) {

return

2 *

pi

* r;

}

background image

Klasa

Dane składowe const

/**

* Klasa definiujaca

* operacje na kole

*/

class

Kolarz

{

private

:

const

double

pi

;

public

:

Kolarz();

double

podajPole(

double

r);

double

podajObwod(

double

r);

};

double

Kolarz::podajPole(

double

r) {

return

pi

* r * r;

}

double

Kolarz::podajObwod(

double

r) {

return

2 *

pi

* r;

}

Kolarz::Kolarz() {

pi

= 3.1415926;

}

background image

Klasa

Dane składowe const

/**

* Klasa definiujaca

* operacje na kole

*/

class

Kolarz

{

private

:

const

double

pi

;

public

:

Kolarz();

double

podajPole(

double

r);

double

podajObwod(

double

r);

};

double

Kolarz::podajPole(

double

r) {

return

pi

* r * r;

}

double

Kolarz::podajObwod(

double

r) {

return

2 *

pi

* r;

}

Kolarz::Kolarz() {

pi

= 3.1415926;

}

background image

Klasa

Dane składowe const

/**

* Klasa definiujaca

* operacje na kole

*/

class

Kolarz

{

private

:

const

double

pi

;

public

:

Kolarz();

double

podajPole(

double

r);

double

podajObwod(

double

r);

};

double

Kolarz::podajPole(

double

r) {

return

pi

* r * r;

}

double

Kolarz::podajObwod(

double

r) {

return

2 *

pi

* r;

}

Kolarz::Kolarz() :

pi

(3.1415926) {

// inicjalizacja obiektów

// nie-const

}

Obiekty nie-const mogą być inicjalizowane również na liście inicjalizacyjnej

background image

Klasa

Wróćmy do samochodów

class

Car

{

private

:

string

brand

;

string

color

;

protected

:

string

model

;

public

:

void

setBrand(

string

b);

string

getBrand();

void

setModel(

string

m);

string

getModel();

void

setColor(

string

c);

string

getColor();

};

Stwórzmy funkcję służącą do

wypisywania na ekranie danych na temat

konkretnego samochodu.

Funkcja taka będzie wymagała

przekazania jej obiektu typu Car.

Obiekt typu Car może zostać przekazany

do funkcji przez:

- wartość

- referencję

- wskaźnik

background image

Klasa

Przekazywanie obiektu do funkcji

- przez wartość

void

wypisz(

Car

c) {

cout << c.getBrand() << endl;
cout << c.getModel() << endl;
cout << c.getColor() << endl;

}

- przez referencję

void

wypisz(

Car

& c) {

cout << c.getBrand() << endl;
cout << c.getModel() << endl;
cout << c.getColor() << endl;

}

- przez wskaźnik

void

wypisz(

Car

* c) {

cout << c->getBrand() << endl;
cout << c->getModel() << endl;
cout << c->getColor() << endl;

}

background image

Klasa

Przekazywanie obiektu do funkcji

- przez wartość

void

wypisz(

Car

c) {

cout << c.getBrand() << endl;
cout << c.getModel() << endl;
cout << c.getColor() << endl;

}

- przez referencję

void

wypisz(

Car

& c) {

cout << c.getBrand() << endl;
cout << c.getModel() << endl;
cout << c.getColor() << endl;

}

- przez wskaźnik

void

wypisz(

Car

* c) {

cout << c->getBrand() << endl;
cout << c->getModel() << endl;
cout << c->getColor() << endl;

}

albo

background image

Klasa

Przekazywanie obiektu do funkcji

int

main() {

// wywolanie w przypadku przekazywania przez

// wartosc lub referencje

Car

c1;

c1.setBrand(

"Audi"

);

c1.setModel(

"A6"

);

c1.setColor(

"black"

);

wypisz(c1);

// wywolanie w przypadku przekazywania przez

// wskaznik

Car

* cPtr = &c1;

wypisz(cPtr);

}

background image

Klasa

Zagadka

void

wypisz(

Car

c) {

c.setBrand("noname");

cout << c.getBrand() << endl;

cout << c.getModel() << endl;

cout << c.getColor() << endl;

}

int

main() {

Car

c1;

c1.setBrand(

"Audi"

);

c1.setModel(

"A6"

);

c1.setColor(

"black"

);

wypisz(c1);

cout << c1.getBrand() << endl;

}

background image

Klasa

Zagadka

int

main() {

Car

c1;

c1.setBrand(

"Audi"

);

c1.setModel(

"A6"

);

c1.setColor(

"black"

);

wypisz(c1);

cout << c1.getBrand() << endl;

}

void

wypisz(

Car

c) {

c.setBrand("noname");

cout << c.getBrand() << endl;

cout << c.getModel() << endl;

cout << c.getColor() << endl;

}

Wynik:

noname

A6

black

Audi

background image

Klasa

Zagadka

void

wypisz(

Car &

c) {

c.setBrand("noname");

cout << c.getBrand() << endl;

cout << c.getModel() << endl;

cout << c.getColor() << endl;

}

int

main() {

Car

c1;

c1.setBrand(

"Audi"

);

c1.setModel(

"A6"

);

c1.setColor(

"black"

);

wypisz(c1);

cout << c1.getBrand() << endl;

}

background image

Klasa

Zagadka

void

wypisz(

Car &

c) {

c.setBrand("noname");

cout << c.getBrand() << endl;

cout << c.getModel() << endl;

cout << c.getColor() << endl;

}

Wynik:

noname

A6

black

noname

int

main() {

Car

c1;

c1.setBrand(

"Audi"

);

c1.setModel(

"A6"

);

c1.setColor(

"black"

);

wypisz(c1);

cout << c1.getBrand() << endl;

}

background image

Klasa

Jeśli chcemy zapewnić użytkownika, że funkcja nie naruszy mu

obiektu, do którego referencję przesyła:

void

wypisz(const

Car &

c) {

//

c.setBrand("noname"); <- tego już kompilator nie puści

cout << c.getBrand() << endl;

cout << c.getModel() << endl;

cout << c.getColor() << endl;

}

background image

Klasa

Jeśli chcemy zapewnić użytkownika, że funkcja nie naruszy mu

obiektu, do którego referencję przesyła:

void

wypisz(const

Car &

c) {

//

c.setBrand("noname"); <- tego już kompilator nie puści

cout << c.getBrand() << endl;

cout << c.getModel() << endl;

cout << c.getColor() << endl;

}

class

Car

{

private

:

string

brand

;

// ...

public

:

string

getBrand()

const

;

// ...

};

std::

string

Car::getBrand()

const

{

return

brand

;

}

background image

Klasa

Jeśli chcemy zapewnić użytkownika, że funkcja nie naruszy mu

obiektu, do którego referencję przesyła:

void

wypisz(const

Car &

c) {

//

c.setBrand("noname"); <- tego już kompilator nie puści

cout << c.getBrand() << endl;

cout << c.getModel() << endl;

cout << c.getColor() << endl;

}

class

Car

{

private

:

string

brand

;

// ...

public

:

string

getBrand()

const

;

// ...

};

std::

string

Car::getBrand()

const

{

return

brand

;

}

Podobnie można zrobić

przy przekazywaniu

przez wskaźnik

background image

Klasa

Konstruktor kopiujący

void

wypisz(

Car

c) {

// ...

}

Przy przekazywaniu obiektu przez

wartość zostaje niejawnie wywołany

domyślny konstruktor kopiujący, który

powiela wartości poszczególnych

zmiennych: brand, model, color

background image

Klasa

Konstruktor kopiujący

void

wypisz(

Car

c) {

// ...

}

Przy przekazywaniu obiektu przez

wartość zostaje niejawnie wywołany

domyślny konstruktor kopiujący, który

powiela wartości poszczególnych

zmiennych: brand, model, color

Car funkcja() {

Car c;

// ...

return c;

}

Podobnie rzecz wygląda w momencie

zwracania obiektu przez funkcje poprzez

return. Obiekt lokalny jest tu kopiowany,

jego kopia jest widoczna w miejscu

wywołania funkcji w programie.

background image

Klasa

Konstruktor kopiujący

Konstruktor kopiujący możemy wywołać też jawnie:

Wynik:

Audi

A6

black

Car

c1;

c1.setBrand(

"Audi"

);

c1.setModel(

"A6"

);

c1.setColor(

"black"

);

Car

c2(c1);

wypisz(c2);

background image

Klasa

Konstruktor kopiujący - problem

class

Totolotek

{

private

:

int

n

;

int

*

tablicaLiczb

;

public

:

Totolotek(

int

ile);

// ...

public

:

void

losuj();

};

Totolotek::Totolotek(

int

ile) {

n

= ile;

tablicaLiczb

=

new

int

[

n

];

srand

(

time

(NULL));

losuj();

}

int

main() {

Totolotek

losowanie(6);

Totolotek

kopia(losowanie);

// ...

}

background image

Klasa

Konstruktor kopiujący - problem

class

Totolotek

{

private

:

int

n

;

int

*

tablicaLiczb

;

public

:

Totolotek(

int

ile);

// ...

public

:

void

losuj();

};

Totolotek::Totolotek(

int

ile) {

n

= ile;

tablicaLiczb

=

new

int

[

n

];

srand

(

time

(NULL));

losuj();

}

int

main() {

Totolotek

losowanie(6);

Totolotek

kopia(losowanie);

// ...

}

- wyświetlając wylosowane elementy z

tablicyLiczb każdego z obiektów

(losowanie i kopia) dostajemy te same

liczby -> OK

- po ponownym wywołaniu metody losuj()

na obiekcie losowanie, liczby zawarte w

obiekcie kopia są TAKIE SAME jak w

obiekcie losowanie -> Nie OK!

background image

Klasa

Należy zdefiniować konstruktor kopiujący

class

Totolotek

{

private

:

int

n

;

int

*

tablicaLiczb

;

public

:

Totolotek(

int

ile);

Totolotek(

Totolotek

& t)

// ...

public

:

void

losuj();

};

Totolotek::Totolotek(

Totolotek

& t) {

n

= t.

n

;

tablicaLiczb

=

new

int

[

n

];

for

(

int

i=0; i<

n

; i++)

tablicaLiczb

[i] = t.

tablicaLiczb

[i];

}

background image

Klasa

Dziedziczenie

class

Samochod

{

public

:

string

marka

;

string

model

;

};

class

Osobowy

:

public

Samochod

{

public

:

int

liczbaOsob

;

};

class

Ciezarowy

:

public

Samochod

{

public

:

float

ladownosc

;

};

class

Wywrotka

:

public

Ciezarowy

{

public

:

void

wysypLadunek();

};

Samochód

- marka

- model

Osobowy

- liczbaOsób

Ciężarowy

- ładowność

Wywrotka

- wysypŁadunek()

background image

Klasa

Składniki klasy
podstawowej

Widoczność w klasach pochodnych

Widoczność w programie

private

class

Samochod

{

private

:

int

marka

;

void

wysMarke();

}

niewidoczne

class

Osobowy

:

public

Samochod

{

public

:

void

f() {

wysMarke();

// ŹLE

}

};

niewidoczne

int

main() {

Samochod

s;

s.wysMarke();

// ŹLE

}

protected

class

Samochod

{

private

:

int

marka

;

protected

:

void

wysMarke();

}

widoczne

class

Osobowy

:

public

Samochod

{

public

:

void

f() {

wysMarke();

// OK

}

};

niewidoczne

int

main() {

Samochod

s;

s.wysMarke();

// ŹLE

}

public

class

Samochod

{

private

:

int

marka

;

public

:

int

wysMarke();

}

widoczne

class

Osobowy

:

public

Samochod

{

public

:

void

f() {

wysMarke();

// OK

}

};

widoczne

int

main() {

Samochod

s;

s.wysMarke();

// OK

}

background image

Klasa

Składniki klasy
podstawowej

Widoczność w klasach pochodnych

Widoczność w programie

private

class

Samochod

{

private

:

int

marka

;

void

wysMarke();

}

niewidoczne

class

Osobowy

:

public

Samochod

{

public

:

void

f() {

wysMarke();

// ŹLE

}

};

niewidoczne

int

main() {

Samochod

s;

s.wysMarke();

// ŹLE

}

protected

class

Samochod

{

private

:

int

marka

;

protected

:

void

wysMarke();

}

widoczne

class

Osobowy

:

public

Samochod

{

public

:

void

f() {

wysMarke();

// OK

}

};

niewidoczne

int

main() {

Samochod

s;

s.wysMarke();

// ŹLE

}

public

class

Samochod

{

private

:

int

marka

;

public

:

int

wysMarke();

}

widoczne

class

Osobowy

:

public

Samochod

{

public

:

void

f() {

wysMarke();

// OK

}

};

widoczne

int

main() {

Osobowy

o;

o.wysMarke();

// OK

}

Oczywiście można też tak

- publiczna metoda klasy
podstawowej może być
wywoływana na obiekcie
klasy pochodnej

( dotyczy to tylko
dziedziczenia publicznego )

background image

Klasa

Dziedziczenie „protected”:

class

Osobowy

:

protected

Samochod

{

// ...

};

- wszystkie składniki publiczne i protected klasy Samochod są w klasie

Osobowy ustawione na protected

background image

Klasa

Dziedziczenie „protected”:

class

Osobowy

:

protected

Samochod

{

// ...

};

- wszystkie składniki publiczne i protected klasy Samochod są w klasie

Osobowy ustawione na protected

Dziedziczenie „private”:

class

Osobowy

:

private

Samochod

{

// ...

};

- wszystkie składniki publiczne i protected klasy Samochod są w klasie

Osobowy ustawione na private

background image

Klasa

Dziedziczenie

Nie dziedziczą się:

- konstruktor

- destruktor

- operator przypisania

W momencie tworzenia obiektu klasy pochodnej, najpierw wywoływany jest

konstruktor klasy podstawowej (domyślny jeśli na liście inicjalizacyjnej nie

wskażemy inaczej), później konstruktor klasy pochodnej.

W momencie likwidowania obiektu klasy pochodnej, najpierw wywoływany jest

destruktor klasy pochodnej, a po nim klasy podstawowej.

background image

class

Person

{

string

name

;

int

age

;

public

:

Person();

Person(

string

name,

int

age);

// ...

};

Klasa

class

Worker

:

public

Person

{

string

occ

;

public

:

Worker();

Worker(

string

name,

int

age,

string

occ);

};

Worker::Worker() : Person() {}

Worker::Worker(

string

p_name,

int

p_age,

string

p_occ) : Person(p_name, p_age) {

occ

= p_occ;

}

Person::Person() {

age

= 18;

}

Person::Person(

string

p_name,

int

p_age) {

name

= p_name;

age

= p_age;

}

Konstruktory klasy

podstawowej

background image

class

Person

{

string

name

;

int

age

;

public

:

Person();

Person(

string

name,

int

age);

// ...

};

Klasa

class

Worker

:

public

Person

{

string

occ

;

public

:

Worker();

Worker(

string

name,

int

age,

string

occ);

};

Worker::Worker() {}

Worker::Worker(

string

p_name,

int

p_age,

string

p_occ) : Person(p_name, p_age) {

occ

= p_occ;

}

Person::Person() {

age

= 18;

}

Person::Person(

string

p_name,

int

p_age) {

name

= p_name;

age

= p_age;

}

Konstruktor klasy

podstawowej

background image

Klasa

class

Totolotek

{

private

:

int

n

;

int

*

tablicaLiczb

;

public

:

Totolotek(

int

ile);

Totolotek(

Totolotek

& t)

// ...

public

:

void

losuj();

};

class

DuzyLotek

:

public

Totolotek

{

private

:

int

zakres

;

public

:

DuzyLotek();

public

:

void

losuj(); // do przedefiniowania

};

DuzyLotek::DuzyLotek() : Totolotek(6) {

zakres

= 49;

}

Jeśli w klasie podstawowej nie ma konstruktora domyślnego,

trzeba jawnie wskazać, który ma zostać wywołany

background image

Klasa

class

Instrument

{

public

:

void

graj() {

cout <<

"nie wiem jak"

<< endl;

}

};

class

Flet

:

public

Instrument

{

public

:

void

graj() {

cout <<

"pipipi"

<< endl;

}

};

Funkcje wirtualne... za chwilę

int

main() {

Instrument

* iPtr =

new

Instrument;

iPtr->graj();

// ?

Flet

* fPtr =

new

Flet;

fPtr->graj();

// ?

Instrument

* i2Ptr =

new

Flet;

i2Ptr->graj();

// ?

}

background image

Klasa

class

Instrument

{

public

:

void

graj() {

cout <<

"nie wiem jak"

<< endl;

}

};

class

Flet

:

public

Instrument

{

public

:

void

graj() {

cout <<

"pipipi"

<< endl;

}

};

Funkcje wirtualne... za chwilę

int

main() {

Instrument

* iPtr =

new

Instrument;

iPtr->graj();

// nie wiem jak

Flet

* fPtr =

new

Flet;

fPtr->graj();

// pipipi

Instrument

* i2Ptr =

new

Flet;

i2Ptr->graj();

// nie wiem jak

}

hmm....

background image

Klasa

class

Instrument

{

public

:

void virtual

graj() {

cout <<

"nie wiem jak"

<< endl;

}

};

class

Flet

:

public

Instrument

{

public

:

void

graj() {

cout <<

"pipipi"

<< endl;

}

};

Funkcje wirtualne

int

main() {

Instrument

* iPtr =

new

Instrument;

iPtr->graj();

// nie wiem jak

Flet

* fPtr =

new

Flet;

fPtr->graj();

// pipipi

Instrument

* i2Ptr =

new

Flet;

i2Ptr->graj();

// pipipi

}

juhu !!

background image

Klasa

class

Instrument

{

public

:

void virtual

graj() {

cout <<

"nie wiem jak"

<< endl;

}

};

class

Flet

:

public

Instrument

{

public

:

void

graj() {

cout <<

"pipipi"

<< endl;

}

};

Funkcje wirtualne

int

main() {

Instrument

* iPtr =

new

Instrument;

iPtr->graj();

// nie wiem jak

Flet

* fPtr =

new

Flet;

fPtr->graj();

// pipipi

Instrument

* i2Ptr =

new

Flet;

i2Ptr->graj();

// pipipi

}

juhu !!

background image

Klasa

class

Instrument

{

public

:

void virtual

graj() {

cout <<

"nie wiem jak"

<< endl;

}

};

class

Flet

:

public

Instrument

{

public

:

void

graj() {

cout <<

"pipipi"

<< endl;

}

};

Funkcje wirtualne – inny przykład

void

zaprezentujSie(

Instrument

& i) {

i.graj();

}

int

main() {

Instrument

i;

Flet

f;

zaprezentujSie(i);

// nie wiem jak

zaprezentujSie(f);

// pipipi

}

background image

Klasa

class

Instrument

{

private:

string

nazwa;

public

:

// setter i getter dla nazwy

void virtual

graj() = 0;

};

class

Flet

:

public

Instrument

{

public

:

void

graj() {

cout <<

"pipipi"

<< endl;

}

};

Funkcje wirtualne – inny przykład

Czy potrzebny nam obiekt typu Instrument, skoro i tak nie umie grać?

Klasa Instrument może definiować pewne cechy wspólne (np. nazwę instrumentu).

int

main() {

Instrument

* iPtr =

new

Instrument;

// PROTEST KOMPILATORA

Flet

* fPtr =

new

Flet;

fPtr->graj();

// pipipi

Instrument

* i2Ptr =

new

Flet;

i2Ptr->graj();

// pipipi

}

background image

Klasa

class

Instrument

{

private:

string

nazwa;

public

:

// setter i getter dla nazwy

void virtual

graj() = 0;

};

class

Flet

:

public

Instrument

{

public

:

void

graj() {

cout <<

"pipipi"

<< endl;

}

};

Funkcje wirtualne – inny przykład

Czy potrzebny nam obiekt typu Instrument, skoro i tak nie umie grać?

Klasa Instrument może definiować pewne cechy wspólne (np. nazwę instrumentu).

Funkcja czysto wirtualna

Klasa abstrakcyjna

(nie można stworzyć

obiektu tej klasy)

background image

Klasa

class

Instrument

{

private:

string

nazwa;

public

:

// setter i getter dla nazwy

void virtual

graj() = 0;

};

class

Flet

:

public

Instrument

{

public

:

void

graj() {

cout <<

"pipipi"

<< endl;

}

};

Funkcje wirtualne – inny przykład

Czy potrzebny nam obiekt typu Instrument, skoro i tak nie umie grać?

Klasa Instrument może definiować pewne cechy wspólne (np. nazwę instrumentu).

Funkcja czysto wirtualna

Klasa abstrakcyjna

(nie można stworzyć

obiektu tej klasy)

Może istnieć klasa, której wszystkie

metody są czysto wirtualne.

Taka klasa definiuje tzw.

interfejs.

background image

Klasa

class

Instrument

{

private:

string

nazwa;

public

:

// setter i getter dla nazwy

void virtual

graj() {

// implementacja

}

virtual

~Instrument() {

// implementacja

}

};

Wirtualny destruktor

Jeśli określona klasa definiuje choć jedną metodę wirtualną, jej destruktor także

powinien być wirtualny.

Wirtualny destruktor


Document Outline


Wyszukiwarka

Podobne podstrony:
2010 ZMP studenci
zakres zmp, PKM, PKM wykłady, PKM-wyklady Salwinski, ZMP
Relacje z klientami, WZR UG ZARZĄDZANIE - ZMP I STOPIEŃ, IV SEMESTR (letni) 2013-2014, ZARZĄDZANIE W
Fuzje i przejęcia - wykłady, WZR UG ZARZĄDZANIE - ZMP I STOPIEŃ, V SEMESTR (zimowy) 2014-2015, FUZJE
marketing pytania i odpowiedzi ZBIÓR, WZR UG ZARZĄDZANIE - ZMP II STOPIEŃ, I SEMESTR (zimowy) 2015-
żmp, Nowe rodzaje żywności
ŻMP - Test 2007, 1. ROLNICTWO, Żywność minimalnie przetworzona
ŻMP, 1. ROLNICTWO, Żywność minimalnie przetworzona
Lokalizacja działalności gospodarczej, WZR UG ZARZĄDZANIE - ZMP I STOPIEŃ, V SEMESTR (zimowy) 2014-2
ZMP 4
Miesiączka Krwawienia nieprawidlowe ZMP Bolsesne miesiączki
notatki ZWP2, WZR UG ZARZĄDZANIE - ZMP I STOPIEŃ, IV SEMESTR (letni) 2013-2014, ZARZĄDZANIE WARTOŚCI
TEKST PREZENTACJA, WZR UG ZARZĄDZANIE - ZMP I STOPIEŃ, IV SEMESTR (letni) 2013-2014, PROMOCJA; S. Ba
Themen ZMP 1 13
owi egzam, WZR UG ZARZĄDZANIE - ZMP I STOPIEŃ, II SEMESTR (letni) 2012-2013, OCHRONA własności intel
PRODUKTY UBEZEPIECZENIOWE - PIERWSZY WYKŁAD, WZR UG ZARZĄDZANIE - ZMP I STOPIEŃ, V SEMESTR (zimowy)

więcej podobnych podstron