Klasy i obiekty w C++

Transkrypt

Klasy i obiekty w C++
Wprowadzenie do programowanie
obiektowego w języku C++
Część druga
Obiekty i klasy
Autor
Roman Simiński
Kontakt
[email protected]
www.us.edu.pl/~siminski
Niniejsze opracowanie zawiera skrót treści wykładu, lektura tych materiałów nie zastąpi uważnego w nim uczestnictwa.
Opracowanie to jest chronione prawem autorskim. Wykorzystywanie jakiegokolwiek fragmentu w celach innych niż nauka własna jest nielegalne.
Dystrybuowanie tego opracowania lub jakiejkolwiek jego części oraz wykorzystywanie zarobkowe bez zgody autora jest zabronione.
Podstawy i języki programowania
Język C++
Obiekty i klasy
Obiekty i klasy w języku C++
Problem
Przewidywane jest napisanie obiektowej wersji programu, realizującego obliczenia
z wykorzystaniem pól różnych, płaskich figur geometrycznych.
Należy zdefiniować klasy opisujące takie figury.
Prostokąt
Koło
Kwadrat
Trójkąt
Copyright © Roman Simiński
Strona : 2
Podstawy i języki programowania
Język C++
Obiekty i klasy
Obiekty i klasy w języku C++
Analiza obiektowa
Stosując zasadę abstrakcji wyodrębniamy najistotniejsze cechy obiektów dla
rozpatrywanego zagadnienia — obliczeń pól figur płaskich.
?
Koło
Kwadrat
Copyright © Roman Simiński
Prostokąt
Trójkąt
Strona : 3
Podstawy i języki programowania
Język C++
Obiekty i klasy
Obiekty i klasy w języku C++
Analiza obiektowa — klasa opisu kwadratu Square
Square
Kwadrat
?
side
Modelowany obiekt
Model
implementacyjny
side
Model analityczny
Copyright © Roman Simiński
Strona : 4
Język C++
Podstawy i języki programowania
Obiekty i klasy
Obiekty i klasy w języku C++
Hermetyzacja a pola publiczne i prywatne
Stosując zasadę hermetyzacji ukrywamy dane w części prywatnej i zapewniamy dostęp
poprzez metody dostępowe (interfejsowe).
Pola publiczne a pola prywatne
s.side = 100;
cout << s.side;
// Brak hermetyzacji, bezpośredni dostęp do pól
// Brak hermetyzacji, bezpośredni dostęp do pól
s.setSide( 100 );
cout << s.getSide();
// Hermetyzacja, dostęp do pola za pomocą modyfikatora
// Hermetyzacja, dostęp do pola za pomocą akcesora
Funkcje publiczne klasy można nieformalnie podzielić na;
akcesory — funkcje umożliwiające pobieranie wartości pól, akcesorem jest np.
metoda getSide.
modyfikatory — funkcje dokonujące modyfikacji wartości pól, modyfikatorem jest
np. metoda setSide.
realizatory — funkcje realizujące właściwe dla danej klasy usługi, realizatorem jest
np. metoda area.
Copyright © Roman Simiński
Strona : 5
Podstawy i języki programowania
Język C++
Obiekty i klasy
Obiekty i klasy w języku C++
Stosowanie pól publicznych
Square
+setSide( double newSide )
+getSide()
+area()
-side: double
Copyright © Roman Simiński
Strona : 6
Podstawy i języki programowania
Język C++
Obiekty i klasy
Obiekty i klasy w języku C++
Obiekt klasy Square od strony programisty-użytkownika
Deklaracja obiektu s klasy Square:
Square s;
Ustalenie boku o długości 100
s.setSide( 100 );
Obliczenie pola kwadratu:
double p;
p = s.area();
Obliczenie i wyprowadzenie pola kwadratu do stdout:
cout << "Pole kwadratu wynosi: " << s.area();
Pobranie aktualnej długości boku:
cout << "Bok kwadratu: " << s.getSide();
Copyright © Roman Simiński
Strona : 7
Podstawy i języki programowania
Język C++
Obiekty i klasy
Obiekty i klasy w języku C++
Szkic programu obliczającego pole kwadratu
#include <iostream>
using namespace std;
// ???
int main()
{
double num;
Square s;
cout << endl << "Obliczam pole kwadratu" << endl;
cout << "Podaj bok: ";
cin >> num;
s.setSide( num );
cout << "Pole kwadratu wynosi: " << s.area();
return EXIT_SUCCESS;
}
Copyright © Roman Simiński
Strona : 8
Podstawy i języki programowania
Język C++
Obiekty i klasy
Obiekty i klasy w języku C++
Deklaracja klasy Square
class Square
{
public :
// Składowe publiczne
void
setSide( double newSide );
double getSide();
double area();
private:
// Składowe prywatne
double side;
};
Copyright © Roman Simiński
Strona : 9
Podstawy i języki programowania
Język C++
Obiekty i klasy
Obiekty i klasy w języku C++
Sekcje private i public
Dwie podstawowe sekcje:
private — elementy zadeklarowane w tej sekcji mogą być wykorzystywane
wyłącznie przez funkcje składowe danej klasy. Elementami tymi mogą być zarówno
pola i funkcje. Mówi się o nich, że są prywatne.
public — elementy zadeklarowane w tej sekcji są dostępne również dla innych
elementów programu. Mówi się o nich, że są publiczne lub stanowią interfejs klasy.
Dwie metody kolejności zapisu sekcji public i private
class C
{
public:
// Część publiczna klasy
void interfaceMethod();
private:
// Część prywatna klasy
void privateMethod();
int internalData;
};
Copyright © Roman Simiński

class C
{
private:
// Część prywatna klasy
void privateMethod();

int internalData;
public:
// Część publiczna klasy
void interfaceMethod();
};
Strona : 10
Podstawy i języki programowania
Język C++
Obiekty i klasy
Obiekty i klasy w języku C++
Definicja funkcji składowych
class Square
{
public :
void
setSide( double newSide );
double getSide();
double area();
private:
double side;
};
W języku C++ występuje operator
zakresu ::. Służy np. do deklarowania
funkcji składowych poza ciałem
klasy. Jego zastosowanie jest szersze,
zapis Square:: oznacza, że
występujący po nim element należy
do klasy Square.
void Square::setSide( double newSide )
{
side = newSide;
}
double Square::getSide()
{
return side;
}
double Square::area()
{
return side * side;
}
Copyright © Roman Simiński
Funkcje składowe poza deklaracja klasy
Strona : 11
Podstawy i języki programowania
Język C++
Obiekty i klasy
Obiekty i klasy w języku C++
Definicja funkcji składowych
class Square
{
public :
void setSide( double newSide )
{
side = newSide;
}
double getSide()
{
return side;
}
double area()
{
return side * side;
}
private:
double side;
};
Copyright © Roman Simiński
Funkcje składowe w obrębie klasy
Strona : 12
Podstawy i języki programowania
Język C++
Obiekty i klasy
Konstruktory
Co się stanie gdy nie ustalimy rozmiaru boku obiektu klasy Square?
Square s;
Square squares[ 3 ];
cout << s.area() << endl;
cout << squares[ 0 ].area() << endl;
cout << squares[ 1 ].area() << endl;
cout << squares[ 2 ].area() << endl;
?
?
?
?
Jak zainicjować obiekt na etapie jego definiowania?
Konstruktor jest specjalną funkcją, aktywowaną przez kompilator automatycznie
w momencie gdy obiekt jest tworzony. Dzieje się tak zanim programista będzie mógł
„dorwać” obiekt. Konstruktor ma przygotować obiekt do „życia”.
Konstruktor to specyficzna funkcja. Konstruktor nie ma typu rezultatu, nosi taką nazwę
jak nazwa klasy i zwykle nie wywołuje się go jawnie w kodzie programu.
Copyright © Roman Simiński
Strona : 13
Podstawy i języki programowania
Język C++
Obiekty i klasy
Konstruktory
Rodzaje konstruktorów
Występują cztery rodzaje konstruktorów:
Konstruktor domyślny (ang. default constructor) aktywowany, gdy tworzony
jest obiekt bez jawnie określonych danych inicjalizujących.
Square s, squares[10];
Konstruktor ogólny (ang. general constructor), zwany też parametrowym,
aktywowany gdy tworzymy obiekt z jawnie określonymi danymi inicjalizującymi.
Square s( 100 );
Konstruktor kopiujący (ang. copy constructor) aktywowany wtedy, gdy
tworzymy obiekt, inicjalizując go danymi z innego obiektu tej samej klasy.
Square s( 100 );
Square a = s, b( s );
Konstruktor rzutujący (ang. cast constructor) aktywowany wtedy, gdy tworzymy
obiekt, inicjalizując go danymi z obiektu innej klasy.
Square s( 100 );
Rectangle c = s, d( s );
Copyright © Roman Simiński
Strona : 14
Podstawy i języki programowania
Język C++
Obiekty i klasy
Konstruktor domyślny ― default constructor
Wprowadzamy konstruktor domyślny klasy Square
class Square
{
public :
Square();
// Konstruktor domyślny (bezparametrowy)
void
setSide( double newSide );
double getSide();
double area();
private:
double side;
};
Okoliczności aktywowania konstruktora domyślnego
Square a;
Square b;
Square c;
// Aktywacja: a.Square()
// Aktywacja: b.Square()
// Aktywacja: c.Square()
Square squares[ 3 ];
// Aktywacja: Square() dla każdego elementu tablicy:
// squares[ 0 ].Square()
// squares[ 1 ].Square()
// squares[ 2 ].Square()
Copyright © Roman Simiński
Strona : 15
Podstawy i języki programowania
Język C++
Obiekty i klasy
Konstruktor domyślny ― default constructor
Dwie wersje realizacji konstruktora domyślnego:
Wersja intuicyjna
Square::Square()
{
side = 0;
}

Wersja z listą inicjalizacyjną
Square::Square() : side( 0 )
{
}
Nazwa pola
Wyrażenie inicjalizujące
Square::Square() : side( 0 )
{
}
Lista inicjalizująca
konstruktora
Copyright © Roman Simiński

Lista inicjalizacyjna ma dwa
zastosowania. Pierwsze z nich to
inicjowanie pól obiektu.
Na liście może wystąpić nazwa pola,
a w nawiasach wartość temu polu
przypisywana.
Drugie zastosowanie listy inicjalizacyjnej zostanie omówione później.
Strona : 16
Podstawy i języki programowania
Język C++
Obiekty i klasy
Konstruktor parametrowy, inaczej ogólny ― general constructor
Czy można zainicjować obiekt na etapie deklaracji?
Square s( 100 );
cout << "Pole kwadratu wynosi: " << s.area();
Okoliczności aktywowania konstruktora ogólnego
Konstruktor ogólny pozwala na zainicjowanie pól obiektu na etapie jego deklaracji,
wartościami określonymi przez programistę.
Square a( 1 );
Square b( 5 );
Copyright © Roman Simiński
// Aktywacja: a.Square( 1 )
// Aktywacja: b.Square( 5 )
Strona : 17
Podstawy i języki programowania
Język C++
Obiekty i klasy
Konstruktor parametrowy, inaczej ogólny ― general constructor
Wprowadzamy konstruktor parametrowy (ogólny) klasy Square
class Square
{
public :
Square();
Square( double startSide );
void
setSide( double newSide );
double getSide();
double area();
private:
double side;
};
Copyright © Roman Simiński
Strona : 18
Podstawy i języki programowania
Język C++
Obiekty i klasy
Konstruktor parametrowy, inaczej ogólny ― general constructor
Dwie wersje realizacji konstruktora:
Wersja intuicyjna
Square::Square( double startSide )
{
side = startSide;
}
Wersja z listą inicjalizacyjną
Square::Square( double startSide ) : side( startSide )
{
}
Copyright © Roman Simiński
Strona : 19
Podstawy i języki programowania
Język C++
Obiekty i klasy
Konstruktor parametrowy, inaczej ogólny ― general constructor
Jak zainicjować obiekt const?
Słowo kluczowe const oznacza, że wartość zmiennej bądź argumentu nie może być
zmieniana w czasie wykonania programu.
const Square cs;
// Niezainicjowany obiekt const
cs.setSide( 1.2 );
// Błąd – próba modyfikacji obiektu const
cout << "Pole kwadratu wynosi: " << cs.area();
Konstruktor ogólny pozwala na zainicjowanie obiektów const
const Square cs( 1.2 );
// Zainicjowany obiekt const
cout << "Pole kwadratu wynosi: " << cs.area();
Copyright © Roman Simiński
Strona : 20
Podstawy i języki programowania
Język C++
Obiekty i klasy
Operator zakresu w akcji
Wykorzystanie operatora zakresu ::
Czy parametr funkcji setSide może nazywać się side? Czyli zamiast:
void Square::setSide( double newSide )
{
side = newSide;
}
definiujemy funkcję tak:
void Square::setSide( double side )
{
side = side;
}
To nie będzie działać poprawnie
Parametr formalny funkcji przesłania w jej ciele pole ― gdy ich nazwy są jednakowe
Ale można użyć operatora zakresu:
void Square::setSide( double side )
{
Square::side = side;
}
Copyright © Roman Simiński
Strona : 21
Podstawy i języki programowania
Język C++
Obiekty i klasy
Operator zakresu w akcji
Wykorzystanie operatora zakresu ::,cd. ...
Podobny problem występuje w konstruktorze:
Square::Square( double side )
{
side = side;
}
Ten konstruktor nie będzie działał poprawnie
Operator zakresu odsłania przysłonięte pole
Square::Square( double side )
{
Square::side = side;
}
Ten konstruktor będzie działał poprawnie
Problem przesłaniania pól nie występuje, gdy stosujemy listę inicjalizującą
Square::Square( double side ) : side( side )
{
}
Copyright © Roman Simiński
Strona : 22
Podstawy i języki programowania
Język C++
Obiekty i klasy
Koncepcja przeciążania funkcji
Dlaczego dwa konstruktory posiadają tę samą nazwę?
W języku C++ istnieje możliwość przeciążania nazw funkcji
Identyfikator Square jest przeciążony i oznacza:
konstruktor domyślny Square(),
konstruktor ogólny Square( float side ).
Przeciążać można również nazwy zwykłych funkcji
int add( int a, int b )
{
return a + b;
}
double add( double a, double b )
{
return a + b;
}
cout << endl << "Dodawanie int
:" << add( 1, 1 )
cout << endl << "Dodawanie double :" << add( 1.0, 1.0 );
Copyright © Roman Simiński
Strona : 23
Podstawy i języki programowania
Język C++
Obiekty i klasy
Funkcje składowe const
Uzupełniamy prototypy i definicje funkcji słowem kluczowym const
class Square
{
public :
Square();
Square( double startSide );
void
double
double
private:
double
};
Metody ze specyfikacją const nie mogą
modyfikować pól obiektu, mogą zatem
być wywoływane dla obiektów stałych.
setSide( double newSide );
getSide() const;
area() const;
side;
double Square::getSide() const
{
return side;
}
double Square::area() const
{
return side * side;
}
Copyright © Roman Simiński
Strona : 24
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Konstruktor kopiujący ― copy constructor
Dla typów wbudowanych można tak:
int j = 1;
int i = j;
Czy można tak samo dla obiektów?
Square first( 100 );
Square second = first;
Konstruktor kopiujący (ang. copy constructor), odpowiedzialny za skopiowanie
zawartości jednego obiektu do drugiego — oba tej samej klasy — na etapie inicjalizacji.
Copyright © Roman Simiński
Strona : 25
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Konstruktor kopiujący ― copy constructor
Najlepiej zdefiniować konstruktor kopiujący
class Square
{
public :
Square();
Square( double side );
Square( Square & otherSquare );
Operator & oznacza referencję,
umieszczony w deklaracji parametru
oznacza przekazanie przez zmienną.
void setSide( double side );
double getSide() const;
double area() const;
private:
double side;
};
Copyright © Roman Simiński
Strona : 26
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Konstruktor kopiujący ― copy constructor
Dwie wersje realizacji konstruktora:
Wersja intuicyjna
Square::Square( Square & otherSquare )
{
side = otherSquare.side;
}
Wersja z listą inicjalizacyjną
Square::Square( Square & otherSquare ) : side( otherSquare.side )
{
}
Copyright © Roman Simiński
Strona : 27
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Konstruktor kopiujący ― copy constructor
Okoliczności aktywowania konstruktora kopiującego
Square first( 100 );
Square second = first;
Square third( first );
// first.Square( 100 );
// second.Square( first );
// third.Square( first );
cout << "Pole kwadratu pierwszego wynosi: " << first.area();
cout << "Pole kwadratu drugiego wynosi : " << second.area();
cout << "Pole kwadratu trzeciego wynosi : " << third.area();
Konstruktor kopiujący odpowiedzialny za skopiowanie zawartości obiektów tej samej
klasy na etapie inicjalizacji.
W tej sytuacji konstruktor kopiujący nie działa!
Square first( 100 );
Square second;
second =
Copyright © Roman Simiński
first; // Tutaj nie zostaje wywołany konstruktor kopiujący
Strona : 28
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Konstruktor kopiujący ― copy constructor
Nie można:
const Square first( 1 );
Square second = first; // Błąd, niejawna referencja do obiektu const
Rozwiązanie problemu z obiektem const:
Square::Square( const Square & otherSquare ) : side( otherSquare.side )
{
}
Copyright © Roman Simiński
Strona : 29
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Będzie jeszcze jeden konstruktor...
Załóżmy, że istnieje klasa opisu prostokąta ― Rectangle
class Rectangle
{
public :
// Konstruktory
Rectangle();
Rectangle( double width, double height );
Rectangle( const Rectangle & otherRectangle );
// Modyfikatory
void setWidth( double width );
void setHeight( double height );
// Akcesory
double getWidth() const;
double getHeight() const;
// Realizator
double area() const;
private:
double width, height;
};
Copyright © Roman Simiński
Strona : 30
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Będzie jeszcze jeden konstruktor...
Definicja konstruktorów i realizatora
// Konstruktor domyślny
Rectangle::Rectangle() : width( 0 ), height( 0 )
{
}
// Konstruktor ogólny
Rectangle::Rectangle( double width, double height )
: width( width ), height( height )
{
}
// Konstruktor kopiujący
Rectangle::Rectangle( const Rectangle & otherRectangle )
: width( otherRectangle.width ), height( otherRectangle.height )
{
}
// Realizator
double Rectangle::area() const
{
return width * height;
}
Copyright © Roman Simiński
Strona : 31
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Będzie jeszcze jeden konstruktor...
Definicja modyfikatorów i realizatorów
// Modyfikatory
void Rectangle::setWidth( double width )
{
Rectangle::width = width;
}
void Rectangle::setHeight( double height )
{
Rectangle::height = height;
}
// Akcesory
double Rectangle::getWidth() const
{
return width;
}
double Rectangle::getHeight() const
{
return height;
}
Copyright © Roman Simiński
Strona : 32
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Konstruktor rzutujący ― cast constructor
Mamy klasę Square i Rectangle, czy można tak:
Square s( 100 );
Rectangle r( s );
// Definicja zainicjowanego kwadratu s
// Definicja prostokąta r, zainicjowanego kwadratem s
Następuje tutaj inicjalizacja obiektu pewnej klasy obiektem innej klasy. Skąd
kompilator ma wiedzieć, jak „przepisać” dane pomiędzy obiektami różnych klas?
Programista może określić metodę przepisania danych z obiektu jednej klasy do
obiektu klasy innej, pisząc konstruktor rzutujący.
Copyright © Roman Simiński
Strona : 33
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Konstruktor rzutujący ― cast constructor
Potrzebny jest konstruktor rzutujący
Konstruktor rzutujący odpowiedzialny za skopiowanie zawartości obiektów pewnej
klasy do obiektu innej klasy na etapie inicjalizacji.
Rectangle::Rectangle( const Square & square )
: width( square.getSide() ), height( square.getSide() )
{
}
Zdefiniowany przez programistę sposób zainicjowania wysokości i szerokości
prostokąta informacjami pochodzącymi z obiektu klasy opisującej kwadrat.
Copyright © Roman Simiński
Strona : 34
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Informacja dodatkowa ― parametry domyślne
Parametry domyślne:
void fun( int i, float
. . .
fun( 10 );
fun( 20, 3.15 );
fun( 30, 22.1, ’Z’ );
f = 0, char c = ’A’ );
// i == 10, f == 0,
c == ’A’
// i == 20, f == 3.15, c == ’A’
// i == 30, f == 22.1, c == ’Z’
Parametry domyślne dotyczą funkcji składowych klas jak i funkcji niezwiązanych
z klasami.
Parametr domyślny to wartość określona na etapie deklaracji funkcji, która
zostanie automatycznie wstawiona do parametru formalnego, jeżeli dana funkcja
zostanie wywołana bez odpowiedniego parametru aktualnego.
Parametry domyślne myszą być definiowane od końca listy parametrów.
Prototypy a parametry domyślne
Jeżeli stosujemy prototypy funkcji, wartości parametrów domyślnych określa się właśnie
w prototypie, w definicji funkcji już nie występują.
void fun( int i, float f = 0, char c = ’A’ );
. . .
void fun( int i, float f, char c )
{
}
Copyright © Roman Simiński
Strona : 35
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Podsumowanie informacji o konstruktorach
Konstruktor domyślny ― default constructor
A();
A( arg1 = wart1, arg2 = wart2, ... );
Konstruktor domyślny:
Jest bezparametrowy, lub posiada wszystkie parametry będące parametrami
domyślnymi.
Jednoczesne wystąpienie obu powyższych form spowoduje błąd kompilacji.
Inicjuje obiekty, deklarowane lub (bądź tworzone) bez parametrów.
Dotyczy to również obiektów będących elementami tablicy.
A a, b, c;
A tab[ 10 ];
Copyright © Roman Simiński
// Aktywacja: a.A(), b.A(), c.A()
// Aktywacja: A() dla każdego z 10-ciu elementów tab:
// tab[ 0 ].A(), tab[ 1 ].A(), itd... .
Strona : 36
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Podsumowanie informacji o konstruktorach
Konstruktor domyślny syntetyzowany przez kompilator
Jeżeli dla danej klasy nie zdefiniowano żadnego konstruktora, kompilator
syntetyzuje konstruktor domyślny.
Jeżeli dla danej klasy zdefiniowano jakiś konstruktor inny od domyślnego, a ten
jest potrzebny, lecz niezdefiniowany, kompilator zgłosi błąd.
Syntetyzowany konstruktor domyślny nie robi niczego mądrego. Nie należy się np.
spodziewać po nim inicjalizacji pól wartościami zerowymi.
Programista powinien zdefiniować jawnie sposób inicjalizacji obiektów definiowanych
bezparametrowo.
Służy do tego właśnie konstruktor domyślny, jego definiowanie jest dobrą praktyką.
Nie należy ufać konstruktorowi domyślnemu syntetyzowanemu przez kompilator.
Copyright © Roman Simiński
Strona : 37
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Podsumowanie informacji o konstruktorach
Konstruktor ogólny ― general constructor
A( arg1, arg2, ... );
Konstruktor ogólny:
Jest to podstawowy konstruktor przeznaczony do inicjowania obiektów na etapie
ich deklaracji czy też tworzenia.
Argumenty określają zwykle wartości jakie mają być przypisane określonym polom
obiektu.
Konstruktorów głównych może być więcej, mogą one zawierać również parametru
domyślne.
Szczególnym przypadkiem jest konstruktor posiadający tylko parametry domyślne,
staje się on wtedy konstruktorem domyślnym.
A( int a, float b, char * c
= NULL );
A obj1( 2, 3.4, "Ala");
A obj2( 1, 0.0 );
A obj3( 5, 5.5, "Pięć");
Copyright © Roman Simiński
Strona : 38
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Podsumowanie informacji o konstruktorach
Wiele konstruktorów ogólnych
Rectangle::Rectangle( float width, float height )
: width( width ), height( height )
{
}
Rectangle::Rectangle( float side )
: width( side ), height( side )
{
}
. . .
Rectangle r1( 10, 30), r2( 20 );
Copyright © Roman Simiński
Strona : 39
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Podsumowanie informacji o konstruktorach
Konstruktor kopiujący ― copy constructor
A( A & obj );
A( A & obj, arg1 = wart1, ... );
A( const A & obj );
A( const A & obj, arg1 = wart1, ... );
Konstruktor kopiujący:
Jest potrzebny jedynie wtedy, gdy przewidziana jest inicjalizacja obiektu danej klasy
innym obiektem tejże klasy:
A obj1;
A obj2 = obj1;
A obj3( obj2 );
void fun( A obj );
A obj1;
fun( obj1 );
A fun( void )
{
. . .
}
Copyright © Roman Simiński
Strona : 40
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Podsumowanie informacji o konstruktorach
Konstruktor kopiujący a bitowe kopiowanie pole po polu
Kompilator potrafi sobie poradzić z takim przypadkiem. Wykona kopiowanie
zawartości obiektu obj1 do obiektów obj2 i obj3 pole po polu, wykonując ich
bitową kopię.
W niektórych przypadkach bitowe kopiowanie pole po polu jest wystarczające.
Wtedy programista nie musi definiować konstruktora kopiującego. Tak na prawdę,
w klasach Square i Rectangle konstruktor ten nie jest potrzebny.
Rectangle r1( 10, 20 );
Rectangle r2( r1 );
r1
Copyright © Roman Simiński
r2
width 10
width 10
height 20
height 20
Strona : 41
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Podsumowanie informacji o konstruktorach
Konstruktor kopiujący a bitowe kopiowanie pole po polu
Samochod volvoS80( "Volvo", "S80" );
Samochod volvoV50( volvoS80 );
volvoV50.zmienModel( "V50" );
volvoS80
marka
Volvo
model
S80 V50
volvoV50
marka
model
Copyright © Roman Simiński
volvoV50.zmienModel( "V50" );
Strona : 42
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Podsumowanie informacji o konstruktorach
Konstruktor kopiujący a bitowe kopiowanie pole po polu
Konstruktor kopiujący ― używać, nie używać?
Stosowanie konstruktora kopiującego jest dobrą, programistyczną praktyką. Dzięki
jawnie zdefiniowanym konstruktorom programista ma kontrolę nad kopiowaniem
wartości, występujących w wielu, czasem zaskakujących sytuacjach.
Można zablokować możliwość inicjowania obiektów, wartością innego obiektu tej
samej klasy:
class A
{
public:
A() : i( 0 )
{
}
private :
A( const A & );
int i;
};
A a1;
A a2( a1 ); // A::A(const A &) is not accessible
Copyright © Roman Simiński
Strona : 43
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Podsumowanie informacji o konstruktorach
Konstruktor rzutujący ― cast, type conversion constructor
A( B & obj );
A( const B & obj );
Konstruktor rzutujący:
Posiada jeden parametr będący referencją obiektu innej klasy. Innych argumentów
może nie być lub powinny być one argumentami domyślnymi.
Jest stosowany wszędzie tam, gdzie należy zainicjować obiekt pewnej klasy
wartością obiektu innej klasy.
Programista może dzięki konstruktorowi rzutującemu określić w jaki sposób
informacje zapisane w obiekcie klasy B mają zostać odwzorowane (przepisane) w
obiekcie klasy A.
Copyright © Roman Simiński
Strona : 44
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Funkcje inline
Klasa Rectangle raz jeszcze
class Rectangle
{
public :
void setWidth( float width )
{
Rectangle::width = width;
}
float getWidth() const
{
return width;
}
. . .
};
Funkcje zdefiniowane wewnątrz definicji klasy są traktowane niejawnie jako
funkcje inline (rozwijane w miejscu wywołania).
Funkcje inline nie są wywoływane w sposób klasyczny — ich kod jest umieszczany
w miejscu wywołania i w rzeczywistości nie są one wywoływane.
Funkcje inline są preferowanym w C++ zamiennikiem makr definiowanych
z wykorzystaniem #define.
Copyright © Roman Simiński
Strona : 45
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Funkcje inline
Jak zadeklarować funkcje jako inline poza zasięgiem deklaracji klasy?
class Rectangle
{
public :
. . .
void setWidth( float width );
float getWidth() const;
. . .
};
inline void Rectangle::setWidth( float width )
{
Rectangle::width = width;
}
inline float Rectangle::getWidth() const
{
return width;
}
Copyright © Roman Simiński
Strona : 46
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Funkcje inline
Uwagi na temat funkcji inline
Jeżeli funkcje inline mają być wykorzystywane modułach umożliwiających
kompilacje rozłączną, definicja funkcji powinna wystąpić w miejscu jej zwyczajowej
deklaracji — w odpowiednim pliku nagłówkowym.
Specyfikacja ze słowem kluczowym inline to tylko rekomendacja dla kompilatora —
niektórych funkcji nie można w pełni rozwinąć i będą one wywoływane klasycznie
(np. rekurencyjne).
W porównaniu z makrami funkcje inline zapewniają kontrolę typów
i wychwytywanie błędów na etapie kompilacji.
Copyright © Roman Simiński
Strona : 47
Podstawy i języki programowania
Język C++
Podstawy programowania obiektowego
Funkcje inline
Kod wielokrotnie wykorzystujący pewną funkcję inline:
Może działać szybciej — brak narzutu czasowego związanego z organizacją wywołania
funkcji i powrotu z podprogramu;
Będzie dłuższy, zawiera bowiem rozwinięcia ciała funkcji w miejscu jej
każdorazowego wywołania.
Mechanizm funkcji zadeklarowanych jako inline przeznaczony jest do optymalizacji
małych, prostych i często wykorzystywanych funkcji.
Dobrym zastosowaniem funkcji inline jest implementacja akcesorów i modyfikatorów
realizujących dostęp do prywatnych pól klasy.
Copyright © Roman Simiński
Strona : 48

Podobne dokumenty