Tam Sürümünü Görmek İçin : saf sanal fonksiyon
http://www.gotw.ca/gotw/031.htm
More Exceptional C++ , konu : 27 kitaba sahip olmayanlar icin baglantidaki soruda anlamadigim bir nokta var ; varsayilan davranisin kabulunu zorlamakla ilgili kisimda.
Burada 'normal virtual' fonksiyonmus gib devre disi birakmayi secmezse durumlari neler? fonksiyonun saf sanal olmasi secmeme durumlarindan biriyse
class B {
public:
virtual void f() = 0;
};
void B::f() {
cout << true;
}
class D : public B {
public:
void f() {
}
};
int main(void)
{
D d;
d.f();
return 0;
}
bu kodda neden ekrana 1 yazilmiyor?
Bir de; eger D::f( ) de B::f( ) davranisi istiyorsam B::f( ) in saf sanal yapilmasi zorunlu mu( varsa normal sanal fonksiyonmus gibi devre disi birakilmadigi durumlar icin)? Yazida belirtildigi gibi turemis sinifin sessizce bu isi yapmamasi icin D nin yazarinin bunu belirtmesi B::f( ) sadece sanal iken de gecerli olmaz mi?
Buradan saf sanal fonksiyonun "2. Force Conscious Acceptance of Default Behaviour" basligindaki kullanim amacini anlamamis oldugum sonucu cikiyor da olabilir, tabii :)
Saygilar,cuneyt
myavuzselim
07/02/2005, 14:22
Bu kod o sayfadaki ornekle ayni degil:
class D : public B {
public:
void f() {
B::f();
}
};
(orada f(i) yazmis ama herhalde dalginlikla olmus)
Yani D::f() icerisinde ozellikle B::f() kullanilacagi belirtilmis.
acehreli
08/02/2005, 00:54
ceeyt,
Ust sinif, islevlerinden birisinin sanal olmasini istiyor ve ek olarak o islev icin varsayilan bir davranis belirliyor.
Dil kurallari geregi, eger alt sinif o sanal sinifi tekrar tanimlamazsa derleyici uyari vermez ve hersey yolunda gider:
class B
{
public:
virtual void f()
{
// varsayilan davranis
}
};
class D : public B
{
public:
// f()'in davranisi degistirilmiyor
// Acaba unutuldu mu yoksa boyle mi istedik?
};
Eger D'nin f'in davranisini degistirmemesinin hatali bir davranis mi yoksa istenen bir davranis mi oldugundan emin olmak istiyorsak, B::f'i saf sanal yapiyoruz ( '= 0' yazarak). Bu durumda D::f islevini mutlaka tanimlamamiz gerekmis oluyor.
Boylece eger varsayilan davranisi istiyorsak, D::f icinden onu acikca cagirabiliyoruz (B::f() diyerek), veya aslinda baska bir davranis tanimlayacaksak derleyicinin hata mesajina minnettar kalarak D::f'i istedigimiz baska bir bicimde tanimliyoruz.
En azindan benim anladigim bu... :)
Ali
class D : public B
{
public:
// f()'in davranisi degistirilmiyor
// Acaba unutuldu mu yoksa boyle mi istedik?
};
yani sorunlu olan durum f( ) in turemis sinifta tanimlanmamis olmasi durumu. Buna karsi onlem aliyoruz ve gercekte ne istedigimizi acikca ve fonksiyonu saf sanal yaparak zorla belirtiyoruz.
ilk bakista "ben kodumda boyle hatalar/unutkanliklar yapmam" dedirtebilecek birsey olsa da, su siralar ugrastigim, gereksiz yere derinlestirilmis ve karmasiklastirilmis dipsiz kuyu misali bir hiyerarsiyi gordukten sonra atlanmamasi gereken ayrintilardan biri olduguna inancim daha cok artti :) :)
tesekkurler...
Saf sanal fonksiyonların amacının programcıyı fonksiyonu yeniden düzenlemeye zorlamaktan daha çok kalıtımın miras verilen sınıflarda tekrar düzenlenmesini sağlamak olduğu düşünülebilir. bir sanal fonksiyonun önüne =0 koyarak aynı zamanda sınıfıda saf sanal sınıf haline getirmeyi hedeflemekteyiz. Bir saf sanal sınıf, kalıtımda sadece miras verilen sınıflar için temel sınıf olmaktan öteye gidemez. =0 kaldırıldığı zaman sınıfın kendiside miras verilen diğer sınıflar gibi kullanıma açık olur.
// Saf ana sınıf
class B {
public:
virtual void f() = 0;
};
void B::f() {
cout << "class B\n";
}
// Miras verilen D sınıfı.
class D : public B {
public:
virtual void f();
};
void D::f() {
B::f();
cout << "class D\n";
}
// Miras verilen ikinci sınıf: E sınıfı.
class E : public B {
public:
virtual void f();
};
void E::f() {
cout << "class E\n";
}
// Saf sanal olmayan D sınıfından türetilmiş F sınıfı
// f() fonksiyonu düzenlenmediği için D sınıfının f()'i çağrılacaktır.
class F : public D {
};
int main(void)
{
B * b = new D;
b->f();
b = new E;
b->f();
b = new F;
b->f();
return 0;
}
myss in belirttiği gibi sanal sınıfta bulunan saf sanal fonksiyonun miras verilen bir sınıfta çağrılabilmesi ancak B::f() in çağrılması ile mümkün olabilir. Aksi taktirde miras verilen sınıfın f() fonksiyonu hiçbir zaman sanal sınıfın f() fonksiyonunda ne var ne yok diye bakmayacaktır çünkü kendisinde zaten bir f() tanımlıdır.
acehreli
08/02/2005, 03:48
alpaes, sanirim ceeyt'in verdigi baglantidaki ikinci sorunun birinci yanitini acikliyorsunuz. (O baglanti ceeyt'in bahsettigi kitabin 27. maddesinin temelini olusturur.)
Eger isimiz "bir sanal fonksiyonun önüne =0 koyarak ayni zamanda sinifi da saf sanal sinif haline getirmeyi hedeflemek" ise, bunun icin bozucu islevi kullanmak daha uygun olabilir.
Herb Sutter'in More Exceptional C++'in 27. maddesinde de tekrarladigi "bozucu islev ya genel (public) ve sanal (virtual) olmalidir, ya da korumali (protected) ama sanal olmamalidir (non-virtual)" kuralina uyarsak; o zaman f() gibi herhangi bir islevi saf sanal yapmak yerine, zaten tanimlamis oldugumuz bozucu islevi saf sanal yapmak yeterli olur.
Ali
evet orası doğru ancak verilen linkte "varsayılan davranışın miras alınmasını zorlamak" diye çevirebileceğim 2. başlıkta yer alan f() fonksiyonun davranışı üzerinde durmuştum. miras verilen sınıflarda - programcı örnek koddaki gibi belirtmediği sürece- saf sınıfın sanal saf fonksiyonunu çağıramayacağını çünkü zorunlu olarak kendisinin bu saf sanal fonksiyonu düzenleme zorunluluğu bulunduğunu vurgulamak istedim. Aksi taktirde sizin belirtiğiniz şekilde sadece bozucuyu sanal ve saf yaparak f() fonksiyonunu işler hale getirirsek, o zaman D sınıfında f() fonksiyonunu tekrar düzenlememiz gerekmeyecektir ve bu da 2. madde deki sorunun özünü kaçırmamıza neden olabilir.
// Saf ana sınıf
class B {
public:
virtual void f();
virtual ~B()=0;
};
void B::f() {
cout << "class B\n";
}
B::~B() {
}
// Miras verilen D sınıfı.
class D : public B {
public:
// Artık bu fonksiyonu yeniden düzenleme zorunluluğu
// ortadan kalkmıştır.
// virtual void f();
virtual ~D() { }
};
int main(void)
{
B * b = new D;
b->f();
return 0;
}
Forum Yazılımı : vBulletin v3.6.8, Copyright ©2000-2008, Jelsoft Enterprises Ltd.