Jump to page: 1 2
Thread overview
İç sınıflar
May 21, 2011
mert
May 22, 2011
mert
May 22, 2011
mert
May 22, 2011
mert
May 22, 2011
erdem
May 22, 2011
mert
July 13, 2010

Tüh ben bu konuda sizden daha bilgiliymişim fark kapanmış :-D

Tdpl'de nested'i görmüştüm sonra digitalmars'ın sitesinden öğrendim azıcık bir şey. Çevirecektim iç içe sınıflar diye(Metin başlığını bile hazırladım.) sonra boşver Ali Bey bir gün çevirir dedim :-)

Herşey şurada http://d-programming-language.org/class.html Nested Classes başlığının altında anlatılıyor.

Daha önce hiç bir programlamada nesnelere kadar gelmediğim için(php'de geldim ama az. ) bana çok doğal geliyor.

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

July 13, 2010

Yeni bir şey öğrendim... :) D'nin sınıf içi sınıfları C++'dan daha farklıymış:

class DışSınıf
{
   int işlemSayacı;

   class Görevli
   {
       void çalış()
       {
           ++işlemSayacı;
           // ... asıl işlemler ...
       }
   }

   void bilgiVer()
   {
       writeln(işlemSayacı, " işlem yapıldı");
   }
}

Dikkat ederseniz, iç sınıf dış sınıfın bir üyesini kullanabiliyor. Yani, iç sınıftan bir nesne oluşturulabilmesi için, öncelikle bir dış sınıf nesnesi gerekiyor.

Bu, C++'da böyle değildir; iç sınıf açısından bakıldığında, dış sınıf yalnızca bir isim alanı belirler. Örneğin içteki sınıfın uzun ismi DisSinif::IcSinif'tır.

D'de ise iç sınıf, bir dış nesneye bağlı oluyor ve ancak o nesne tarafından oluşturulabiliyor:

import std.stdio;

void main()
{
   auto dış = new DışSınıf;

   auto görevli1 = dış.new Görevli;
   auto görevli2 = dış.new Görevli;

   görevli1.çalış();
   görevli1.çalış();
   görevli2.çalış();

   dış.bilgiVer();
}

Oradaki 'dış.new' kullanımından haberim yoktu! :)

O programda iki tane iç nesne oluşturuluyor ve ikisi de tek dış nesneyi kullanıyorlar. Sonuçta program "3 işlem yapıldı" yazıyor.

C++'daki gibi olması istenirse, iç sınıfın başına 'static' yazılıyor:

   static class Görevli

Tabii o zaman dış nesneye bağlantı diye bir kavram olmuyor. Yani '++işlemSayacı;' çalışamaz.

Ali

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

May 21, 2011

Peki, içiçe sınıfları nerelerde kullanabiliriz bana örnekleyebilir misiniz?

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

May 22, 2011

Öncelikle açıklamalar ve örneklemeler için çok teşekkür ederim. Oldukça yararlı olanaklarmış bunlar. D dilinde öğrenecek şey bitmiyor hiç :-)

İç sınıf hem daha kısa kod yazılmasını hem de türetme kolaylığını beraberinde getiriyormuş. Yine de programlama yaparken programcının izleyeceği yol kendi tercihine bırakılıyor; D'ilin en sevdiğim tarafı da bu. Çoğu durumda "bu yöntemi uygulayacaksınız!" dayatması yok bu d'ilin.

(5 numaralı gönderiniz için not: İç sınıfın kaydet işlevini override ile baskılamayı unutmuşsunuz sanırım.)

İşlev içi isimsiz sınıflar da kullanışlı bir özellikmiş. Sizdeki gibi bendeki çıktısı da aynı:

[0, -1, -2]
// eksi giriş değerlerim [1, 2, 3]
tür ismi: __anonclass16

Burada bir sınıf olmayan sınıf demek mi istiyor? Ya da işlev içi sınıfı bu türden mi işaretliyor acaba; __anonclass16 ?

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

May 21, 2011

Bu olanağın ne olduğunu düşünelim. Burada önemli olan, başka sınıfın içinde sınıf oluşturmak değil. O kadarı örneğin C++'ta da var. Burada iki nokta ilginç:

  • İçtekini oluşturabilmek için dıştakinden bir nesne şart. Buna bakarak içtekinin dıştakinin bir yardımcısı olduğunu düşünebiliriz.

  • Yine aynı nedenden, içteki dıştakinin bütün üyelerine isimle erişebiliyor. Açıkça olarak dıştaki.üye yazmak gerekmiyor.

Benim aklıma güzel bir örnek gelmiyor ama içteki sınıfın dıştaki ile çok yakın ilişkisi olduğu doğru. İçteki, kendi işi sırasında dıştakinin üyelerine erişecek; işi onları içeriyor...

Bu olanak tabii ki şart değil. En azından örneğin C++'ta yok ve eksikliği büyük bir sorun oluşturmuyor. Böyle bir olanak olmasaydı, şöyle gerçekleştirirdik:

import std.stdio;

class Sınıf
{
   int i;
}

class İşçi
{
   Sınıf nesne;

   /* Üzerinde çalışacağı nesneyi kurucuda almak zorunda
    * kalırdı */
   this(Sınıf nesne)
   {
       this.nesne = nesne;
   }

   void işle()
   {
       /* Dıştakinin üyelerine nokta ile erişmek zorunda
        * kalırdı */
       writeln(nesne.i);
   }
}

void main()
{
   auto nesne = new Sınıf;

   /* Hangi nesneyle işleyeceğini kurucuda bildiriyoruz */
   auto işçi = new İşçi(nesne);
   işçi.işle();
}

Öyle de olurdu işte ama bu olanak sayesinde daha kısa oluyor:

import std.stdio;

class Sınıf
{
   int i;

   class İşçi
   {
       /* Burada 'nesne' isminde bir Sınıf değişkeni tutmak
        * gerekmiyor; dıştakine burada otomatik olarak
        * 'this.outer' diye erişilebiliyor. */

       /* Kurucu işlev yazmaya gerek yok */

       void işle()
       {
           /* Dıştakinin üyelerine nokta ile erişmek zorunda
            * değiliz */
           writeln(i);

           /* Bunu yeni hatırladım: i'nin içtekinin bir
            * üyesiyle isim benzerliği olan durumda
            * 'this.outer' diye belirlemek gerekebilir */

           writeln(this.outer.i);   // üsttekinin aynısı
       }
   }
}

void main()
{
   auto nesne = new Sınıf;

   /* Hangi nesneyle işleyeceği kurarken otomatik olarak
    * anlaşılıyor */
   auto işçi = nesne.new İşçi;
   işçi.işle();
}

O kısaltmalardan başka neden göremiyorum.

Örnek olarak da aklıma C++'ın erişicileri geliyor. Onların eşdeğerleri D aralıkları olduğu için, bir topluluğun aralıkları iç sınıf olarak tasarlanabilir:

(Şimdilik bu kadar. TDPL'de çoklu kalıtım (multiple subtyping) konusunda yardımı olduğu söyleniyor. (Acaba 'alias this' dmd 2.053'te ne durumda? Çok hatalı bir olanaktı.))

Ali

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

May 21, 2011

(Sonradan not: Bu yazdıklarımın yukarıdaki örnekten farkı yok aslında.)

TDPL'de 'alias this' ve iç sınıf olanaklarının çoklu kalıtım için nasıl bir araya getirildikleri anlatılıyor. Özetleyeceğim.

Şekil isimli bir üst sınıftan türetmek istediğimiz kendi şekil sınıfımız var. Ek olarak, bu şekil sınıfının bir veritabanına kaydedilebilmesi için, veri tabanı kütüphanesinin DbNesnesi isimli sınıfından türetilmiş olması gerekiyor.

İşte o bir sorun: iki sınıftan türetemeyiz:

class Şekil
{}

class DbNesnesi
{
   abstract void kaydet();
}

class KayıtlıŞekil : Şekil, DbNesnesi  // <-- DERLEME HATASI
{}

Bir çözüm, DbNesnesi'ni bir üye yapmak ve kendimizi 'alias this' ile DbNesnesi yerine de geçirtmek. (Gerektiğinde çoklu kalıtım D'de böyle sağlanıyor.)

class KayıtlıŞekil : Şekil
{
   DbNesnesi kayıt;

   alias kayıt this;  // bunun sayesinde bir DbNesnesi olarak
                      // da kullanılabiliyoruz (D'nin çoklu
                      // kalıtımı bu)
}

Ama o kadarı yeterli değil, çünkü DbNesnesi soyut bir sınıftır. Normalde Şekil'leri kaydetmeyi bilen bir sınıfı DbNesnesi'nden türetmek isteriz:

/* Şekil kaydetmeyi bu sınıf bilir */
class ŞekilDbNesnesi : DbNesnesi
{
   Şekil şekil;

   /* Daha önce söylediğim gibi, Şekil'in bu sınıfın
    * kurucusuna verilmesi gerekir */
   this(Şekil şekil)
   {
       this.şekil = şekil;
   }

   void kaydet()
   {
       writeln("Şekil kaydediliyor");
   }
}

O yüzden KayıtlıŞekil içinde aslında somut olarak ondan bir nesne oluşturmak gerekir:

class KayıtlıŞekil : Şekil
{
   DbNesnesi kayıt;

   alias kayıt this;

   this()
   {
       /* Somut ŞekilDbNesnesi'ne this ile kendimizi
        * tanıtıyoruz */
       this.kayıt = new ŞekilDbNesnesi(this);
   }
}

Bir önceki yazdığımdaki gibi, ŞekilDbNesnesi'ni bir iç sınıf yaptığımızda işler daha kolay hale geliyor:

class KayıtlıŞekil : Şekil
{
   DbNesnesi kayıt;

   alias kayıt this;

   /* Dış sınıfın bütün üyeleri bu sınıfa açık */
   class ŞekilDbNesnesi : DbNesnesi
   {
       void kaydet()
       {
           writeln("Şekil kaydediliyor");
       }
   }

   this()
   {
       this.kayıt = this.new ŞekilDbNesnesi;
   }
}

Sonuçta farklı şeyler söylenmedi. Böyle daha kolay oluyor işte... :)

Bütün kod şöyle:

import std.stdio;

class Şekil
{}

class DbNesnesi
{
   abstract void kaydet();
}

class KayıtlıŞekil : Şekil
{
   DbNesnesi kayıt;

   alias kayıt this;

   /* Dış sınıfın bütün üyeleri bu sınıfa açık */
   class ŞekilDbNesnesi : DbNesnesi
   {
       void kaydet()
       {
           writeln("Şekil kaydediliyor");
       }
   }

   this()
   {
       this.kayıt = this.new ŞekilDbNesnesi;
   }
}

void main()
{
   auto şekil = new KayıtlıŞekil;

   dbİşlevi(şekil);
}

void dbİşlevi(DbNesnesi nesne)
{
   nesne.kaydet();
}

Ali

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

May 21, 2011

Son olarak sınıf içi sınıfların kardeşi olan işlev içi isimsiz sınıfları göstereceğim.

Hem tam konu üstündeyiz, hem de Andrei geçende isimsiz iç sınıfların aralık algoritmalarında yararlı olabildiklerini düşündüğünü yazmıştı.

Başka Aralık Olanakları dersinde (http://ddili.org/ders/d/araliklar_baska.html) Eksili diye bir aralık türü ve eksili() diye bir kolaylık işlevi tanımlamıştım. Çok kısa olarak gösteriyorum:

import std.stdio;
import std.array;

struct Eksili(T)
{
   T aralık;

   this (T aralık)
   {
       this.aralık = aralık;
   }

   @property bool empty()
   {
       return aralık.empty;
   }

   @property auto front()
   {
       return -aralık.front;
   }

   void popFront()
   {
       aralık.popFront();
   }
}

Eksili!T eksili(T)(T aralık)
{
   return Eksili!T(aralık);
}

void main()
{
   auto aralık = [ 0, 1, 2 ];
   writeln(eksili(aralık));
}

Bir zararı olmasa da, Eksili diye bir türü kullanıcıların bilmeleri gerekmiyor. Kullanıcıların eksili() işlevini çağırmaları yetiyor. Eksili ise bu kütüphaneni işini halleden yardımcı bir tür...

İşte o Eksili'yi işlev içinde isimsiz bir sınıf olarak da tanımlayabiliriz. O zaman işlevin dönüş türünün de 'auto' olması gerekiyor, çünkü içteki sınıfın ismi bile yok. :)

import std.stdio;
import std.array;

auto eksili(T)(T aralık_parametre)
{
   return new class
   {
       T aralık;

       this ()
       {
           this.aralık = aralık_parametre;
       }

       @property bool empty()
       {
           return aralık.empty;
       }

       @property auto front()
       {
           return -aralık.front;
       }

       void popFront()
       {
           aralık.popFront();
       }
   };
}

void main()
{
   auto aralık = [ 0, 1, 2 ];
   writeln(eksili(aralık));

   writeln("tür ismi: ", typeof(eksili(aralık)).stringof);
}

Orada return satırında hem isimsiz bir sınıf tanımlanıyor hem de new ile onun bir nesnesi oluşturuluyor. Ve tabii o nesne döndürülüyor da... Böylece artık programda Eksili diye bir sınıf bulunmuyor; onun yerine ismi çok garip bir sınıf var. :p Programın son satırında yazdırınca bendeki çıktısı şöyle:

'[0, -1, -2]
tür ismi: __anonclass16
'

Ali

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

May 22, 2011

Alıntı:

>

Derleyicinin hata vermesi gerekirdi ama Linux'ta dmd 2.053 hata vermiyor.

32 bit 2.053 kullanıyor olmalısınız. 64 bit hata veriyor çünkü:-)

Alıntı:

>

__anonclass herhalde "isimsiz sınıf" anlamındaki "anonymous class"tan geliyor. Sonundaki numara da derleyicinin o noktaya kadar kaç tane görmüş olduğunu gösteriyor herhalde. Eklenmiş olan modüllerde de veya iç olanaklarda da böyle sınıflar olsa gerek.

Bu konuda açığa kavuştu. Teşekkürlerimle

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

May 22, 2011
/*override*/   void kaydet()
       {
           writeln("Şekil kaydediliyor");
       }

Çıktısı:  deneme1.d(20): Warning: overrides base class function deneme1.DbNesnesi.kaydet, but is not marked with 'override'

linux 2.053 64 bit override kullanmadan aldığım hata. Derleme seçeneklerinizden olabilir mi acaba?

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

May 22, 2011

Denemedim ama benim hatırladığım -w parametresini vermeden hata vermiyordu.

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

« First   ‹ Prev
1 2