this ve static
Gün 2: Nesne Yönelimli Programlama (OOP) | this anahtar kelimesi, statik değişkenler ve metodlar
Bu derste iki önemli OOP kavramını öğreneceğiz: nesnenin kendisini ifade eden this anahtar kelimesi ve tüm nesneler arasında ortak olan static değişken ile metodlar. Ayrıca this'i döndürerek metodları zincirleme (method chaining) bağlamayı göreceğiz.
this Anahtar Kelimesi
this, bir metodun içinde o an üzerinde çalışılan nesneyi ifade eder. En sık iki amaçla kullanılır:
- İsim çakışmasını çözmek: Bir parametre ile özellik aynı ada sahipse,
this.id = idifadesindethis.idnesnenin özelliğini,idise parametreyi belirtir. - Metod zincirleme: Bir metod
this'i döndürürse, çağrılarınesne.metot1().metot2()şeklinde art arda bağlayabilirsiniz.
static Değişkenler ve Metodlar
Normalde her nesnenin özelliklerinin kendi kopyası vardır. static olarak işaretlenen bir değişken ise sınıfa aittir; o sınıftan üretilen tüm nesneler arasında tek bir ortak kopya paylaşılır.
staticdeğişkenler: Nesne sayısı saymak, toplam istatistik tutmak veya benzersiz kimlik üretmek gibi sınıf düzeyinde durum tutmak için idealdir.staticmetodlar: Bir nesneye ihtiyaç duymadan, sınıf adı ve::operatörüyle (Transaction::get_count()) çağrılabilir. Birstaticmetod yalnızcastaticüyelere erişebilir, nesneye özgü üyelere erişemez.
Kaynak Kod
// =============================================================================
// GUN 2 - Konu 3: this Anahtar Kelimesi, Statik Degiskenler ve Metodlar
// =============================================================================
class Transaction;
// Statik degisken: Tum nesneler arasinda paylasilir
static int count = 0;
static int total_data = 0;
// Nesne degiskenleri
int id;
int data;
string name;
// Constructor: 'this' ile parametre/ozellik ayrimi
function new(int id, int data, string name = "txn");
this.id = id; // this.id = nesne ozelligi, id = parametre
this.data = data;
this.name = name;
count++; // Her yeni nesne sayaci artirir
total_data += data;
endfunction
function void display();
$display(" [%s] id=%0d, data=%0d", this.name, this.id, this.data);
endfunction
// Statik metod: Nesne olmadan cagrilabilir
static function int get_count();
return count;
endfunction
static function int get_total_data();
return total_data;
endfunction
static function void reset_stats();
count = 0;
total_data = 0;
endfunction
// Zincirleme metod (method chaining benzeri): this dondur
function Transaction set_data(int data);
total_data -= this.data; // Eski degeri toplamdan dus...
total_data += data; // ...yeni degeri ekle (toplam tutarli kalir)
this.data = data;
return this;
endfunction
function Transaction set_name(string name);
this.name = name;
return this;
endfunction
endclass
module this_ve_static;
initial begin
Transaction t1, t2, t3;
$display("=== this ve static Kullanimi ===\n");
// --- Statik: Nesne olusmadan erisim ---
$display("--- static: Baslangic ---");
$display(" Nesne sayisi = %0d", Transaction::get_count());
// --- Nesne olustur ---
$display("\n--- Nesne Olusturma (this ile) ---");
t1 = new(1, 100, "paket_A");
t2 = new(2, 200, "paket_B");
t3 = new(3, 300, "paket_C");
t1.display();
t2.display();
t3.display();
// --- set_data ve set_name kullanimi (tek tek) ---
$display("\n--- set_data ve set_name (tek tek cagri) ---");
t1.set_data(150);
t1.set_name("paket_A_guncel");
t1.display();
// --- set_data ve set_name kullanimi (zincirleme) ---
$display("\n--- set_data ve set_name (zincirleme) ---");
t2.set_name("paket_B_plus").set_data(250);
t2.display();
// --- Statik degiskenlere erisim ---
$display("\n--- static Degiskenler ---");
$display(" Toplam nesne = %0d", Transaction::get_count());
$display(" Toplam veri = %0d", Transaction::get_total_data());
// Nesne uzerinden de erisilebilir (ayni deger)
$display(" t1.count = %0d (statik, tum nesneler ayni)", t1.count);
// --- Statik reset ---
$display("\n--- static Reset ---");
Transaction::reset_stats();
$display(" Reset sonrasi sayac = %0d", Transaction::get_count());
// Yeni nesneler
t1 = new(10, 500);
// Yeni nesne uzerinde zincirleme setter ornegi
t1.set_name("reset_sonrasi_t1").set_data(550);
t1.display();
t2 = new(20, 600);
$display(" 2 yeni nesne sonrasi sayac = %0d", Transaction::get_count());
$display(" Toplam veri = %0d", Transaction::get_total_data());
$display("\n=== this ve static Sonu ===");
$finish;
end
endmodule
Kodun Açıklaması
- Statik değişkenler:
static int countvestatic int total_data,Transactionsınıfının tüm nesneleri arasında paylaşılır. Hernew()çağrısındacount++ile nesne sayısı artar vetotal_data += dataile toplam veri birikir. thisile başlatma: Constructor'dathis.id = id,this.data = data,this.name = nameifadeleri parametre adlarıyla çakışan özellikleri ayrıştırır.- Statik metodlar:
get_count(),get_total_data()vereset_stats()staticolduğundan nesne olmadanTransaction::get_count()biçiminde çağrılabilir. Nitekim ilk çağrı, henüz hiç nesne yokken sayacı0olarak okur. - Method chaining:
set_data()veset_name()metodları, ilgili özelliği güncelledikten sonrareturn thisile nesnenin kendisini döndürür. Bu sayedet2.set_name("paket_B_plus").set_data(250)gibi zincirleme çağrı mümkün olur. - Statik üyeye nesne üzerinden erişim:
t1.countifadesi de aynı paylaşılan değeri verir; statik değişken nesneye özgü olmadığı için tüm nesnelerde aynıdır. reset_stats()etkisi: Statik sayaçlar sıfırlanır; ardından oluşturulan yeni nesneler sayacı tekrar artırmaya baştan başlar.- Dikkat -
set_datavetotal_data:set_data()yalnızcatotal_data += datayapsaydı, aynı nesnenin verisini değiştirmek toplamı çift sayardı (eski 100 + yeni 150 = 250, oysa nesnede yalnızca 150 var). Bu yüzden önce eski değer toplamdan düşülür, sonra yeni değer eklenir. Statik istatistik tutan her sınıfta bu "önce çıkar, sonra ekle" kalıbını alışkanlık yapın.
Önemli Noktalar
this, yalnızca bir nesne metodu (non-static) içinde anlamlıdır;staticbir metodun içindethiskullanılamaz çünkü ortada belirli bir nesne yoktur.staticdeğişkenler sınıf yüklendiğinde bir kez başlatılır ve nesneler arasında paylaşılır; benzersiz kimlik üretimi veya sayaç gibi global durum için idealdir.staticmetodlar yalnızcastaticüyelere erişebilir; nesneye özgü (id,data,name) alanlara erişemezler.- Statik üyelere erişmek için sınıf adı ve
::operatörünü kullanmak (Transaction::get_count()), nesne üzerinden erişmekten (t1.count) niyet olarak daha açıktır. - Method chaining için her setter'ın
return thisyapması gerekir; bu kalıp, akıcı ve okunaklı yapılandırma kodu yazmayı sağlar. t1.set_data(150);gibi bir çağrıda dönüş değeri (handle) kullanılmaz; bazı simülatörler bunun için uyarı verir. Zincirleme yapmadığınız yerlerdevoid'(t1.set_data(150));yazarak uyarıyı susturabilirsiniz.staticdeğişkenlerin bildirimde başlatılması (static int count = 0;) simülasyon başında bir kez gerçekleşir. Aynı sınıfın birden fazlapackage'e kopyalanması veya parametreli sınıflarda her özelleşmenin (Foo#(8),Foo#(16)) kendi statik kopyasına sahip olması sürpriz yaratabilir.
Statik vs Nesne Üyeleri
Nesne üyesi (int id) |
Statik üye (static int count) |
|
|---|---|---|
| Kopya sayısı | Her nesnede bir tane | Sınıf başına tek |
| Erişim | t1.id |
Transaction::count veya t1.count |
this kullanılabilir mi? |
Evet | Statik metot içinde hayır |
| Ömür | Nesne yaşadığı sürece | Tüm simülasyon boyunca |
| Tipik kullanım | Transaction alanları | ID sayacı, toplam istatistik, singleton |
Benzetme: Bir sınıfı okul olarak düşünün: her öğrencinin (nesne) kendi numarası ve notu vardır (nesne üyeleri). Okulun tek bir ziline (statik üye) herkes aynı anda uyar; zili "3-A sınıfının zili" diye ayrı ayrı düşünmezsiniz.
Transaction::get_count()zile dışarıdan bakmaktır;t1.countda aynı zile bir öğrencinin penceresinden bakmaktır.
UVM'de Karşılığı
UVM'de static kavramı her yerdedir: her bileşen tipi için factory kaydı statik bir nesnede tutulur (type_id), uvm_root::get() ve uvm_config_db statik metodlarla erişilen tekil (singleton) yapılardır. Bu derste Transaction::get_count() ile yaptığınız şey, ileride uvm_config_db#(int)::get(...) yazarken aynen karşınıza çıkacaktır.
Sık Yapılan Hatalar
- Statik metottan nesne alanına erişmek:
static function int get_id(); return id; endfunctionderleme hatasıdır; ortada bir nesne yoktur. - Statik sayacı reset etmeyi unutmak: Birden fazla test aynı simülasyonda art arda koşarsa
countsıfırlanmaz ve ikinci testin ID'leri 0'dan başlamaz. Test başındareset_stats()çağırın. thisile parametreyi karıştırmak: Constructor'daid = id;yazarsanız parametre kendine atanır, nesne alanı değişmez. Yathis.id = idyazın ya da parametre adını farklı seçin (id_i).- Static ile
const'u karıştırmak:staticpaylaşılan değişkendir ve değiştirilebilir;constise sabittir. İkisi birlikte (static const int MAX = 10;) sınıf sabiti tanımlamanın doğru yoludur.
Kendinizi Deneyin
set_dataiçindekitotal_data -= this.data;satırını silin veToplam veriçıktısının nasıl bozulduğunu gözlemleyin.Transactionsınıfınastatic function Transaction create_default();fabrika metodu ekleyip içindenew(0, 0, "default")döndürün. Statik metot nesne yaratabilir mi?static const int MAX_DATA = 1000;ekleyipset_dataiçindedata > MAX_DATAise uyarı basın.t1,t2,t3içint1.count,t2.count,t3.countdeğerlerini yazdırın; neden hepsi aynı?
Hızlı Kontrol: Statik bir metot içinde this kullanılabilir mi?
Hayır. Statik metot belirli bir nesneye bağlı değildir; Transaction::get_count() çağrıldığında ortada "bu nesne" yoktur. Bu yüzden statik metotlar yalnızca statik üyelere ve argümanlarına erişebilir.