Thread overview
Virtual ve Interface Sınıflar
Jun 04, 2013
Salih Dinçer
Jun 04, 2013
Salih Dinçer
Jun 05, 2013
Salih Dinçer
Jun 05, 2013
Salih Dinçer
June 04, 2013

Merhaba,

Bugün çok ilginç bir konuya girdik. Başlangıcı şurada alevlenmişti: http://ddili.org/forum/post/9470

Konuyu assembly kodlarını inceleyerek devam ettirmek istiyorum. Ama çok vaktim yok ve hepsini hemen şimdi aktaramayabilirim. Elimden geldiğince çok bilgi aktarmak istiyorum bakalım ne yapabiliriz...:)

Önce vtbl denen şey nedir ona bakalım ve geriye doğru gidelim:
Alıntı:

>

_D9interface4Kedi6__vtblZ:
dd offset FLAT:_D9interface4Kedi7__ClassZ@SYM32
dd offset FLAT:_D6object6Object8toStringMFZAya@SYM32
dd offset FLAT:_D6object6Object6toHashMFNbNeZk@SYM32
dd offset FLAT:_D6object6Object5opCmpMFC6ObjectZi@SYM32
dd offset FLAT:_D6object6Object8opEqualsMFC6ObjectZb@SYM32
dd offset FLAT:_D6object6Object8opEqualsMFC6ObjectC6ObjectZb@SYM32
dd offset FLAT:_D9interface4Kedi11sesÇıkartMFZv@SYM32
db 068h,061h,076h,000h ;hav.

İşte böyle bir şey ama örneğimizdeki Köpek için de bir şey değişmiyor. Sadece Kedi yazan yerlerde Köpek yazıyor; hepsi bu kadar.Tamamen aynı gibi görünüyor ve aslında bu bir durağan (static) veritabanı. Sınıfların override edilebilecek gizli işlevlerini ve 1 adet kendi işlevimizi açıkca görmekteyiz.

Dip Not: Kedi sınıfına ait VTBL'de neden "hav" dizgesi tanımlanmış bilmiyorum. Bu konuda çok karışık şeyler var ama anlayacağız. Bu arada _D9interface, aslında benim dosya ismimden (interace.d) geliyor. Oradaki interface sınıfı ile alakalı değildir.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

June 04, 2013

Devam edelim...

Bizim bir de asıl icraatın olduğu sesÇıkart() isminde, neredeyse birbirinin aynısı iki işlevimiz var. Bunların virgülüne bile dokunmadan ve iki parça halinde aşağıda paylaştım. En önemli saçmalık (!) köpek içinde kedi ile ilgili şeylerin yığına atılma ihtimalinin olması. Hadi orada assert() olayı birbirinin zıttı olacak şekilde icra edilmesi gerekiyor ise, peki kedi içinde köpek ile ilgili şey niye yok? Burada ilginç bir şey var ama incelemeye engel değil. Sadece her iki işlevin ayrı ayrı ama VTBL'daki dizgeye ulaşabilecek şekilde olduğunu (orada da ters aslında, köpekde "miyav", kedide "hav" var!) görmekteyiz:

Alıntı:

>

.text._D9interface4Kedi11sesÇıkartMFZv segment
assume CS:.text._D9interface4Kedi11sesÇıkartMFZv
_D9interface4Kedi11sesÇıkartMFZv:
push EBP
mov EBP,ESP
sub ESP,4
test EAX,EAX
jne L29
push 0Ah
push dword ptr _TMP1@SYM32[012h]
push dword ptr _TMP1@SYM32[014h]
push dword ptr _D9interface4'Kedi'6__initZ@SYM32[06h]
push dword ptr _D9interface4'Kedi'6__initZ@SYM32[08h]
call _d_assert_msg@PC32
L29: call _D9invariant12_d_invariantFC6ObjectZv@PC32
push dword ptr _D9interface4'Kedi'6__vtblZ@SYM32[04h]
push dword ptr _D9interface4'Kedi'6__vtblZ@SYM32[06h]
call _D3std5stdio16__T7writelnTAyaZ7writelnFAyaZv@PC32
leave
ret
nop
nop
nop
_TMP4:
sub EAX,8
jmp L100000000
.text._D9interface4Kedi11sesÇıkartMFZv ends
Alıntı:

Alıntı:

>

.text._D9interface6Köpek11sesÇıkartMFZv segment
assume CS:.text._D9interface6Köpek11sesÇıkartMFZv
_D9interface6Köpek11sesÇıkartMFZv:
push EBP
mov EBP,ESP
sub ESP,4
test EAX,EAX
jne L29
push 012h
push dword ptr _TMP1@SYM32[012h]
push dword ptr _TMP1@SYM32[014h]
push dword ptr _D9interface4'Kedi'6__initZ@SYM32[06h]
push dword ptr _D9interface4'Kedi'6__initZ@SYM32[08h]
call _d_assert_msg@PC32
L29: call _D9invariant12_d_invariantFC6ObjectZv@PC32
push dword ptr _D9interface6'Köpek'6__vtblZ@SYM32[04h]
push dword ptr _D9interface6'Köpek'6__vtblZ@SYM32[06h]
call _D3std5stdio16__T7writelnTAyaZ7writelnFAyaZv@PC32
leave
ret
nop
nop
nop
_TMP7:
sub EAX,8
jmp L100000000
.text._D9interface6Köpek11sesÇıkartMFZv ends_TMP2:
db 009h,000h,000h,000h ;....
dd offset FLAT:_D9interface6Köpek6__initZ[01Ch]@SYM32
db 06dh,069h,079h,061h,076h,000h,000h,000h ;miyav...
.text._D9interface3fooFC9interface6HayvanZv segment

Düzeltme...

Nedense "miyav" dizgesi _TMP2 isminde başka bir table'da rastladım. Bunun böyle olmaması gerekiyordu. Orada değil de ilk iletimdeki bölümde olmalıydı. Belki assembly kodunu üreten yazılım saçmalamış olabilir. İşte saçmalığın kanıtı!

Alıntı:

>

_TMP2:
db 009h,000h,000h,000h ;....
dd offset FLAT:_D9interface6Köpek6__initZ[01Ch]@SYM32
db 06dh,069h,079h,061h,076h,000h,000h,000h ;miyav...

Neyse konumuz bu değil zaten, olaya son noktayı koyalım. İşler ilginçleşecek...:)

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

June 04, 2013

vtbl, NYP dillerinde derleyecilerin çok kullandıkları bir çokşekillilik yöntemidir. Aslında çok basit olduğu için assembly kodlarına girmeye hiç gerek yok. Ayrıca internette kesin anlatılıyordur.

C dilinde struct'ların üye işlevleri yoktur. Aşağıdaki bir D programı olduğu halde C'de nasıl çokşekillilik gerçekleştirilebileceğini göstermek için kendimi kısıtlayacağım ve aşağıdaki struct'lara üye işlev eklemeyeceğim:

import std.stdio;

// 'interface' veya üst sınıfın eşdeğeri
struct Hayvan
{
   Hayvan_vtbl * vtbl;
   void * asılHayvan;
}

// Üye işlev kullanmadığım için ismini Hayvan_ ile başlatıyorum
void Hayvan_sesÇıkart(Hayvan * this_)
{
   // Asıl hangi hayvan olduğunu bilmeden ses çıkartma işlemini
   // çağıracağız. vtbl üzerinden zıplayınca orada hangi işlev göstergesi
   // varsa o çağrılır.
   this_.vtbl.sesİşlevi(this_);
}

// Üye işlev kullanmadığım için ismini Hayvan_ ile başlatıyorum
void Hayvan_yürü(Hayvan * this_, size_t mesafe)
{
   // Yukarıdaki gibi...
   this_.vtbl.yürümeİşlevi(this_, mesafe);
}

// Sen çıkartma ve yürüme işlevleri için işlev gösterge türleri
alias Sesİşlevi = void function(Hayvan * this_);
alias Yürümeİşlevi = void function(Hayvan * this_, size_t mesafe);

// Hayvan vtbl'da yalnızca iki aden virtual işlev var
struct Hayvan_vtbl
{
   Sesİşlevi sesİşlevi;
   Yürümeİşlevi yürümeİşlevi;
}

struct Kedi
{
   string renk;
}

// Kedi'ye özgü ses çıkartma işlemi. Dikkat ederseniz işe Hayvan ile
// başlıyoruz çünkü programcılar Hayvan arayüzü ile kullanacaklar
void Kedi_sesÇıkart(Hayvan * this_)
{
   // Bu tür dönüşümü NYP'de derleyici tarafından otomatik olarak halledilir
   auto kedi = cast(Kedi*)(this_.asılHayvan);

   writefln("ben bir %s kediyim: miyav", kedi.renk);
}

// Kedi'ye özgü yürüme işlemi.
void Kedi_yürü(Hayvan * this_, size_t mesafe)
{
   // Bu tür dönüşümü NYP'de derleyici tarafından otomatik olarak halledilir
   auto kedi = cast(Kedi*)(this_.asılHayvan);

   writef("ben bir %s kediyim:", kedi.renk);

   foreach (i; 0 .. mesafe) {
       write(" tıpır" );
   }

   writeln();
}

// Kedi türünün virtual işlev tablosu. Bu da derleyici tarafından otomatik
// olarak oluşturulur. Bundan bir adet vardır.
auto Kedi_vtbl = Hayvan_vtbl(&Kedi_sesÇıkart, &Kedi_yürü);

// NYP'deki kurucu işlev. Dikkat ederseniz Kedi oluşturduğu halde arayüz olan
// Hayvan döndürüyor. Böylece çeşitli hayvandan oluşan topluluklar
// oluşturabileceğiz. Yani, çokşekillikten yararlanmış olacağız.
Hayvan Kedi_kur(string renk)
{
   // Hayvanın Kedi ile ilgili olan bölümü
   auto kedi = new Kedi();
   kedi.renk = renk;

   // Kedi davranışını (üye işlevlerini) ve verilerini (üye değişkenlerini)
   // bir araya getiren genel Hayvan nesnesi.
   auto hayvan = Hayvan(&Kedi_vtbl, kedi);
   return hayvan;
}

void main()
{
   // Başka Hayvan olsaydı onu da bu dilime yerleştirebilirdik.
   Hayvan[] hayvanlar = [ Kedi_kur("sarı"), Kedi_kur("mavi") ];

   foreach (i, hayvan; hayvanlar) {
       Hayvan_sesÇıkart(&hayvan);

       auto mesafe = i * 2 + 1;
       Hayvan_yürü(&hayvan, mesafe);
   }
}

NYP derleyicisi perde arkasında yukarıdakine çok benzer şeyler yapar. Yukarıdaki, C'de NYP gerçekleştirmenin bir yoludur.

Özetle, vtbl, bir türün kendi davranışlarını belirleyen işlevleri bir araya getiren bir işlev tablosudur. Her NYP nesnesinde bir adet vtbl bulunur ve böylece onun nasıl davranacağı çalışma zamanında belirlenir.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

June 04, 2013

Belki açık olmamıştır diye: Bu yazdığım yapılar ve normal işlevler Salih'in bağlantısını verdiği konuda konuştuğumuz Hayvan sıradüzenine karşılık derleyicinin perde arkasında yazdığı yapılar ve işlevlerdir. (Tam aynı olmasa da çok yakın kavramlardır.)

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

June 05, 2013

Bu konuya devam etmeden evvel biraz bilgilerimi tazeliyorum. Çünkü alternatif örnekleri de deneyip karşılaştırmalıydım. Çok yakında örneğe son demi vuracağız...:)

Ama önce küçük bir gereksiz hatırlatma yapmalıyım...

Hocam, yakın bir zaman önce, D.ershane'deki güncellemeyi başka başlıkta ve aşağıdaki gibi bir iletiyle bizi bilgilendirmiştin. Öncelikle çok teşekkür ediyorum çünkü inanılmaz yararı oluyor bu tür şeylerin...

Alıntı (acehreli:1370320421):

>

Bu konuyu "İşlev Göstergeleri, İsimsiz İşlevler, ve Temsilciler" bölümüne "delegate parametreli toString" başlığı altında ekledim:

http://ddili.org/ders/d/kapamalar.html

Bu bölümü, her ne kadar okusam da baştan sona tekrar etmeye başladım. Oradaki Çalışan örneği ilgimi çekti ve konuyla bağlantılı olabileceğini düşünmekteyim:

interface Çalışan
{
   double ücretHesabı();
}
   :    :    :

Gerçi burada işaretçiler (gösterge) için OOP çözümü nakledilmiş ve kısa geçilmiş. Belki doğrusu budur, bilemiyorum. Yani zaten arayüzlerin bir başlığı var ve kafa karıştırmamak en uygunudur. Yine de burada tartıştığımız mevzuya azıcık hatırlatmak iyi olabilir mi?

Teşekkürler...

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

June 06, 2013

Evet, ek öneriyorum ama hacmini arttıracak derecede değil. Örneğin tek cümle ile VTBL kullanıldığına değinilebilir. Aynı şekilde diğer bölüme bağlantı verme fikri de gayet basit ve net çözüm bence.

Performans olayına gelince; henüz bir netice elde edemedik. İstersen bunu kesinleştirdiğimizde dile getirelim. Çünkü bahsi geçen derste, temsilciler ve işaretçiler işlenerek OOP'daki benzerinden bahsediliyor. Gerçi işaretçi her zaman hızlıdır ya...:)

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

June 05, 2013

Alıntı (Salih Dinçer):

>

Gerçi burada işaretçiler (gösterge) için OOP çözümü nakledilmiş ve kısa geçilmiş. Belki doğrusu budur, bilemiyorum. Yani zaten arayüzlerin bir başlığı var ve kafa karıştırmamak en uygunudur.

Evet, öyle düşünmüştüm. Belki "şurada anlatıldığı gibi" diye bir bağlantı da vermeliydim.

Alıntı:

>

Yine de burada tartıştığımız mevzuya azıcık hatırlatmak iyi olabilir mi?

O cümleni anlayamadım. :) Bölüme bir ek mi öneriyorsun yoksa bu konuyu burada daha açalım mı diyorsun?

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]