PDA

Tam Sürümünü Görmek İçin : Oge islev gostergeleri


acehreli
03/06/2007, 21:24
Bir arkadas oge islev gostergeleri (member function pointers) ile bilgi istemisti. Yanitini buraya yaziyorum.

Oncelikle, ben oge islev gostergelerini C++'in gunluk kullanimdan uzak, nadiren ihtiyac duyulan bir olanagi olarak goruyorum. Ben cok az kullandim...

Islev gostergeleri kullanarak nasil aslinda hangi islevi cagirdigimizi bilmeden is yapabiliyorsak (ornegin: qsort'un aldigi karsilastirma islevi), oge islev gostergeleri kullanarak da bir nesnenin aslinda hangi islevini cagirdigimizi bilmeden islem yapabiliriz.

Oge islev gostergesi olusturmak cok kolaydir. Islev gostergelerinde oldugu gibi, basina bir & karakteri koyariz:

&Hayvan::Konus

diyince, Hayvan tUrUnun Konus adli ogesini gosteren bir oge islev gostergesi olusur. Burasi kolay... Asil karisik yazim, bu turu tanimlarken ve cagirirken olusur. :)

Once isinma amaciyla iki satir:


// nesne'nin ogeIslev'in gosterdigin islevi cagriliyor
(nesne.*ogeIslev)(1.1);

// Ayni sekilde ama elimizde bir nesne degil, bir gosterge var
(nesneGostergesi->*ogeIslev)(2.2)


Bu ornekte, elindeki Hayvan'in hangi oge islevini cagirdigini bilmeden islem yapan islevler var (HayvanlaBirIsYap ve HayvanlaBirIsYapGostergeyle):


#include <iostream>

using std::cout;

class Hayvan
{
public:

virtual ~Hayvan()
{}

virtual int Konus(double saniye) = 0;
virtual int Yuru(double metre) = 0;
};

/*
* Bu islevde ne tUr bir hayvanla ilgilendigimizi bilmeden onun Konus
* islevini cagiriyoruz. Yani Hayvan bilinmiyor ama oge islev
* biliniyor.
*/
void HayvanKonustur(Hayvan & hayvan)
{
hayvan.Konus(1.2);
}

/*
* Ayni sekilde, yine Hayvan bilinmiyor ama oge islev Yuru olarak
* biliniyor.
*/
void HayvanYurut(Hayvan & hayvan)
{
hayvan.Yuru(3.4);
}

/*
* Kedi: Hayvan arayuzunu gerceklestiren bir sinif.
*/
class Kedi : public Hayvan
{
public:

virtual int Konus(double sure) {
cout << sure << " saniye miyav diyorum\n";
return 11;
}

virtual int Yuru(double metre) {
cout << metre << " metre kedi gibi yuruyorum\n";
return 22;
}
};

/*
* Hayvan'in baska bir gerceklestirmesi
*/
class Kopek : public Hayvan
{
public:

virtual int Konus(double sure) {
cout << sure << " saniye hav diyorum\n";
return 33;
}

virtual int Yuru(double metre) {
cout << metre << " metre kopek gibi yuruyorum\n";
return 44;
}
};

/*
* Hayvan'in int dOndUren ve double alan islevlerini gosterebilen bir
* "oge islev gostergesi tUrU" tanimliyorum. Onun adini OgeIslev
* koyuyorum.
*/
typedef int (Hayvan::*OgeIslev)(double);

/*
* Simdi bu islev hem ne tur hayvanla ilgilendigini bilmiyor hem de o
* hayvanin hangi oge islevini cagirdigini bilmiyor.
*/
void HayvanlaBirIsYap(Hayvan & hayvan, OgeIslev islev)
{
cout << "Bir hayvanin bir islevini cagiriyorum\n";
const int sonuc = (hayvan.*islev)(5.6);
cout << "Donus degeri: " << sonuc << '\n';
}

/*
* Bu da benzer ama Hayvan referansi yoluyla degil, Hayvan
* gostergesiyle cagiriyor.
*/
void HayvanlaBirIsYapGostergeyle(Hayvan * hayvan, OgeIslev islev)
{
cout << "Hangi islevi kullandigimi bilmiyorum ama islevi\n"
<< " Hayvan gostergesi yoluyla cagiriyorum\n";
(hayvan->*islev)(7.8);
}

int main()
{
Kedi kedi;

HayvanlaBirIsYap(kedi, &Hayvan::Konus);

HayvanlaBirIsYapGostergeyle(&kedi, &Hayvan::Yuru);
}

Oge islev gostergelerini, genellikle onlari once saklayip, daha sonraki bir zamanda islem yapmak icin kullanabiliriz. Bu da icinde oge islev barindiran bir sinif nesnelerini (Hesaplayici) bir vector'de toplayan ve sonra onlarla islemler yapan bir ornek:


#include <iostream>
#include <vector>

using std::cout;

class BirDeger
{
double deger_;

public:

explicit BirDeger(double deger)
:
deger_(deger)
{}

double BirHesap(double yeniDeger) const
{
cout << deger_ << " x " << yeniDeger << '\n';
return deger_ * yeniDeger;
}

double BaskaHesap(double yeniDeger) const
{
cout << deger_ << " / " << yeniDeger << '\n';
return deger_ / yeniDeger;
}
};

class Hesaplayici
{
public:

/*
* Bize verilecek olan oge islevin tUrUnu belirliyoruz. Burada o
* oge islevin 'const' bir islev oldugunu da soyledim.
*/
typedef double (BirDeger::*HesapIslevi)(double) const;

private:

// Aklimizda tutacagimiz oge islev
HesapIslevi hesapIslevi_;

// O islevi cagirirken kullanacagimiz bir deger
double hesaptaKullanilacakDeger_;

public:

Hesaplayici(HesapIslevi hesapIslevi, double hesaptaKullanilacakDeger)
:
hesapIslevi_(hesapIslevi),
hesaptaKullanilacakDeger_(hesaptaKullanilacakDeger )
{}

void Hesapla(const BirDeger & birDeger)
{
cout << "Aklimda tuttugum islevi bana verilen nesneye uyguluyorum\n";

const double sonuc
= (birDeger.*hesapIslevi_)(hesaptaKullanilacakDeger_ );

cout << "Sonuc: " << sonuc << '\n';
}
};

int main()
{
/*
* Daha sonradan hesaplanmasi gereken hesap islemlerini bir
* vector'de biriktiriyorum.
*/
std::vector<Hesaplayici> hesapIslemleri;
hesapIslemleri.push_back(Hesaplayici(&BirDeger::BirHesap, 7.77));
hesapIslemleri.push_back(Hesaplayici(&BirDeger::BaskaHesap, 8.88));

// Elimde hesap isinde kullanilacak bir deger var
BirDeger deger(1.2345);

/*
* Programda daha sonraki bir noktada butun o hesap islemlerini
* herhangi bir nesneye uygulayabilirim:
*/
hesapIslemleri[0].Hesapla(deger);
hesapIslemleri[1].Hesapla(deger);
// vs.
}


Ali