PDA

Tam Sürümünü Görmek İçin : Static Üye İşlevler


Arkantos
26/12/2005, 13:11
Geçenlerde aslında CDilinde konuşulmuştu. Ama ben bazı ayrıntılarını tam anlamadığım için burada da sorayım dedim. Soru şu:
Statik üye işlevler yalnızca statik olan sınıf değişkenlerine mi erişebilirler?

Ben bu sorunun cevabını:

Statik üye işlevler kendi sınıflarına ait tüm statik üyelere erişebilirler ayrıca bu nesnelerin var olduklarından haberdar oldukları sürece kendi sınıflarına ait tüm veri üyelerine de
erişebilirler

diye biliyorum.

Örneğin:

class BirSinif
{
public:
static void birseyYap (BirSinif & sinif)
{
sinif.deger_ = 42;
}

private:
int deger_;
};

int main ()
{
BirSinif nesne;
BirSinif::birseyYap (nesne);
}

Başka bir arkadaş da "Static Fonksiyon kullanirken dinamik olarak tanimlanan veri elemanlarına ulasamazsın" demiş ve şu örneği vermiş:

class Item
{
public:
double x,y,z;
public:
static void Draw(Item * item)
{
item->x;
}

};


int main()
{
Item item;
item.x=10;
item.y=20;
item.z=30;
Item::Draw(&item);
return 1;
}

Ama burada dinamik olarak tanımlamakla falan alakası yok değil mi? Burada da static işleve bir Item* gönderdiğimiz için statik üye işlevi nesnenin varlığından haberdar ettiğimiz için erişebiliyoruz.

Bir de genel olarak hangi durumlarda yazdığım bir üye işlevi statik yapmam gerekir, statik üye işlevlere ne zaman ihtiyaç duyarız?


mr1yh1
26/12/2005, 18:24
Statik üye işlevler kendi sınıflarına ait tüm statik üyelere erişebilirler ayrıca bu nesnelerin var olduklarından haberdar oldukları sürece kendi sınıflarına ait tüm veri üyelerine de
erişebilirler
+1

fakat bu "haberdar edilme" durumu, olayı prosedürel programlama haline getiriyor.
class B : A {...}
A* a = new B();
a.virtualMethod();// çalışma zamanı polimorfizmi mümkün.
B::staticMethod(a); // imkansız.
...
statik metodları , factory ve singleton gibi "yaratım" kategorisindeki design pattern'lerinde görüyorum.
statik metodların çağrılması nesnenin yaratılmasını gerektirmediğinden , nesnenin yaratımının kontrol altına alınması için uygunlar.

ayrıca sadece fonksiyonları paketleyen sınıflar , sadece statik metodlardan oluşabiliyor.
mesela sin(x) cos(x), bu fonksiyonlara ulaşmak için nesne yaratılması gereksiz.(java daki Math sınıfı gibi. )
tabi ki bu C++ de namespace kullanılarak da yapılabilir.

...
ikinci örnekteki kastedilen durumu anlamadım.

Sabahi
26/12/2005, 21:59
mr1yh1 in da soyledigi gibi bir sinifin uye islevi static ise bu islev C ile yazilmis bir islevden farksiz hale gelir. Ve static uye ile static olmayan uye islevinin arasindaki fark sadece non-static uyelerin gizli parametresi "this" pointer a sahip olmasindan ibarettir. Bu pointer olmadan islev hangi nesne uzerinde islem yapacagini bilemeyecegi icin extra olarak soz konusu nesneyi belirten bir parametreye ihtiyac duyulur. Elbette boyle bir ihtiyac ancak bir sinifin birden fazla nesnesi kullanildiginda gereklidir. Verdiginiz ikinci ornekte arkadasin demek istedigi bu olsa gerek.

Arkantos
27/12/2005, 18:29
Yani benim anladığım kadarıyla ben bu haberdar edilmeyi şöyle yorumluyorum. Statik olan bir üye işleve bir (BirSinif &) yani BirSinif türünde bir referans gönderdiğimizde bu statik üye işlevi BirSinif nesnesinin varlığından haberdar etmiş oluyoruz. Yine ikinci örnekte de ben statik üye işleve bir Item * gönderdiğimiz için yine statik üye işlevi Item nesnesinin varlığından haberdar etmiş oluyoruz diye düşünmüştüm. Bilmiyorum yorum yanlış mı? Yani burada dinamik olarak tanımlanan bir veri üyesi falan yok. Dinamik olarak tanımlanan öğeleri new ile oluşturmuyormuyuz..

Çok ilginç bir şekilde Schildt'in kitabının Türkçe çevirisinde:

Static olarak bildirilen bir üye işlev sadece kendi sınıfının üye işlevlerine erişebilir.

demiş ama ben biryerlerde bunun böyle olmadığını okumuştum. Emin olmak için (kafama takılmasın diye sordum)

Yani biz o nesneyi statik üye işleve gönderdiğimizde normalde statik üye işlevlerin gizli this işaretçisi yokken artık bir this işaretçisine sahip oluyor ve artık diğer üye işlevlere de erişebiliyoruz. Umarım yanlış anlamamışımdır.. Bir de ne zaman ihtiyaç duyarız derken kastettiğim şuydu. Normal değişkenler bir nesnenin kopyasını kullanıyor, statik üye değişkende ise tüm nesneler aynı nesneye ait değişkeni paylaşıyor. Böyle bir duruma pratik olarak ne zaman ihtiyaç duyarız diye merak ettim..

@mr1yh1: factory, singleton, design pattern .. mr1yh1 bu konuştukların çok teknik geliyor bana. Daha bunları anlamak için çok ekmek yemem lazım :p

Revne
27/12/2005, 21:31
Yani benim anladığım kadarıyla ben bu haberdar edilmeyi şöyle yorumluyorum. Statik olan bir üye işleve bir (BirSinif &) yani BirSinif türünde bir referans gönderdiğimizde bu statik üye işlevi BirSinif nesnesinin varlığından haberdar etmiş oluyoruz. Yine ikinci örnekte de ben statik üye işleve bir Item * gönderdiğimiz için yine statik üye işlevi Item nesnesinin varlığından haberdar etmiş oluyoruz diye düşünmüştüm. Bilmiyorum yorum yanlış mı?

Dogru fakat eksik..

Aslinda static bir fonksiyona bir nesneyi parametre olarak gecirmekteki tek amac o nesnenin static olmayan verilerine erismek.

Item* parametre olarak gecirilmesi tamamen fonksiyonun ne yapacagiyla alakalı.. Eger sen fonksiyonu, olusturulmus bir nesne kullanan fonksiyon olarak tasarlamıssan demek ki bu hazır halde parametre olarak gonderilen nesnenin diger static olmayan uyerine eriseceksin..
Yada NULL olan bir pointer gonderip bunu statik fonksiyon icinde new ile olusturup bazı ilk degerlerle de set etmekte de kullanabilirsin.. Tamaman sana kalmış.

Genelde static fonksiyonlara fazla ihtiyac duyulmaz.
Static konusunu bende ilk okudugumda anlamamıştım. Daha sonra ozelikle thread ve timer islemleri icin gerektiginde mecburen kullandım. (Buradan su cıkıyor geliba Thread ve Timer fonksiyonlari stackten cagrilması gereken fonksiyonlardır.Yanlışta dusunuyor olabilirim.)

Advanced:
MFC deki static Create fonksiyonlari tamamen boyle calisir. Yaptıkları tek sey uyerleri olduklari nesneleri new ile olusturmak.. Bu aslında Serieleştirmenin de temelini olusturuyor...

Sabahi
28/12/2005, 07:25
#include <iostream>

using namespace std;

class BirSinif
{
public:

BirSinif(char *i) {isim = strdup(i); m_objCount++; cout<<"\n"<<isim<<" isimli nesne dogdu.\n";}
~BirSinif() { m_objCount--; cout<<"\n"<<isim<<" isimli nesne oldu. Ruhuna fatiha!\n"; free(isim);}

static int get_object_count() { return m_objCount; }
void kimdir() { cout<<"\nBenim ismim "<<isim<<" .\n"; }

private:
static int m_objCount;
char *isim;

};

/* static degiskenler constructor icerisinde initialize edilmez. */
int BirSinif::m_objCount=0; // Initialize m_objCount

int main(int argc, char* argv[])
{
cout<<BirSinif::get_object_count ()<<" nesne bulundu.\n";
BirSinif bs1("bs1");
//bs1.kimdir ();
/* Static uye verilere iki turlu ulasilabilir. Nesne ile veya nesne kullanmadan. */
cout<<BirSinif::get_object_count ()<<" nesne bulundu.\n"; // Sinif ismi niteleyicisi ile cagri
cout<<bs1.get_object_count ()<<" nesne bulundu.\n"; // Nesne araciligi ile cagri

BirSinif *bs2 = new BirSinif("bs2");
//bs2->kimdir();
cout<<BirSinif::get_object_count ()<<" nesne bulundu.\n";
cout<<bs2->get_object_count ()<<" nesne bulundu.\n";
delete bs2;

return 0;
}

Yukaridaki kod parcasi cogu C++ kitaplarinda bulunabilecek turden ve static uye islevlerin yaygin bir kullanim amacina uygun bir ornek. Ve bu ornekten yola cikarsak su ifadeler dogru.
1) Statik üye işlevler kendi sınıflarına ait tüm statik üyelere erişebilirler ancak normal data uyelerine erisemezler. Normal uye islevler her tur data uyesine erisebilir.
2) Static uye islevler herhangi bir nesnenin var olup olmadigindan bagimsiz olarak cagrilabilirler. Normal uye islevler sadece nesneye bagli olarak cagrilabilir.
3) Static uye islevler virtual olamaz. Normal uye islevler olabilir.
4) Static uye islevler this pointer a sahip degildir. Normal uye islevler sahiptir.

Bu ifadeler dogru olmakla birlikte zaman zaman static uye islev kullanmamiz ve bu ifadelerin getirdigi sinirlamalarin otesine gecebilmemiz gerekiyor ki cogu sinirlamalarin nedeni this isaretcisinin eksikligi. Bu tur durumlarda erismek istedigimiz nesneye bir isaretci yada referans parametresini statik uye islevine gecmek yeterli olabiliyor.

Static uye islevlerin kullanildigi bazi yerler arasinda, nesne sayimi, sinif ozellikleri, global API islevlerinin wrap yapilmasi, bazi sinif kutuhaneleri aklima gelenler.