PDA

Tam Sürümünü Görmek İçin : spaydır men ile betmen in maskesi altında aynı yüz varsa nolur : virtual inheritance


sckz
29/06/2005, 19:53
spaydır men ile betmen in maskesi altında aynı yüz varsa nolur : virtual inheritance
#include <iostream>
using namespace std;

class A
{
public :
int a;
A()
{
a = 5;
cout << __FUNCSIG__ << endl;
}
};

class B : public A
{
public :
B()
{
a = 6;
cout << __FUNCSIG__ << endl;
}
};

class C : public A
{
public :
C()
{
a = 7;
cout << __FUNCSIG__ << endl;
}
};

class D : public B, public C
{
public :
D()
{
cout << __FUNCSIG__ << endl;
}
};


int main()
{
D d;
return 0;
}

Yukarıdaki kodda d nesnesi B ve C tipinde iki alt nesneye sahip… Dolayısıyla D nin yapılandırıcısı çağrılmadan önce B ve C nin yapılandırıcısı çağrılacak.. B sınıfından oluşturulacak nesneler de A tipinde bir alt nesneye sahip.. ve aynı şekilde önce A alt nesnesinin yapılandırıcısı çağrılacak..

Bu mantıkla önce D nin B tipindeki alt nesnesinin A tipindeki alt nesnesinin yapılandırıcısı, sonra B alt nesnesinin kendi yapılandırıcısı; Sonra D nin C tipindeki alt nesnesinin A tipindeki alt nesnesinin yapılandırıcısı, sonra C alt nesnesinin kendi yapılandırıcı çağrılacak.. Ve en sonunda D sınıfının yapılandırıcısı çağrılıp d nesnesi oluşturulmuş olacak..

Çıktı :

__thiscall A::A(void)
__thiscall B::B(void)
__thiscall A::A(void)
__thiscall C::C(void)
__thiscall D:: D(void)

Burada sorun yok.. Devam edelim…
Sonra B ve C sınıflarını A sınıfından virtual olarak türetirsek ve D yi de B ve C sınıflarından türettiğimizde, D sınıfının alt nesneleri olan B ve C sınıfına ait nesneler aynı A alt nesnesini kullanacağından çıktı:

__thiscall A::A(void)
__thiscall B::B(void)
__thiscall C::C(void)
__thiscall D:: D(void)

Olur.. yine sorun yok.. Her şey beklenildiği gibi (debugger kullanırsanız, local penceresinde d nesnesinin B ve C alt nesnesinin a üyesinin aynı degere(7) sahip oldugunu görebilirsiniz)..

Sanal temel sınıflar ın çoklu kalıtımla bağlantılı olduğunu biliyorum yalnız.. Ama B yi A dan normal olarak türetip, C yi virtual olarak türettiğimizde çıktı :

__thiscall A::A(void)
__thiscall A::A(void)
__thiscall B::B(void)
__thiscall C::C(void)
__thiscall D:: D(void)

Oluyo.. Da ? neden böle oluyo (bu birinci sorum)? (çünkü bu durumda B nin de bir C nin de bir A alt nesnesi var..)

Sorumun ikinci kısmı aslında birinci kısmının aynısı.. yani aslında ikinci soruya hiç gerek yok 8).. ben daha görkemli sorular sormak isterdim tabi ki ama kafama bunlar takıldı..
Şimdi C yi A dan normal olarak türetip, B yi sanal olarak türettiğimizde ise çıktı en baştaki gibi, yani :

__thiscall A::A(void)
__thiscall B::B(void)
__thiscall A::A(void)
__thiscall C::C(void)
__thiscall D:: D(void)

Oluyo… işte ben bunu da anlamadım ? dedim ya ikinci sorumla birincisi aynı.. yani neden anlamadım ? bir şeyleri yanlış mı biliyorum..

Pliz help mi..


Sabahi
30/06/2005, 05:25
http://msdn.microsoft.com/archive/?url=/archive/en-us/dnarvc/html/jangrayhood.asp

acehreli
01/07/2005, 02:25
Belki Sabahi'nin verdigi baglantida da anlatiliyordur ama, bir nesne kurulurken su sira izlenir:

1) Nesnenin virtual ust sinif ogeleri
2) Nesnenin virtual olmayan ust sinif ogeleri
3) Nesnenin icinde tanimli olan ogeleri, sinif taniminda siralandiklari sirada

Ayrica, virtual ust sinif ogesinin kurulmasinin en alt sinif tarafindan yapildigini da hatirlamak gerek. Yani virtual kalitim durumunda virtual ust siniflarin kurulmasi hep D tarafindan halledilir.

Ornegin; B ve C'nin ikisinin de virtual olarak turedigi durumda ikisinin de kurulmasi sirasinda A nesnesi kurulmaz, cunku o A nesneleri D'nin kurulmasi sirasinda D tarafindan zaten halledilmistir.


Ama B yi A dan normal olarak türetip, C yi virtual olarak türettigimizde çikti :

__thiscall A::A(void)
__thiscall A::A(void)
__thiscall B::B(void)
__thiscall C::C(void)
__thiscall D:: D(void)


O durumda D'nin iki tane A parcasi vardir: Biri B'den virtual olmadan gelen, oteki de C'den virtual olarak gelen. Yukaridaki aciklamaya gore, birinci A, D tarafindan kurulan ve virtual kalitim ile edinilen A'dir. Ikinci A ise B'nin kurulmasi sirasinda virtual olmayan kalitim ile gelen A'dir.

Bu arada, o durumda g++ bana soyle bir uyari veriyor:

warning: virtual base `A' inaccessible in `D' due to ambiguity

Yani D'nin icindeyken A ogesine karisiklik olmadan erisemeyiz cunku D'nin iki degisik A ogesi vardir.


Simdi C yi A dan normal olarak türetip, B yi sanal olarak türettigimizde ise çikti en bastaki gibi, yani :

__thiscall A::A(void)
__thiscall B::B(void)
__thiscall A::A(void)
__thiscall C::C(void)
__thiscall D:: D(void)


B sanal olarak turetildigi icin o kurulurken bir A kurulmaz. Ilk olarak kurulan A, yine D'nin kurulmasi sirasinda kurulan virtual A ogesidir.

Ondan sonra D'nin birinci ust sinifi olan B kuruluyor.

Ondan sonra D'nin ikinci ust sinifi olan C kuruluyor. O da once kendi ust sinifi olan A'yi kuruyor.

Ali

ceeyt
01/07/2005, 03:19
"deadly diamond of death" :)

Herb Sutter'in kitaplarindan biriydi sanirim, bu tasarima galiba boyle bir isim verilmisti. Gerci baska kaynaklarda da ayni ismi duymustum.