this Pointer, static Üyeler
Bu derste iki önemli kavramı öğreneceğiz: this pointer ve static üyeler. this bir nesnenin "kendisine" işaret eden pointer'dır. static ise nesneye değil, sınıfa ait olan üyelerdir.
İkisi birbirinin zıttı gibi: this "ben kimim?" der, static ise "ben hiç kimseye özel değilim, herkesle paylaşılırım" der.
this Pointer Nedir?
Her üye fonksiyon çağrıldığında, derleyici gizli bir parametre olarak çağıran nesnenin adresini geçirir. Bu gizli parametrenin adı this'tir.
Bunu bir nüfus cüzdanı gibi düşün. Her vatandaşın cüzdanı var ve cüzdan sahibinin kim olduğunu gösterir. Nesnenin this'i de o nesnenin "kimliği" — kendisinin bellekteki adresi.
#include <iostream>
#include <string>
using namespace std;
class Ogrenci {
private:
string isim;
int numara;
public:
Ogrenci(string isim, int numara) {
// Parametre adı üye değişkenle aynı olunca
// this-> ile ayırt ederiz
this->isim = isim;
this->numara = numara;
}
void bilgi() {
cout << "Nesne adresi: " << this << endl;
cout << "İsim: " << this->isim << endl; // this-> opsiyonel burada
cout << "İsim: " << isim << endl; // aynı şey
}
};
int main() {
Ogrenci ali("Ali", 1001);
Ogrenci veli("Veli", 1002);
ali.bilgi(); // farklı adres
veli.bilgi(); // farklı adres
return 0;
}this Ne Zaman Kullanılır?
İsim çakışması: Parametre adı üye değişkenle aynı olduğunda
Method chaining: Fonksiyondan
*thisdöndürerek zincirleme çağrıKendini parametre olarak geçirme: Başka fonksiyona kendini gönderme
#include <iostream>
using namespace std;
class Sayac {
private:
int deger;
public:
Sayac(int deger = 0) : deger(deger) {}
// 1. İsim çakışması
void ayarla(int deger) {
this->deger = deger; // this-> olmadan deger = deger olur (anlamsız)
}
// 2. Kendini döndürme (daha sonra method chaining'de)
Sayac& artir() {
deger++;
return *this;
}
void yazdir() {
cout << "Değer: " << deger << endl;
}
};
int main() {
Sayac s;
s.ayarla(10);
s.yazdir(); // Değer: 10
return 0;
}💡 İpucu: Modern C++'ta isim çakışmasından kaçınmak için üye değişkenlere önek eklemek yaygın bir pratiktir:
m_isim,isim_veya_isim. Bu durumdathis->kullanmaya gerek kalmaz.
Method Chaining (Fluent Interface)
Fonksiyondan *this döndürerek birden fazla çağrıyı zincirleme yapabilirsin. Bu kalıba fluent interface denir.
jQuery veya JavaScript'teki .then().then().catch() zincirini biliyorsan, aynı fikir:
#include <iostream>
#include <string>
using namespace std;
class Sorgu {
private:
string tablo;
string kosul;
int limit_deger;
string siralama;
public:
Sorgu() : limit_deger(0) {}
Sorgu& from(const string& t) {
tablo = t;
return *this; // kendini döndür
}
Sorgu& where(const string& k) {
kosul = k;
return *this;
}
Sorgu& limit(int n) {
limit_deger = n;
return *this;
}
Sorgu& orderBy(const string& s) {
siralama = s;
return *this;
}
string olustur() {
string sql = "SELECT * FROM " + tablo;
if (!kosul.empty()) sql += " WHERE " + kosul;
if (!siralama.empty()) sql += " ORDER BY " + siralama;
if (limit_deger > 0) sql += " LIMIT " + to_string(limit_deger);
return sql;
}
};
int main() {
// Method chaining — her fonksiyon *this döndürdüğü için zincirleme çalışır
string sql = Sorgu()
.from("ogrenciler")
.where("yas > 18")
.orderBy("isim ASC")
.limit(10)
.olustur();
cout << sql << endl;
// SELECT * FROM ogrenciler WHERE yas > 18 ORDER BY isim ASC LIMIT 10
return 0;
}Bir de klasik "Builder" örneği:
#include <iostream>
#include <string>
using namespace std;
class HtmlBuilder {
private:
string html;
public:
HtmlBuilder& baslik(const string& metin) {
html += "<h1>" + metin + "</h1>\n";
return *this;
}
HtmlBuilder& paragraf(const string& metin) {
html += "<p>" + metin + "</p>\n";
return *this;
}
HtmlBuilder& liste(const string& oge) {
html += "<li>" + oge + "</li>\n";
return *this;
}
string olustur() { return html; }
};
int main() {
string sayfa = HtmlBuilder()
.baslik("Merhaba")
.paragraf("Bu bir test sayfası.")
.liste("Madde 1")
.liste("Madde 2")
.olustur();
cout << sayfa;
return 0;
}static Üye Değişkenler
Normal üye değişkenler her nesne için ayrı kopyadır. static üye değişken ise tüm nesneler tarafından paylaşılır — sınıfa ait, nesneye değil.
Bunu bir sınıftaki sınıf panosu gibi düşün. Her öğrencinin kendi defteri var (normal üyeler), ama panodaki bilgi herkesle ortak (static üye).
#include <iostream>
#include <string>
using namespace std;
class Ogrenci {
private:
string isim;
int numara;
static int toplam_ogrenci; // static — tüm nesneler paylaşır
public:
Ogrenci(string i) : isim(i) {
toplam_ogrenci++;
numara = toplam_ogrenci;
cout << isim << " oluşturuldu (Toplam: "
<< toplam_ogrenci << ")" << endl;
}
~Ogrenci() {
toplam_ogrenci--;
cout << isim << " silindi (Toplam: "
<< toplam_ogrenci << ")" << endl;
}
static int toplamOgrenci() {
return toplam_ogrenci;
}
void bilgi() {
cout << numara << ". " << isim << endl;
}
};
// static üye değişken sınıf DIŞINDA tanımlanmalı
int Ogrenci::toplam_ogrenci = 0;
int main() {
cout << "Başlangıç: " << Ogrenci::toplamOgrenci() << endl; // 0
Ogrenci ali("Ali");
Ogrenci veli("Veli");
cout << "Şu an: " << Ogrenci::toplamOgrenci() << endl; // 2
{
Ogrenci ayse("Ayşe");
cout << "İç scope: " << Ogrenci::toplamOgrenci() << endl; // 3
} // Ayşe silindi
cout << "Dış scope: " << Ogrenci::toplamOgrenci() << endl; // 2
return 0;
}Önemli Noktalar
class Ornek {
static int sayac; // BİLDİRİM — sınıf içinde
static const int MAX = 100; // const static başlatılabilir (integral)
inline static int id = 0; // C++17: inline static doğrudan başlatılabilir
};
int Ornek::sayac = 0; // TANIM — sınıf dışında (zorunlu, C++17 öncesi)⚠️ Dikkat: static üye değişken sınıf içinde bildirilir ama sınıf dışında tanımlanmalıdır (C++17'deki
inline statichariç). Tanımlamayı unutursan linker hatası alırsın.
static Üye Fonksiyonlar
static fonksiyonlar nesne olmadan çağrılabilir. this pointer'ları yoktur — sadece static üyelere erişebilirler:
#include <iostream>
using namespace std;
class Matematik {
public:
static double pi() { return 3.14159265; }
static double daire_alani(double r) {
return pi() * r * r;
}
static int faktoriyel(int n) {
if (n <= 1) return 1;
return n * faktoriyel(n - 1);
}
static double mutlak(double x) {
return x < 0 ? -x : x;
}
};
int main() {
// Nesne oluşturmadan çağrılır
cout << "Pi: " << Matematik::pi() << endl;
cout << "Daire alanı (r=5): " << Matematik::daire_alani(5) << endl;
cout << "5! = " << Matematik::faktoriyel(5) << endl;
cout << "|-7| = " << Matematik::mutlak(-7) << endl;
return 0;
}static Fonksiyonların Kısıtlamaları
class Ornek {
int x; // normal üye
static int y; // static üye
public:
static void staticFn() {
// y = 10; // OK — static üyeye erişebilir
// x = 10; // HATA! Non-static üyeye erişemez
// this->x = 10; // HATA! this pointer yok
}
void normalFn() {
x = 10; // OK
y = 10; // OK — normal fonksiyon static üyeye de erişebilir
}
};
int Ornek::y = 0;Singleton Pattern (Kısa Örnek)
Singleton, bir sınıftan sadece bir nesne oluşturulmasını garanti eden tasarım kalıbıdır. static üye fonksiyon ve private constructor ile uygulanır:
#include <iostream>
#include <string>
using namespace std;
class Ayarlar {
private:
string tema;
int font_boyutu;
// Constructor private — dışarıdan nesne oluşturulamaz
Ayarlar() : tema("koyu"), font_boyutu(14) {
cout << "Ayarlar oluşturuldu" << endl;
}
public:
// Kopyalama yasak
Ayarlar(const Ayarlar&) = delete;
Ayarlar& operator=(const Ayarlar&) = delete;
// Tek nesneye erişim noktası
static Ayarlar& getInstance() {
static Ayarlar instance; // İlk çağrıda oluşturulur, sonra aynı döner
return instance;
}
void setTema(const string& t) { tema = t; }
string getTema() const { return tema; }
void setFontBoyutu(int b) { font_boyutu = b; }
int getFontBoyutu() const { return font_boyutu; }
};
int main() {
// Ayarlar a; // HATA! Constructor private
Ayarlar& ayar1 = Ayarlar::getInstance();
Ayarlar& ayar2 = Ayarlar::getInstance();
ayar1.setTema("açık");
cout << ayar2.getTema() << endl; // "açık" — aynı nesne!
// Adresleri kontrol et
cout << "&ayar1: " << &ayar1 << endl;
cout << "&ayar2: " << &ayar2 << endl; // aynı adres!
return 0;
}Bu Singleton implementasyonu Meyers' Singleton olarak bilinir ve C++11'den itibaren thread-safe'dir (yerel static değişkenler thread-safe olarak başlatılır).
💡 İpucu: Singleton çok tartışmalı bir pattern'dir. Global state oluşturur ve test etmeyi zorlaştırır. Kullanmadan önce gerçekten gerekli mi diye düşün. Alternatif olarak dependency injection tercih edilebilir.
Pratik Örnek: ID Generator
#include <iostream>
#include <string>
using namespace std;
class IdGenerator {
private:
static int sonraki_id;
public:
static int yeniId() {
return ++sonraki_id;
}
static int mevcutId() {
return sonraki_id;
}
static void sifirla() {
sonraki_id = 0;
}
};
int IdGenerator::sonraki_id = 0;
class Urun {
private:
int id;
string isim;
double fiyat;
public:
Urun(string i, double f)
: id(IdGenerator::yeniId()), isim(i), fiyat(f) {}
void yazdir() {
cout << "#" << id << " " << isim << " - " << fiyat << " TL" << endl;
}
};
int main() {
Urun u1("Klavye", 250);
Urun u2("Mouse", 150);
Urun u3("Monitor", 3500);
u1.yazdir(); // #1 Klavye - 250 TL
u2.yazdir(); // #2 Mouse - 150 TL
u3.yazdir(); // #3 Monitor - 3500 TL
cout << "Toplam ürün: " << IdGenerator::mevcutId() << endl;
return 0;
}Pratik Örnek: Bağlantı Havuzu (Connection Pool Konsepti)
#include <iostream>
using namespace std;
class Baglanti {
private:
int id;
bool aktif;
static int toplam_baglanti;
static const int MAX_BAGLANTI = 5;
public:
Baglanti() : aktif(false), id(0) {}
static bool yeniBaslat(Baglanti& b) {
if (toplam_baglanti >= MAX_BAGLANTI) {
cout << "HATA: Maksimum bağlantı sayısına ulaşıldı!" << endl;
return false;
}
toplam_baglanti++;
b.id = toplam_baglanti;
b.aktif = true;
cout << "Bağlantı #" << b.id << " açıldı ("
<< toplam_baglanti << "/" << MAX_BAGLANTI << ")" << endl;
return true;
}
void kapat() {
if (aktif) {
aktif = false;
toplam_baglanti--;
cout << "Bağlantı #" << id << " kapatıldı ("
<< toplam_baglanti << "/" << MAX_BAGLANTI << ")" << endl;
}
}
static int aktifSayisi() { return toplam_baglanti; }
};
int Baglanti::toplam_baglanti = 0;
int main() {
Baglanti b1, b2, b3, b4, b5, b6;
Baglanti::yeniBaslat(b1);
Baglanti::yeniBaslat(b2);
Baglanti::yeniBaslat(b3);
Baglanti::yeniBaslat(b4);
Baglanti::yeniBaslat(b5);
Baglanti::yeniBaslat(b6); // HATA: Maksimum!
b2.kapat();
Baglanti::yeniBaslat(b6); // Şimdi açılabilir
return 0;
}Özet
this pointer, üye fonksiyon içinde çağıran nesnenin adresini tutan gizli bir pointer'dır. Parametre ismi ile üye değişken çakıştığında
this->ile ayırt edilir.Method chaining (fluent interface), fonksiyonlardan
*thisdöndürerek zincirleme çağrı yapmayı sağlar. Builder pattern ve sorgu oluşturucularda yaygın kullanılır.static üye değişkenler tüm nesneler tarafından paylaşılır, sınıfa aittir. Sınıf dışında tanımlanmalıdır (C++17
inline statichariç).static üye fonksiyonlar nesne olmadan
Sinif::fonksiyon()şeklinde çağrılır.thispointer'ları yoktur, sadece static üyelere erişebilirler.Singleton pattern, private constructor + static getInstance() ile bir sınıftan tek nesne oluşturmayı garanti eder. Meyers' Singleton C++11'den itibaren thread-safe'dir.
static üyeler global state oluşturur; dikkatli kullan. Nesne sayacı, ID üreteci, konfigürasyon gibi gerçekten paylaşılması gereken durumlar için uygundur.
AI Asistan
Sorularını yanıtlamaya hazır