Co to jest konstruktor?
Konstruktor to specjalna metoda, która jest wywoływana automatycznie w momencie tworzenia obiektu. Można go porównać do „fabryki” – ustawia początkowy stan obiektu, nadaje mu wartości i przygotowuje do użycia.
Analogia z życia codziennego
Wyobraź sobie fabrykę samochodów:
- Konstruktor = linia montażowa
- Parametry konstruktora = instrukcje montażu (kolor, silnik, wyposażenie)
- Nowy obiekt = gotowy samochód zjezżający z linii
Podstawy konstruktorów
Jak wygląda konstruktor?
public class Samochod
{
public string Marka;
public string Model;
public int Rocznik;
// To jest konstruktor!
public Samochod()
{
// Kod wykonywany przy tworzeniu obiektu
Marka = "Nieznana";
Model = "Nieznany";
Rocznik = 2024;
}
}Charakterystyka konstruktora:
- Ma taką samą nazwę jak klasa
- Nie ma typu zwracanego (nawet
void) - Jest wywoływany automatycznie przy
new - Może przyjmować parametry
Używanie konstruktora
// Tworzenie obiektu - konstruktor wywołuje się automatycznie
Samochod mojeAuto = new Samochod();
Console.WriteLine(mojeAuto.Marka); // "Nieznana"
Console.WriteLine(mojeAuto.Model); // "Nieznany"
Console.WriteLine(mojeAuto.Rocznik); // 2024Konstruktor domyślny (bezparametrowy)
Jeśli nie napiszesz żadnego konstruktora, C# automatycznie tworzy konstruktor domyślny:
public class Osoba
{
public string Imie;
public int Wiek;
// C# automatycznie dodaje:
// public Osoba() { }
}
// Działa, bo istnieje konstruktor domyślny
Osoba osoba = new Osoba();UWAGA: Jeśli napiszesz własny konstruktor z parametrami, konstruktor domyślny znika!
public class Student
{
public string Imie;
public int Wiek;
// Mamy konstruktor z parametrami
public Student(string imie)
{
Imie = imie;
}
}
// To już NIE DZIAŁA - brak konstruktora bezparametrowego!
// Student student = new Student(); // BŁĄD!
// Musimy użyć konstruktora z parametrem
Student student = new Student("Jan");Konstruktory z parametrami
Konstruktor z jednym parametrem
public class Ksiazka
{
public string Tytul;
public int Strony;
public string Autor;
public Ksiazka(string tytul)
{
Tytul = tytul;
Strony = 0; // Wartość domyślna
Autor = "Nieznany"; // Wartość domyślna
}
}
// Używanie
Ksiazka ksiazka = new Ksiazka("Hobbit");
Console.WriteLine(ksiazka.Tytul); // "Hobbit"Konstruktor z wieloma parametrami
public class Prostokat
{
public double Szerokosc;
public double Wysokosc;
public string Kolor;
public Prostokat(double szerokosc, double wysokosc, string kolor)
{
Szerokosc = szerokosc;
Wysokosc = wysokosc;
Kolor = kolor;
}
}
// Używanie - parametry w odpowiedniej kolejności!
Prostokat prostokat = new Prostokat(10.5, 7.2, "czerwony");Przeciążanie konstruktorów
Możesz mieć kilka konstruktorów w jednej klasie – każdy z różnymi parametrami:
public class Telefon
{
public string Marka;
public string Model;
public double Cena;
// Konstruktor 1 - bez parametrów
public Telefon()
{
Marka = "Nieznana";
Model = "Nieznany";
Cena = 0.0;
}
// Konstruktor 2 - tylko marka
public Telefon(string marka)
{
Marka = marka;
Model = "Nieznany";
Cena = 0.0;
}
// Konstruktor 3 - marka i model
public Telefon(string marka, string model)
{
Marka = marka;
Model = model;
Cena = 0.0;
}
// Konstruktor 4 - wszystkie parametry
public Telefon(string marka, string model, double cena)
{
Marka = marka;
Model = model;
Cena = cena;
}
}Używanie różnych konstruktorów
// Możemy używać dowolnego konstruktora
Telefon telefon1 = new Telefon(); // konstruktor 1
Telefon telefon2 = new Telefon("Samsung"); // konstruktor 2
Telefon telefon3 = new Telefon("Apple", "iPhone 15"); // konstruktor 3
Telefon telefon4 = new Telefon("Xiaomi", "Mi 13", 1200.50); // konstruktor 4Słowo kluczowe this
W konstruktorach możesz użyć this, żeby odwołać się do obecnego obiektu:
Problem z nazwami
public class Auto
{
public string marka;
public string model;
// Parametry mają inne nazwy niż pola - OK
public Auto(string markaSamochodu, string modelSamochodu)
{
marka = markaSamochodu;
model = modelSamochodu;
}
// Parametry mają takie same nazwy - potrzebne 'this'
public Auto(string marka, string model)
{
this.marka = marka; // this.marka = pole klasy
this.model = model; // marka = parametr
}
}Wywołanie innego konstruktora
public class Punkt
{
public int X;
public int Y;
// Konstruktor główny
public Punkt(int x, int y)
{
X = x;
Y = y;
}
// Konstruktor wywołujący inny konstruktor
public Punkt() : this(0, 0) // Wywołaj konstruktor z parametrami
{
// Dodatkowy kod (opcjonalny)
}
}Konstruktor kopiujący
Konstruktor kopiujący to specjalny konstruktor, który tworzy nowy obiekt na podstawie już istniejącego obiektu tego samego typu. W C# nie ma automatycznego konstruktora kopiującego – musimy go napisać sami.
Po co potrzebujemy konstruktora kopiującego?
Pamiętasz z tematu o referencjach? Gdy kopiujemy obiekty, kopiujemy tylko referencje:
public class Osoba
{
public string Imie;
public int Wiek;
public Osoba(string imie, int wiek)
{
Imie = imie;
Wiek = wiek;
}
}
// Problem - to nie tworzy kopii obiektu!
Osoba osoba1 = new Osoba("Jan", 25);
Osoba osoba2 = osoba1; // Tylko kopia referencji!
osoba2.Wiek = 30;
Console.WriteLine(osoba1.Wiek); // 30 - zmienione! To ten sam obiekt!Jak napisać konstruktor kopiujący
public class Osoba
{
public string Imie;
public int Wiek;
// Konstruktor normalny
public Osoba(string imie, int wiek)
{
Imie = imie;
Wiek = wiek;
}
// Konstruktor kopiujący - jako parametr obiekt tego samego typu
public Osoba(Osoba inna)
{
if (inna != null) // Sprawdzamy, czy obiekt istnieje
{
this.Imie = inna.Imie;
this.Wiek = inna.Wiek;
}
else
{
Imie = "Nieznane";
Wiek = 0;
}
}
}Używanie konstruktora kopiującego
// Tworzymy pierwszy obiekt
Osoba osoba1 = new Osoba("Jan", 25);
// Tworzymy kopię - używamy konstruktora kopiującego
Osoba osoba2 = new Osoba(osoba1); // Nowy obiekt!
// Teraz to są różne obiekty
osoba2.Wiek = 30;
Console.WriteLine(osoba1.Wiek); // 25 - nie zmieniło się!
Console.WriteLine(osoba2.Wiek); // 30Konstruktor kopiujący dla bardziej złożonych klas
public class Adres
{
public string Ulica;
public string Miasto;
public string KodPocztowy;
public Adres(string ulica, string miasto, string kod)
{
Ulica = ulica;
Miasto = miasto;
KodPocztowy = kod;
}
// Konstruktor kopiujący dla Adresu
public Adres(Adres inny)
{
if (inny != null)
{
Ulica = inny.Ulica;
Miasto = inny.Miasto;
KodPocztowy = inny.KodPocztowy;
}
}
}
public class Pracownik
{
public string Imie;
public double Pensja;
public Adres AdresZamieszkania; // Obiekt innej klasy!
public Pracownik(string imie, double pensja, Adres adres)
{
Imie = imie;
Pensja = pensja;
AdresZamieszkania = adres;
}
// Konstruktor kopiujący - uwaga na obiekt w obiekcie!
public Pracownik(Pracownik inny)
{
if (inny != null)
{
Imie = inny.Imie;
Pensja = inny.Pensja;
// WAŻNE! Tworzymy kopię adresu, nie kopiujemy referencji
if (inny.AdresZamieszkania != null)
{
AdresZamieszkania = new Adres(inny.AdresZamieszkania);
}
}
}
}Praktyczne przykłady
Przykład 1: Klasa Uczeń
public class Uczen
{
public string Imie;
public string Nazwisko;
public string Klasa;
public double SredniaOcen;
// Konstruktor pełny
public Uczen(string imie, string nazwisko, string klasa)
{
Imie = imie;
Nazwisko = nazwisko;
Klasa = klasa;
SredniaOcen = 0.0; // Domyślnie brak ocen
}
// Konstruktor z średnią
public Uczen(string imie, string nazwisko, string klasa, double srednia)
{
Imie = imie;
Nazwisko = nazwisko;
Klasa = klasa;
SredniaOcen = srednia;
}
}
// Używanie
Uczen uczen1 = new Uczen("Jan", "Kowalski", "3Ti");
Uczen uczen2 = new Uczen("Anna", "Nowak", "3Ti", 4.5);Przykład 2: Klasa Konto bankowe
public class KontoBankowe
{
public string NumerKonta;
public string Wlasciciel;
public double Saldo;
// Konstruktor - nowe konto zawsze zaczyna od 0 zł
public KontoBankowe(string numer, string wlasciciel)
{
NumerKonta = numer;
Wlasciciel = wlasciciel;
Saldo = 0.0; // Nowe konto ma 0 zł
}
// Konstruktor z początkowym saldem
public KontoBankowe(string numer, string wlasciciel, double poczatkoweSaldo)
{
NumerKonta = numer;
Wlasciciel = wlasciciel;
Saldo = poczatkoweSaldo;
}
}Najczęstsze błędy
Błąd 1: Konstruktor z typem zwracanym
// ŹLE - konstruktor nie może mieć typu zwracanego
public void Samochod()
{
// To nie jest konstruktor, to zwykła metoda!
}
// DOBRZE
public Samochod()
{
// To jest konstruktor
}Błąd 2: Inna nazwa niż klasa
public class Auto
{
// ŹLE - nazwa konstruktora musi być taka sama jak klasa
public Samochod()
{
}
// DOBRZE
public Auto()
{
}
}Błąd 3: Zapomnienie o konstruktorze domyślnym
public class Osoba
{
public string Imie;
// Mamy tylko konstruktor z parametrem
public Osoba(string imie)
{
Imie = imie;
}
}
// To nie zadziała - brak konstruktora bezparametrowego!
// Osoba osoba = new Osoba(); // BŁĄD!
// Rozwiązanie - dodaj konstruktor domyślny:
public class Osoba
{
public string Imie;
public Osoba() // Konstruktor domyślny
{
Imie = "Nieznane";
}
public Osoba(string imie)
{
Imie = imie;
}
}Kluczowe wnioski
- Konstruktor = specjalna metoda wywoływana przy tworzeniu obiektu
- Nazwa konstruktora = nazwa klasy
- Brak typu zwracanego w konstruktorze
- Konstruktor domyślny znika, gdy dodasz własny konstruktor z parametrami
- Przeciążanie – możesz mieć wiele konstruktorów z różnymi parametrami
this– odwołanie do obecnego obiektu- Konstruktor kopiujący – tworzy kopię obiektu, nie kopię referencji
Zadania do przećwiczenia
Zadanie 1: Utwórz klasę Filmv
Napisz klasę Film z polami:
Tytul(string)Rezyser(string)RokProdukcji(int)CzasTrwania(int, w minutach)
Utwórz konstruktory:
- Bezparametrowy (domyślne wartości)
- Z tytułem i reżyserem
- Z wszystkimi parametrami
Zadanie 2: Klasa Komputer
Napisz klasę Komputer z polami:
Procesor(string)Ram(int, GB)Cena(double)
Stwórz różne konstruktory i przetestuj je.
Zadanie 3: Znajdź błędy
public class Zwierze
{
public string Gatunek;
public int Wiek;
// Czy ten konstruktor jest poprawny?
public int Zwierze(string gatunek)
{
Gatunek = gatunek;
return 0;
}
}Zadanie 4: Konstruktor z walidacją
public class Student
{
public string Imie;
public int Wiek;
public Student(string imie, int wiek)
{
// Dodaj sprawdzenie:
// - imie nie może być puste
// - wiek musi być między 16 a 100
}
}