Kalıtım (Inheritance)
Gün 2: Nesne Yönelimli Programlama (OOP) | Sınıf hiyerarşisi, super anahtar kelimesi, metod genişletme
Bu derste kalıtımı (inheritance) öğreneceğiz: Var olan bir sınıftan yeni sınıflar türeterek kodu yeniden kullanmayı, extends ile sınıf hiyerarşisi kurmayı ve super anahtar kelimesiyle üst sınıfın yapısına erişmeyi inceleyeceğiz.
Kalıtım Nedir?
Kalıtım, bir sınıfın (alt/türetilmiş sınıf) başka bir sınıfın (üst/temel sınıf) tüm özelliklerini ve metodlarını devralmasıdır. SystemVerilog'da bu, class AltSinif extends UstSinif sözdizimiyle yapılır. Alt sınıf, devraldığı yapının üzerine yeni alanlar ve metodlar ekleyebilir.
Kalıtımın doğrulamadaki en büyük faydası, ortak davranışı tek bir temel sınıfta toplayıp (örneğin genel bir Transaction), özelleşmiş türleri (okuma, yazma, hatalı işlem) bu temelden türetmektir. Bu hem tekrar eden kodu azaltır hem de polimorfizmin önünü açar.
- Temel (base) sınıf: Ortak alan ve metodları içerir.
- Türetilmiş (derived) sınıf: Temeli devralır, kendine özgü alanlar ekler ve gerektiğinde metodları yeniden tanımlar.
- Çok seviyeli kalıtım: Bir alt sınıftan tekrar türetme yapılabilir (örneğin temel → yazma → hatalı yazma).
super Anahtar Kelimesi
super, alt sınıf içinden üst sınıfın üyelerine ve constructor'ına erişmeyi sağlar. En kritik kullanımı, alt sınıfın constructor'ında super.new(...) çağrısıdır: Alt sınıf, kendi alanlarını başlatmadan önce üst sınıfın doğru biçimde kurulmasını garanti etmelidir.
Kaynak Kod
// =============================================================================
// GUN 2 - Konu 5: Kalitim (Inheritance) ve super Anahtar Kelimesi
// =============================================================================
// Temel (Base) Sinif
class Transaction;
int id;
int data;
string txn_type;
static int count = 0;
function new(int id = 0, int data = 0);
this.id = id;
this.data = data;
this.txn_type = "BASE";
count++;
endfunction
function void display();
$display(" [%s] ID=%0d, Data=0x%08h", txn_type, id, data);
endfunction
function bit is_valid();
return (data != 0);
endfunction
endclass
// Alt Sinif 1: Okuma Islemi
class ReadTransaction extends Transaction;
logic [31:0] address;
int burst_length;
function new(int id, logic [31:0] addr, int burst = 1);
super.new(id, 0); // Ust sinif constructor'i cagir
this.address = addr;
this.burst_length = burst;
this.txn_type = "READ";
endfunction
function void display();
$display(" [READ] Addr=0x%08h, Burst=%0d", address, burst_length);
endfunction
endclass
// Alt Sinif 2: Yazma Islemi
class WriteTransaction extends Transaction;
logic [31:0] address;
logic [31:0] write_data;
logic [3:0] byte_enable;
function new(int id, logic [31:0] addr, logic [31:0] wdata, logic [3:0] be = 4'hF);
super.new(id, wdata);
this.address = addr;
this.write_data = wdata;
this.byte_enable = be;
this.txn_type = "WRITE";
endfunction
function void display();
$display(" [WRITE] Addr=0x%08h, WData=0x%08h, BE=0x%01h",
address, write_data, byte_enable);
endfunction
endclass
// Alt-Alt Sinif: Hatali Yazma (Hata Enjeksiyonu)
class ErrorWriteTransaction extends WriteTransaction;
bit inject_addr_error;
bit inject_data_error;
function new(int id, logic [31:0] addr, logic [31:0] wdata);
super.new(id, addr, wdata);
this.txn_type = "ERR_WRITE";
this.inject_addr_error = 0;
this.inject_data_error = 0;
endfunction
function void corrupt();
if (inject_addr_error) begin
address ^= 32'hDEAD_0000;
$display(" [!] Adres bozuldu: 0x%08h", address);
end
if (inject_data_error) begin
write_data ^= 32'h0000_BEEF;
$display(" [!] Veri bozuldu: 0x%08h", write_data);
end
endfunction
function void display();
$display(" Hata Enj.: addr=%0b, data=%0b",
inject_addr_error, inject_data_error);
endfunction
endclass
module kalitim;
initial begin
Transaction base_txn;
ReadTransaction rd_txn;
WriteTransaction wr_txn;
ErrorWriteTransaction err_txn;
$display("=== Kalitim (Inheritance) ===\n");
// --- Nesne olusturma ---
$display("--- Hiyerarsik Nesneler ---");
base_txn = new(0, 16'h0000);
rd_txn = new(1, 32'hA000_0000, 4);
wr_txn = new(2, 32'hB000_0000, 32'hCAFE_BABE);
err_txn = new(3, 32'hC000_0000, 32'h1234_5678);
base_txn.display();
rd_txn.display();
wr_txn.display();
// --- super kullanimi (zaten constructor'da) ---
$display("\n--- Hata Enjeksiyonu ---");
err_txn.inject_addr_error = 1;
err_txn.inject_data_error = 1;
$display(" Bozulmadan once:");
err_txn.display();
err_txn.corrupt();
$display(" Bozulduktan sonra:");
err_txn.display();
// --- Statik sayac (tum nesneler arasinda paylasilir) ---
$display("\n--- Statik Sayac ---");
$display(" Toplam Transaction sayisi = %0d", Transaction::count);
// --- Ust sinif referansi ile alt sinif nesnesi ---
$display("\n--- Ust Sinif Referansi ---");
$display(" base_txn.is_valid() = %0b", base_txn.is_valid());// Başta data'sı 0'dı
base_txn = wr_txn; // WriteTransaction -> Transaction (gecerli)
$display(" base_txn.is_valid() = %0b", base_txn.is_valid());
$display("\n=== Kalitim Sonu ===");
$finish;
end
endmodule
Kodun Açıklaması
- Temel
Transactionsınıfı:id,data,txn_typealanlarını vestatic int countsayacını içerir.display()veis_valid()ortak metodlarını sunar. Hernew()çağrısındacount++ile toplam işlem sayısı artar. ReadTransaction extends Transaction: Temeli devralır veaddressileburst_lengthalanlarını ekler. Constructor'dasuper.new(id, 0)ile üst sınıf kurulur, ardından kendi alanları vetxn_type = "READ"ayarlanır.WriteTransaction extends Transaction: Benzer şekildeaddress,write_data,byte_enableekler vesuper.new(id, wdata)ile veriyi temel sınıfa iletir.ErrorWriteTransaction extends WriteTransaction: İki seviyeli kalıtım örneğidir;WriteTransaction'dan türer.inject_addr_error/inject_data_errorbayraklarını ekler.corrupt()metodu, bayraklar açıksaaddressvewrite_dataalanlarını XOR (^=) ile bozar.super.new(...)zinciri:ErrorWriteTransaction::new,WriteTransaction::new'i çağırır, o daTransaction::new'i çağırır. Böylece tüm hiyerarşi sırayla başlatılır.- Statik sayaç paylaşımı:
Transaction::count, hangi alt sınıftan olursa olsun oluşturulan tüm nesneleri sayar; çünkücounttemel sınıfa aitstaticbir değişkendir. - Üst sınıf referansı:
base_txn = wr_txn;satırı geçerlidir çünküWriteTransactionbirTransaction'dır (upcasting). Atamadan sonrabase_txn.is_valid(),wr_txn'in verisi0olmadığı için1döner.
Önemli Noktalar
- Alt sınıfın constructor'ında, kendi alanlarınızı atamadan önce
super.new(...)çağrısı yapın; birçok durumda bu zorunludur ve hiyerarşinin doğru başlatılmasını sağlar. staticüyeler temel sınıfta tanımlandığında tüm alt sınıf nesneleri tarafından paylaşılır; bu, tüm hiyerarşi genelinde sayım/istatistik için kullanışlıdır.- Bir alt sınıf nesnesi her zaman üst sınıf tipindeki bir handle'a atanabilir (upcasting); tersi (downcasting) için
$castgerekir. - Bu örnekteki
display()metodlarıvirtualdeğildir; bu nedenlebase_txn = wr_txnsonrasındabase_txn.display()çağrılsaydı temel sınıfın sürümü çalışırdı. Çalışma zamanında nesnenin gerçek tipine göre metod seçilmesi içinvirtualgerekir (sonraki ders: Polimorfizm). - Çok seviyeli kalıtım güçlüdür ama hiyerarşiyi gereğinden derin tutmak okunabilirliği düşürür; ortak davranışı doğru seviyede toplamaya özen gösterin.