Selamlar,
Volkan Uzun "Türden bağımsız bir toplama algoritması" yazısında eksik bıraktığım bazı konulara değinmiş. Burada devam ediyorum...
--- volkan <...> wrote:
> selamlar,
> ceviz.netteki yazıyı okudum. stl konusuna oldukca uzak biri
> olarak kafama bir soru takıldı.
> aslında sorunun pek stl le alakası da yok sanırım
Evet yok, şablonlarla ilgili genel bir soru.
> şimdi türden bağımsız bir algoritma ile fonksiyonumuz yazdık,
> ve artık derleme anında değilde çalışma anında artık tipler
> belirnerek fonsiyonumuz düzenlenip cagiralacak.
Hayır, işlev ve sınıf şablonlarının kodları derleme zamanında kullanılırlar. Derleyici, o kodları kullanarak, şablonların her bir kullanımı için değişik kod üretir. Yani aşağıdaki 'toplam' işlevini 'char' ve 'int' türleri için iki kere kullanan bir programda derleyici, iki değişik işlev oluşturur ve onları derler.
Birbirlerinden bağımsız olan o iki işlevin kimlikleri (signature) şöyle olur:
Derleyicini böyle her tür için ayrı kod üreterek programın boyutunu arttırmasına kod şişmesi (code bloat) denir. (Bunun kısmen önüne geçmenin bazı yolları vardır.)Kod:char toplam<char>(char const *, char const *); int toplam<int >(int const *, int const *);
C++ durağan türlü bir dildir (statically typed (evet, kötü bir çeviri oldu). Şablon kullanımı, dilin bu özelliğini bozmaz.
> diyelimki ben bir class yazdım ve bu class'in + operatörü için
> tanımlı bir fonksiyonu yok.
> bu durumda toplamı cagirirsam oluscak hatayı nasıl anlayip
> engellerim ??!?
Önce küçük bir nokta: Her ne kadar soru genel olsa da, 'toplam' şablonunda toplama işleci (operator+) değil, arttırma işleci (operator+=) kullanılıyor.
Asıl yazıda da çok uzağından değinmeye çalıştığım gibi, aslında şablonlar tamamen türden bağımsız değillerdir. Volkan'ın da belirttiği gibi, her şablon ancak bazı şartları sağlayan türlerle kullanılabilir.
> yani :
>
> şimdi main içinden toplam(sacma_class a,sacma _class b )Kod:> #include <iostream> > > using std::cout; > > class sacma_class > { > private: > int a,b,c,d; > public : > int get_all(); > }; > template <class Tur> > Tur toplam(Tur const * bas, Tur const * son) > { > Tur sonuc = 0; > > for ( ; bas != son; ++bas) > { > sonuc += *bas; > } > > return sonuc; > }
> cagirimi bir hata ama ben bunu nasıl anlayuip onlem alırım ?
Derleyicinin kodları derleme zamanında kullanıyor olması bu konuda işimize yarar. Şablonları o şablonun gerektirdiği niteliklere sahip olmayan türlerle kullanmaya kalktığımızda derleme hatası alırız.
Yukarıdaki kodu eksiklerini giderdikten sonra aşağıdaki program içinde kullanacağım.
Önce, yapacağım bir değişikliğin nedenini söyleyeyim. Ben de çoğu C++ programcısı gibi, öğe nesnelerin adlarının sonuna bir '_' karakteri koyarım. Böyle yaptığım zaman, onları öğe işlevler içerisinde kolayca ayırdedebiliyorum. Aksi taktirde, en azından kurucu işlevde sorunlar yaşıyorum. Örneğin 'a' öğesine ilk değerini getiren parametreye ne diyeceğimi şaşırıyorum. Onun için, öğe adlarını değiştirdim.
AliKod:#include <iostream> using std::cout; template <class Tur> Tur toplam(Tur const * bas, Tur const * son) { /* Asil yazida kullandigimin aksine, burada 'sonuc' nesnesini varsayilan kurucu ile kuracagim. Asil yazida Tur sonuc = 0; yazmistim. Oyle yazmak, bu algoritmanin kullanilabilecegi turlerin sayisini azaltir. Cunku, o satirin kullanilabilmesi icin, turun bir 'int' alan (veya bir 'int'e donusturulebilecek bir tur alan) bir kurucusunun olmasi gerekir. Ustelik, o kurucunun 'explicit' de olmamasi gerekir. Asil yazida yaptigim bu dar goruslulugu :) burada duzeltiyor ve varsayilan kurucusu olan her turle calisabilecek sekilde yaziyorum: */ Tur sonuc = Tur(); /* Yukaridakini Tur sonuc(); seklinde yazmak daha dogal olurdu. Ancak, o zaman o satir ne yazik ki bir islev bildirimi olarak anlasilirdi: Tur donduren, hicbir parametre almayan, ve adi 'sonuc' olan bir islev! Varsayilan kurucuyla nesne olusturmaya calisirken boyle yanlislikla islev bildirimi yapmak, C++'in cok dusulen tuzaklarindan birisidir. (Ben de bu ornegi yazarken bu tuzaga belki de bir milyonuncu kere dustum :o) */ for ( ; bas != son; ++bas) { sonuc += *bas; } return sonuc; } /* Yukaridaki algoritma ile kullanilabilecek turlerin sunlari saglamalari gerekir: - varsayilan kurucu: Bunu biz yazacagiz - operator+=(Tur const &): Bunu biz yazacagiz - kopyalama kurucusu: Bunu yazmamiza gerek yok; derleyicinin yazdigi kopyalayici bu sinif icin yeterli olacaktir. (Cunku bu sinifin sahip oldugu ve sonradan geri verecegi bir kaynak yok.) */ class sacma_class { private: int a_,b_,c_,d_; public : // Varsayilan kurucu sacma_class() : a_(0), b_(0), c_(0), d_(0) {} sacma_class(int a, int b, int c, int d) : a_(a), b_(b), c_(c), d_(d) {} /* Arttirma isleci, sagdakinin her ogesinin degerini o ogeye karsilik gelen ogeye eklesin. */ sacma_class & operator+= (sacma_class const & sagdaki) { a_ += sagdaki.a_; b_ += sagdaki.b_; c_ += sagdaki.c_; d_ += sagdaki.d_; return *this; } void yazdir(ostream & cikis) const { cikis << a_ << ' ' << b_ << ' ' << c_ << ' ' << d_; } }; /* operator+= islecinin geleneksel yazis bicimi yukaridaki gibidir. operator+ ise, operator+= isleci kullanarak yazilir. Bu ornekte hicbir ise yaramasa da, cok kisa oldugu icin, ek bir bilgi olarak onu da veriyorum: */ sacma_class operator+ (sacma_class const & soldaki, sacma_class const & sagdaki) { /* Asagidaki satir, once soldakinin bir kopyasini alir, sonra sagdakini ona ekler, ve sonucu dondurur. */ return sacma_class(soldaki) += sagdaki; } #define OGE_ADEDI(x) (sizeof(x) / sizeof(*(x))) int main() { sacma_class const sacmalar[] = { sacma_class(11, 12, 13, 14), sacma_class(21, 22, 23, 24) }; sacma_class const sonuc = toplam(sacmalar, sacmalar + OGE_ADEDI(sacmalar)); sonuc.yazdir(cout); cout << '\n'; }
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks