Konstruktor (programowanie obiektowe): Różnice pomiędzy wersjami

[wersja nieprzejrzana][wersja nieprzejrzana]
Usunięta treść Dodana treść
Linia 59:
===Konstruktor kopiujący (C++)===
Konstruktor, którego jedynym argumentem niedomyślnym jest referencja do obiektu swojej klasy. Jest on używany niejawnie wtedy, gdy działanie programu wymaga skopiowania obiektu (np.: przy przekazywaniu obiektu do funkcji ''przez wartość''). Gdy konstruktor kopiujący nie został zdefiniowany, jest on generowany niejawnie (nawet gdy są zdefiniowane inne konstruktory) i domyślnie powoduje kopiowanie wszystkich składników po kolei, np. (przykład w C++):
class leszkaKlasa {
public:
int dana;
MojaKlasa( int parametrDomyslny ) { // inny konstruktor użytkownika
this->dana = parametrDomyslny;
}
};
int main () {
MojaKlasa obiektMojejKlasy( 5 );
MojaKlasa kopiaObiektu( obiektMojejKlasy ); // użyty zostanie pedał ssący
konstruktor kopiujący
std::cout << kopiaObiektu.dana; // wyświetli "5"
return 0;
}
 
Zablokowanie tego konstruktora (np. przez umieszczenie go w sekcji prywatnej lub chronionej) oznacza brak zezwolenia na kopiowanie obiektu.
 
====Kopiowanie obiektu ''składnik po składniku''====
W większości przypadków kopiowanie obiektu ''składnik po składniku'' jest tym, czego oczekuje użytkownik klasy i nie ma potrzeby definiowania własnej wersji konstruktora kopiującego. Jednak nie zawsze takie działanie jest pożądane (przykład w C++):
siała baba mak xD
class MojaKlasa {
public:
int* wsk; // wskaźnik
MojaKlasa( int parametrDomyslny ) {
this->wsk = new int( parametrDomyslny );
}
~MojaKlasa() { // destruktor
delete this->wsk;
}
};
int main () {
MojaKlasa obiektMojejKlasy( 5 );
std::cout << *( obiektMojejKlasy.wsk ) << endl; // wyświetli: 5
MojaKlasa kopiaObiektu( obiektMojejKlasy );
// kopiowanie składnik po składniku, wskazanie też zostanie skopiowane
*( kopiaObiektu.wsk ) = 3;
std::cout << *( obiektMojejKlasy.wsk ) << endl; // wyświetli: 3
return 0;
}
: Klasa <code>MojaKlasa</code> zawiera pole <code>wsk</code> będące wskaźnikiem na zmienną typu <code>int</code>. Każdy obiekt tej klasy ma posiadać własną zmienną typu <code>int</code> którą wskazuje wskaźnik <code>wsk</code>. W kodzie programu znajduje się deklaracja obiektu klasy <code>MojaKlasa</code> gdzie następuje wywołanie zdefiniowanego konstruktora, a w nim rezerwacja pamięci na zmienną typu int i przypisanie jej adresu do wskaźnika. Następnie, w celu sprawdzenia wartości, wyświetlana jest wartość zmiennej wskazywanej przez wskaźnik z utworzonego obiektu, wartość jest równa <code>5</code>. Następnie tworzony jest drugi obiekt klasy o nazwie <code>kopiaObiektu</code> za pomocą niejawnie wygenerowanego konstruktora kopiującego, konstruktor ten kopiuje wszystkie pola klasy ''składnik po składniku''. W kolejnym kroku przypisywana jest wartość <code>3</code> zmiennej wskazywanej przez wskaźnik obiektu <code>kopiaObiektu</code>. Następnie wyświetlana jest ponownie wartość zmiennej wskazywanej przez wskaźnik obiektu <code>obiektMojejKlasy</code> (gdzie wcześniej była wartość <code>5</code>). Okazuje się, że teraz znajduje się tam wartość <code>3</code>, oba obiekty wskazują na tę samą zmienną, a w założeniach każdy obiekt miał mieć własną zmienną. Problem wynikł z tego, że nie zdefiniowano konstruktora kopiującego. Kopiowanie ''składnik po składniku'' w tym przypadku okazało się rozwiązaniem niezgodnym ze wcześniejszymi założeniami, ponieważ została skopiowana wartość wskaźnika, a nie została utworzona nowa zmienna, do której wskazanie powinno być umieszczone we wskaźniku. W efekcie otrzymaliśmy 2 obiekty wskazujące na ten sam obiekt w pamięci i modyfikacja w jednym z nich miała swój efekt w drugim. Jeszcze większy problem pojawi się w trakcie zakończania programu. Niszczenie pierwszego z dwóch obiektów przebiegnie prawidłowo, destruktor drugiego zwalnianego obiektu będzie wykonywał operację zwolnienia już zwolnionej pamięci, co spowoduje błąd. Aby uzyskać działanie klasy zgodnie z założeniami, należy zaimplementować w klasie MojaKlasa własną wersję konstruktora kopiującego:
// ...