Çok Biçimlilik (Polymorphism)
Gün 2: Nesne Yönelimli Programlama (OOP) | Virtual metodlar, upcasting, $cast ile downcasting
Bu derste çok biçimliliği (polymorphism) öğreneceğiz: Bir üst sınıf handle'ı üzerinden çağrılan metodun, çalışma zamanında nesnenin gerçek tipine göre seçilmesini sağlayan virtual metodları, upcasting'i ve $cast ile güvenli downcasting'i inceleyeceğiz.
Polimorfizm ve virtual Metodlar
Polimorfizm, "tek arayüz, çok davranış" demektir. Aynı metod çağrısının (speak()), çağrıldığı nesnenin tipine göre farklı sonuç vermesidir. Bunun anahtarı virtual anahtar kelimesidir:
- Bir metod
virtualolarak işaretlenirse, hangi sürümün çalışacağı derleme zamanında handle'ın tipine değil, çalışma zamanında nesnenin gerçek tipine göre belirlenir. Buna dinamik bağlama (dynamic dispatch) denir. virtualolmayan bir metodda ise handle'ın bildirilen tipi belirleyicidir; bu polimorfik davranışı engeller.
Bu sayede bir üst sınıf dizisinde (Animal animals[4]) farklı alt sınıf nesneleri tutup hepsi üzerinde aynı display() çağrısını yaptığınızda, her nesne kendi özelleşmiş sürümünü çalıştırır.
Upcasting ve Downcasting ($cast)
- Upcasting: Bir alt sınıf nesnesini üst sınıf handle'ına atamaktır (
animals[1] = d;). Her zaman güvenlidir ve örtük (implicit) yapılır, çünkü birDogzaten birAnimal'dır. - Downcasting: Üst sınıf handle'ından alt sınıf handle'ına dönüştürmektir. Bu tehlikelidir çünkü handle gerçekte beklenen alt tipi işaret etmeyebilir. Bu yüzden
$cast(hedef, kaynak)ile yapılır; dönüşüm başarılıysa1, değilse0döndürür ve böylece güvenli kontrol sağlanır.
Kaynak Kod
// =============================================================================
// GUN 2 - Konu 6: Cok Bicimlilik (Polymorphism) ve Sanal (Virtual) Metodlar
// =============================================================================
class Animal;
string name;
int age;
function new(string name, int age);
this.name = name;
this.age = age;
endfunction
// virtual: Alt siniflarda override edilebilir
virtual function string speak();
return "...";
endfunction
virtual function void display();
$display(" [%s] Isim: %s, Yas: %0d, Ses: %s",
get_type(), name, age, speak());
endfunction
virtual function string get_type();
return "Animal";
endfunction
endclass
class Dog extends Animal;
string breed;
function new(string name, int age, string breed = "Mixed");
super.new(name, age);
this.breed = breed;
endfunction
virtual function string speak();
return "Hav hav!";
endfunction
virtual function string get_type();
return "Dog";
endfunction
virtual function void display();
super.display();
$display(" Cins: %s", breed);
endfunction
endclass
class Cat extends Animal;
bit is_indoor;
function new(string name, int age, bit indoor = 1);
super.new(name, age);
this.is_indoor = indoor;
endfunction
virtual function string speak();
return "Miyav!";
endfunction
virtual function string get_type();
return "Cat";
endfunction
virtual function void display();
super.display();
$display(" Ev kedisi: %s", is_indoor ? "Evet" : "Hayir");
endfunction
endclass
class Parrot extends Animal;
string vocabulary [$];
function new(string name, int age);
super.new(name, age);
endfunction
function void learn_word(string word);
vocabulary.push_back(word);
endfunction
virtual function string speak();
if (vocabulary.size() > 0) begin
int idx = $urandom % vocabulary.size();
return vocabulary[idx];
end
return "Cik cik!";
endfunction
virtual function string get_type();
return "Parrot";
endfunction
endclass
module polymorphism;
initial begin
// Ust sinif dizisi ile tum hayvanlari tutma (Polimorfizm)
Animal animals [4];
Dog d;
Cat c;
Parrot p;
Animal a_ref; // Dog nesnesi, Animal referansi
Dog d_ref;
$display("=== Polimorfizm (Polymorphism) ===\n");
// --- Nesneler olustur ---
d = new("Karabas", 3, "Golden Retriever");
c = new("Tekir", 2, 0);
p = new("Papagan", 5);
p.learn_word("Merhaba!");
p.learn_word("Gunaydin!");
p.learn_word("Nasilsin?");
// --- Polimorfik dizi ---
animals[0] = new("Bilinmeyen", 0); // Base
animals[1] = d; // Dog -> Animal (upcasting)
animals[2] = c; // Cat -> Animal
animals[3] = p; // Parrot -> Animal
// --- virtual metod cagrilari ---
$display("--- Polimorfik display() ---");
foreach (animals[i]) begin
$display("\n Hayvan #%0d:", i);
animals[i].display(); // Her nesne kendi override'ini calistirir
end
// --- $cast ile downcasting ---
$display("\n--- $cast ile Downcasting ---");
a_ref = d; // Dog nesnesi, Animal referansi
// Guvenli donusum
if ($cast(d_ref, a_ref)) begin
$display(" Cast basarili! Cins: %s", d_ref.breed);
end else begin
$display(" Cast basarisiz!");
end
// Yanlis cast denemesi
a_ref = c; // Cat nesnesi
if (!$cast(d_ref, a_ref))
$display(" Cat -> Dog cast basarisiz (beklenen)");
// --- Polimorfik fonksiyon ---
$display("\n--- Polimorfik Fonksiyon ---");
begin
foreach (animals[i]) begin
make_speak(animals[i]);
end
end
$display("\n=== Polimorfizm Sonu ===");
$finish;
end
// Herhangi bir Animal alt sinifini kabul eder
function void make_speak(Animal a);
$display(" %s diyor: %s", a.name, a.speak());
endfunction
endmodule
Kodun Açıklaması
Animaltemel sınıfı:name,agealanları ve üçvirtualmetod (speak(),display(),get_type()) içerir.virtualolmaları, alt sınıfların bu metodları geçersiz kılabilmesini (override) ve polimorfik çağrıyı mümkün kılar.- Alt sınıflar:
Dog,CatveParrot,Animal'dan türer vespeak()ileget_type()metodlarını kendilerine göre yeniden tanımlar.DogveCatayrıcadisplay()'i geçersiz kılarken içindesuper.display()çağırarak temel çıktının üzerine ek bilgi yazar. Parrotve kuyruk:vocabularybir kuyruktur (string [$]).learn_word()ile kelime eklenir;speak()kuyrukta kelime varsa$urandomile rastgele birini döndürür.- Polimorfik dizi:
Animal animals[4]dizisine farklı tipte nesneler atanır (upcasting).animals[1] = d;ile birDog,Animalhandle'ına yerleştirilir. - Dinamik bağlama:
foreachdöngüsündeanimals[i].display()çağrılır. Metodvirtualolduğu için her eleman kendi gerçek tipinindisplay()vespeak()sürümünü çalıştırır; handleAnimaltipinde olmasına rağmen. $castile downcasting:a_ref = d;sonrası$cast(d_ref, a_ref)başarılı olur çünküa_refgerçekte birDog'u işaret eder. Ancaka_ref = c;(birCat) yapıldığında$cast(d_ref, a_ref)başarısız olur ve0döndürür; bu yüzden!$cast(...)koşulu beklenen şekilde çalışır.- Polimorfik fonksiyon:
make_speak(Animal a)herhangi birAnimalalt sınıfını kabul eder vea.speak()çağrısı yine gerçek tipe göre çözülür.
Önemli Noktalar
- Polimorfik davranış için metodlar
virtualolmalıdır.virtualolmazsa, handle'ın bildirilen tipine göre statik bağlama yapılır ve override edilen sürüm çağrılmaz. virtualbir metod, kalıtım zinciri boyunca türetilen sınıflarda davirtualkalır; alt sınıflarda tekrarvirtualyazmak iyi bir okunabilirlik pratiğidir.- Downcasting için her zaman
$castkullanın ve dönüş değerini kontrol edin; doğrudan atama derleme hatası verir veya güvensizdir.$castbaşarısızsa0döner ve çalışma zamanı hatasından kaçınılır. - Upcasting örtüktür ve daima güvenlidir; downcasting ise yalnızca handle gerçekten hedef tipi işaret ediyorsa başarılı olur.
super.metot()çağrısı, override edilen bir metodun üst sınıf davranışını koruyup üzerine ekleme yapmak için kullanılır (örneğinDog::displayiçindekisuper.display()).- Polimorfizm, UVM gibi doğrulama metodolojilerinin temelidir: ortak bir temel transaction/bileşen arayüzü üzerinden farklı türler tek tip kodla işlenebilir.