EDA Playground'da Dene

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 Transaction sınıfı: id, data, txn_type alanlarını ve static int count sayacını içerir. display() ve is_valid() ortak metodlarını sunar. Her new() çağrısında count++ ile toplam işlem sayısı artar.
  • ReadTransaction extends Transaction: Temeli devralır ve address ile burst_length alanlarını ekler. Constructor'da super.new(id, 0) ile üst sınıf kurulur, ardından kendi alanları ve txn_type = "READ" ayarlanır.
  • WriteTransaction extends Transaction: Benzer şekilde address, write_data, byte_enable ekler ve super.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_error bayraklarını ekler. corrupt() metodu, bayraklar açıksa address ve write_data alanlarını XOR (^=) ile bozar.
  • super.new(...) zinciri: ErrorWriteTransaction::new, WriteTransaction::new'i çağırır, o da Transaction::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ü count temel sınıfa ait static bir değişkendir.
  • Üst sınıf referansı: base_txn = wr_txn; satırı geçerlidir çünkü WriteTransaction bir Transaction'dır (upcasting). Atamadan sonra base_txn.is_valid(), wr_txn'in verisi 0 olmadığı için 1 dö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 $cast gerekir.
  • Bu örnekteki display() metodları virtual değildir; bu nedenle base_txn = wr_txn sonrasında base_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çin virtual gerekir (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.