Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

indekiler
C Dili ile C++ Dili Arasndaki Farkllklar (3)
Referanslar (21)
Parametre Deikenlerine Varsaylan Deerlerin Aktarlmas (37)
lev Yklemesi (43)
Snflar (53)
le Yklemesi (133)
sim Alanlar (155)
Tretme (171)
Sanal levler ve ok Biimlilik (197)
lev ablonlar (221)
alma Zaman Hatalarnn Yakalanmas ve lenmesi(247)
alma Zamannda Tr Belirlenmesi (279)
new ve delete lelerinin Yklenmesi (291)
oklu Tretme (303)

C++ Kitabi (1/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

C++ Kitabi (2/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

C DL LE C++ DL ARASINDAK
FARKLILIKLAR
Bu blmde ANSI C dili (C89 ISO/IEC 9889:1990) ile C++ dili (ISO/IEC 14882:1998)
arasndaki szdizim (sentaks) farkllklarn ele alacaz.
Bir C++ derleyicisi ile ayn zamanda C'de yazlm kaynak kodlar da derlenebilir. C++
derleyicisinin ayarlar (settings) deitirilerek yazlacak kaynak kodlarn dorudan C
kaynak dosyas olarak ele alnmas salanabilir. Ayrca derleyicilerin hemen hepsi,
yaratlan kaynak dosyann uzantsna bakarak -rnein uzantnn .c ya da .cpp olmasna
gre- kaynak kodu hangi dilin kurallarna gre derleyeceklerini anlar.
C++ dilinin temel szdizimsel yaps C dili szdiziminin zerine birtakm eklemelerin
yaplmasyla oluturulmutur. Bu durumda C dili szdizimsel adan C++ dilinin bir alt
kmesi olarak grlebilir. Baz noktalarda da C ve C++ dilleri szdizim kurallar asndan
farkllklar gsterir.
C ile C++ arasndaki szdizimsel farkllklar iki ana grupta ele alnabilir:
1. C alt programlama tekniine destek veren bir dilken, C++ birden fazla programlama
tekniine destek verir (multiparadigm). ki dil arasndaki farkllklarn nemli ksm, C++
n dier programlama tekniklerine destek verebilmek iin ekledii yeni aralara ilikindir.
2. Dier farkllklarn dorudan programlama teknikleriyle ilgisi yoktur. Bu farklar C++'
daha iyi bir C yapma amacna ynelik yaplan deiiklikler ve eklemeleri kapsar.
Cde yazlan bir dosya C++ diline, C++'da yazlan bir dosya da C diline tanmak
istenebilir. ANSI C dilinin kurallarna gre yazlan ve geerli olan bir kaynak dosya C++
diline tandnda, C++ dilinin kurallarna gre geersiz durumlar oluabilir.
phesiz bunun tersi de sz konusudur. Yani C++da bir szdizim hatas iermeyen bir
kod paras C dilinin kurallarna gre geersiz olabilir.
Baz durumlarda da yazlan kod her iki dilin kurallarna gre geerli olarak deerlendirilse
de, yazlan kod iki dilin kurallarna gre farkl anlamlara sahip olabilir. Bir kaynak dosyann
bir dilden dierine tanmasnda kural deiiklikleri yznden uyumsuzluk sorunlar ile
karlalabilir.
C ve C++ dilleri arasndaki temel szdizime ilikin farkllklar ayr balk altnda ele
alacaz:
C'de geerli C++'da geersiz olan durumlar
C++'da geerli C'de geersiz olan durumlar
C ile C++ arasndaki kural farkllklar

C++ Kitabi (3/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


C'de Geerli C++'da Geersiz Olan Durumlar
1. C'de anahtar szck olmayan baz szckler C++'da anahtar szcktr. Standart ANSI
C dilinin (C89) 32 anahtar szc vardr. Bu szckler ayn zamanda C++ dilinin de
anahtar szckleridir. Ancak C++ bunlara ek olarak yeni 42 anahtar szck daha
tanmlamtr. Aadaki szckler C++'da anahtar szck iken C'de anahtar szck
deildir:
and/and_eq/asm/bitand/bitor/bool/catch/class/compl/const_cast
/delete/dynamic_cast/explicit/export/false/friend/inline/mutable
/namespace/new/not/not_eq/operator/or/or_eq/private/protected
/public/reinterpret_cast/static_cast/template/this/throw/true/try
/typeid/typename/using/virtual/wchar_t/xor/xor_eq
Geerli bir C kodunda yukardaki szcklerden herhangi biri bir isim (identifier) olarak
kullanlm olabilir. Ancak ayn kod C++'da derlendiinde geerli deildir:
voidfoo()
{
intnew;
/***/
}
Yukarda int trden new isimli bir deiken tanmlanyor. Tanmlama Cde geerli C++da
geersizdir.
2. C'de geri dn deeri reten bir ilevin tanm iinde, return deyimi ile bir geri dn
deeri retilmez ise bu durum derleyiciler tarafndan bir szdizim hatas olarak
deerlendirilmez. Bu durumda arlan ilev bir p deere (garbage value) geri dner.
phesiz bu durum bir programlama hatasdr.
Oysa C++'da geri dn deeri reten bir ilevin tanm iinde mutlaka return deyimi
yazlarak bir geri dn deeri retilmelidir. Eer bir return deyimi ile geri dn deeri
retilmez ise kod geersizdir.
intfunc()
{
}
Yukardaki ilev tanm C'de geerli, C++'da geersizdir.
C++'da geri dn deeri reten ilevlerin tanm iinde yaln return deyimi kullanlamaz:
intfunc()
{
/***/
return;
}
Yukardaki rnekte yer alan return deyimi C'de geerli ancak C++ geersizdir.
phesiz yukarda return deyiminin kullanlma biimi bir programlama hatasdr. C
derleyicilerinin hemen hemen hepsi bu durumu mantksal bir uyar iletisi ile bildirir.
Ancak main ilevi C++'da bu kuraln dnda tutulur. main ilevi int trden bir geri dn
deeri retecek ekilde tanmlanm olsa da, main ilevi iinde bir return deyimi
yazlmayabilir. Bu durumda derleyici otomatik olarak main ilevinin ana blounun
sonlanmasndan nce, kaynak kod iinde
return0;

C++ Kitabi (4/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


deyimi yazlm gibi kaynak kodu ele alr. Kod geerlidir.
Aadaki kod hem Cde hem de C++'da geerlidir. C++ derleyicileri iin mantksal bir
uyar gerektirecek bir durum sz konusu deildir.
intmain()
{
}
3. C'de bir ilevin geri dn deerinin tr bilgisi yazlmaz ise, ilevin int trden deer
dndrd anlalr (implicit int). Oysa C++'da ilev bildirimlerinde ve tanmlarnda geri
dn deerinin trn yazmak zorunludur:
foo(void);
func(doublex)
{
/***/
}
Yukarda foo ilevinin bildirimi Cde geerli C++da geersizdir.
Yukarda func ilevinin tanm Cde geerli C++da geersizdir.
4. C'de bir ilevin tanmlanmasna ilikin iki ayr szdizim kural vardr. Bu szdizim
kurallar eski biim (old style) ve yeni biim (new style) olarak isimlendirilir. Eski biim
ilev tanmlamas programclar tarafndan artk hi tercih edilmemesine karn, C dilinin
kurallarna gre halen geerlidir. Oysa C++ dili standartlarna gre eski biim ilev
tanmlamas geerli deildir:
intfoo(a,b,c)
inta;
doubleb,c;
{
/***/
}
Yukardaki ilev tanm Cde geerli, C++da geersizdir.
5. C'de ilev bildirimi zorunlu deildir. C derleyicisi bildirimi yaplmayan bir ilevin
arsyla karlatnda ilevin int trden geri dn deeri rettiini varsayarak kod
retir. Oysa C++'da ilev bildirimi zorunludur:
intmain()
{
foo();
}
Yukardaki rnekte foo ilevine yaplan ar C'de geerli C++'da geersizdir:
Ancak bir ilevin bildirim yaplmadan arlmas C'de geerli olmasna karn doru kabul
edilmez.
6. C'de ilev bildiriminde ilev parametre ayracnn iinin bo braklmas ile parametre
ayracnn iine void anahtar szcnn yazlmas farkl anlam tar:

C++ Kitabi (5/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


intfunc();
voidfoo()
{
func(5);
}
Yukardaki rnekte func ilevi iin yaplan bildirimde parametre ayrac iine bir ey
yazlmamtr. Cde bu bildirimin anlam udur: Bildirilen func ilevinin parametre
deikenleri hakknda derleyiciye bir bilgi verilmemitir. Yani func ilevine yaplan arda
derleyici ileve gnderilen argman says ile ilevin parametre deiken saysnn ayn
olup olmadna bakmaz. Gemie doru uyumluluk iin bu bildirime zel bir anlam
yklenmitir. Cde bu bildirim
intfunc(void);
biiminde yaplsayd, derleyiciye func ilevinin parametre deikeni olmad bilgisi aka
verilmi olurdu.
Oysa C++'da her iki bildirimin de anlam ayndr:
intfunc();
intfoo(void)
C++'da ilev bildiriminde parametre ayracnn iinin bo braklmasyla ayracn iine void
anahtar szcnn yazlmas arasnda bir fark yoktur. Her ikisinde de ilevin parametre
deikenine sahip olmad bilgisi verilmi olur.
7. C de main ilevinin adresi alnabilir. main ilevi kendi kendini arabilir. Ancak C++'da
bu duruma izin verilmemitir.
C++'da main ilevi kendi kendini aramaz. main ilevinin adresi alnamaz.
8. C'de belirleyiciler (auto, register, static, extern, const, volatile), deiken
tanmlamalarnda tr belirten anahtar szck olmakszn dorudan deiken ismiyle
kullanlabilir. Bu durumda derleyici, tanmlanan deikenin int trden olduunu kabul
eder. Ancak C++'da belirleyicilerin byle kullanlmas geerli deildir.
voidfoo()
{
consti=0;
}
Yukardaki kod Cde geerli C++da geersizdir.
9. C'de const bir deikenin ilk deer verilmeden tanmlanmas tamamen geerlidir.
phesiz otomatik mrl bir nesne iin bu durum bir programlama hatasdr. C++'da
const deikenlere ilk deer vermek zorunludur:
voidfoo()
{
constintx;
char*constptr;
/***/
}
Yukardaki tanmlamalar Cde geerli, C++da geersizdir.
C++da statik mrl const deikenlere de ilk deer vermek zorunludur:

C++ Kitabi (6/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


constintx;
voidfoo(){}
Yukardaki rnekte x deikeninin tanm Cde geerli, C++da geersizdir.
Ancak aadaki tanmlama iki dilde de geerlidir:
constint*ptr;
Burada ptr deikeninin kendisi const deildir. ptr deikeninin gsterdii yer const olarak
ele alnr.
10. C'de void trden bir adresin void trden olmayan bir gsterici deikene, tr
dntrme ilemi yaplmakszn atanmas geerlidir. Baz C derleyicileri bu durumda bir
mantksal uyar iletisi verebilir. Ama bu durum bir szdizim hatas olarak deerlendirilmez.
Ancak bu durum C++'da bir szdizim hatasdr. C++'da void trden adresler tr
dntrme ileci kullanlmadan, baka trden bir gstericiye atanamaz:
#include<stdlib.h>
voidfoo()
{
int*ptr;
ptr=malloc(sizeof(int));
/***/
}
Yukardaki rnekte ptr deikenine yaplan atama Cde geerli, C++da geersizdir.
11. C'de bir gsterici deikene adres bilgisi dndaki bir deerin atanmas ya da bir
gsterici deikene farkl trden bir adresin atanmas yanltr. C derleyicilerinin ou bu
durumu bir mantksal uyar iletisiyle bildirir. Cde doal trler ile adres trleri arasnda
otomatik tr dnm vardr.
C++'da bir adres deeri olmayan bir ifadenin bir gsterici deikene atanmas ya da bir
adresin farkl trden bir gsterici deikene atanmas durumu dorudan szdizim
hatasdr.
voidfoo()
{
intx=10;
double*dp;
int*ip;
dp=&x;
ip=20;
/***/
}
Yukardaki kod parasnda dp ve ip isimli gsterici deikenlere yaplan atamalar C++da
geerli deildir.
12. C'de const bir deikenin adresinin, gsterdii yer const olmayan bir gstericiye
atanmas yanltr. C derleyicilerinin ou byle bir durumda yalnzca bir mantksal uyar
iletisi verme eilimindedir. C++'da bir const deikenin adresinin gsterdii yer const
olmayan bir gstericiye tr dnm yaplmadan atanmas geersizdir.
C++'da const nesnelerin adresleri ayr bir adres trnden kabul edilir. Byle adresler
ancak gsterdii yer const olan gsterici deikenlere atanabilir:

C++ Kitabi (7/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidfoo()
{
constintx=20;
volatileinty=50;
int*ptr;
ptr=&x;
ptr=&y
}
Yukardaki kod parasnda ptr gstericisine yaplan atamalar C++'da geerli deildir.
Benzer ekilde C++da gsterdii yer const olan bir gstericinin deeri de, gsterdii yer
const olmayan bir gstericiye atanamaz:
voidfunc(constchar*ptr)
{
char*temp=ptr;
/***/
}
Yukardaki kod parasnda temp gstericisine yaplan atama C++'da geerli deildir.
13. C'de const ya da volatile bir nesnenin adresi void trden bir gstericiye atanabilir.
C++'da void trden bir gstericiye const ya da volatile anahtar szc ile tanmlanm
bir nesnenin adresi tr dnm yaplmadan atanamaz.
void trden gstericilere her trden adres atanabilir. Ancak C++'da const ya da volatile
anahtar szc ile tanmlanm bir nesnenin adresi tr dntrmesi yaplmakszn void
trden bir gstericiye atanamaz.
voidfoo()
{
void*vptr1,*vptr2;
constintx=10;
volatileintv=20;
vptr1=&x;
vptr2=&v;
/***/
}
Yukardaki kod Cde geerlidir. Ancak vptr1 ve vptr2 deikenlerine yaplan atamalar C+
+da geerli deildir.
14. C'de ilev tanmlarnda ya da bildirimlerinde, geri dn deerinin yazld yerde,
parametre deikenlerinin bildirildii yerde programc tarafndan tanmlanan trler
bildirilebilir. C++'da byle bildirimler geerli deildir.
structA{inta1,inta2;}foo();
Yukardaki bildirim C'de geerlidir. foo ilevinin geri dn deeri bildirilen struct A yaps
trndendir. Ancak C++'da bu bildirim geersizdir.
voidfunc(structB{intb1,intb2;}x);
Yukardaki bildirim de C'de geerlidir. func ilevinin parametre deikeni, parametre
ayrac iinde bildirilen struct B yaps trndendir. C++'da bu bildirim geersizdir.
15. C'de doal trlerden bir deerin bir numaralandrma trnden deikene atanmas
geerlidir. C++'da bir numaralandrma trnden bir nesneye ancak sz konusu
C++ Kitabi (8/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


numaralandrma trne ilikin bir numaralandrma deimezi (enumaration constant)
atanabilir.
enumPosition{ON,OFF,HOLD};
voidfoo()
{
enumPositionpos=1;
/***/
}
pos deikenine yaplan atama Cde geerli iken C++da geersizdir.
16. C'de global bir deiken extern anahtar szc olmadan birden fazla kez bildirilebilir.
C++ bir kaynak dosya iinde bir deiken extern anahtar szc kullanlmadan yalnzca
bir kez bildirilebilir.
intx;
intx;
voidfoo()
{
}
Yukardaki kod C'de geerli iken C++'da geersizdir.
17. C'de programc tarafndan tanmlanan bir tr iin kullanlan etiket-isim (tag) ayn
bilinirlik alan iinde kullanlan bir typedef ismiyle ayn olabilir. Bu durum bir szdizim
hatas deildir.
structWord{
charhb,lb;
};
typedefintWord;
Yukardaki kod paras C'de geerli, C++'da geersizdir.
18. C'de isel bir yap bildirimi ait olduu bilinirlik alannda dorudan grlebilir. C++'da
isel bildirilen trler dorudan kullanlamaz:
structOuter{
structInner{
/***/
}
/***/
}
structInneri;
Yukardaki rnekte struct Inner trnn bildirimi struct Outer trnn bildirimi iinde
yaplyor. struct Inner trnden i isimli deikenin tanm C'de geerlidir. nk bu
tanmlama noktasnda struct Inner tr bilinir. Ancak yukardaki kod C++'da geersizdir.
C++'da struct Inner tr dorudan deil Outer::Inner biiminde kullanlabilir.
19. C'de char trden bir diziye bir dizgeyle ilkdeer verilirken, dizge iinde yazlan
karakterlerin says, tanmlanan dizinin belirtilen boyutuna eit olabilir. Bu durumda diziye
yerletirilen yaznn sonunda sonlandrc karakter bulunmaz.
C++ Kitabi (9/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


C++'da byle bir ilkdeer verme ilemi geersizdir.
voidfoo()
{
charmessage[4]="hata";
/***/
}
Yukardaki kod paras C'de geerli, C++'da geersizdir.
20. C++'da dizgeler bir ileme sokulduunda char trden adrese deil const char trden
adrese dntrlr.
C'de kaynak kod iinde bir dizge gren derleyici, nce bu dizge iin bellekte gvenilir bir
yer ayarlar. Daha sonra bellekte ayarlanan yerin (bloun) balang adresini dizgenin
yerine yerletirir. C'de gstericiler yoluyla bir dizgeyi deitirmeye almak, bir
programlama hatas olmasna karn, bir szdizim hatas oluturmaz.
Oysa C++'da dizgeler ileme sokulduklarnda const char trden bir adres olarak ele alnr.
Ancak gemite yazlan ok sayda C++ kodunun geersiz hale gelmemesi iin const char
trden birer adres olan dizgelerin, const olmayan char trden gstericilere atanmasna
1998 Standartlaryla izin verilmitir. Ancak bu durum "deprecated"(2) ilan edilmitir.
Bu durumda 1998 C++ standartlarna gre aadaki kod geerlidir:
char*p="NecatiErgin";
Burada gsterdii yer const olmayan p gstericisine const bir adres atanmas geerlidir.
Ama C++ derleyicilerinin ou bu durumda mantksal uyar iletisi verir.
Ancak dizgeler herhangi bir ifade iinde, const olmayan char trden (char *) bir adres
gereken yerde kullanlrsa C++ da bu geersizdir.
voidfoo()
{
char*p="NecatiErgin"+1;
char*str=x>1?"Books":"Book";
*"selam"='k';
}
Yukardaki deyimler C'de geerli C++'da geersizdir.
Yazlacak yeni kodlarda artk dizgeler const char trden bir adres olarak grlmeli ve
ancak okuma amal gsterici deikenlere, yani const char * trden deikenlere
atanmaldr.
21. Cde bilinirlik alan iinde bir sramay salayan goto ve switch kontrol deyimleri bir
tanmlama deyiminin bulunduu kod blgesinin sonrasna sramay salayabilir. C++da
bu durum yasaklanmtr.

C++ Kitabi (10/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

C++'Da Geerli C'de Hatal Olan Durumlar


1. C89 standartlarna gre yerel her trl bildirim bloklarn banda yaplmak zorundadr.
Yani bir blok iinde yaplan bildirimden nce yrtlebilir bir deyim (executable
statement) bulunamaz. [C99 standartlarna gre yerel bir blok iinde her yerde bildirim yaplabilir.]
C'de byle bir tasarmn yaplm olmasnn nedeni, programcnn yaplm olan bildirimin
yerini kolayca bulabilmesini salamaktr.
Oysa C++'da bildirimler ve tanmlamalar blok iinde herhangi bir yerde yaplabilir:
voidfoo()
{
inty;
y=10;
intx;
/***/
}
Yukarda x deikeninin tanmlanmas Cde geersiz C++'da geerlidir.
C++'da bir blok iinde yaplan bildirim ya da tanmlamann, bildirimin ilk kullanlaca
yere yakn bir yerde yaplabilmesi, kaynak kodun okunabilirliini artrc bir etken olarak
dnlmtr. Ancak asl nemli neden, programc tarafndan tanmlanan trlere ait
deikenlere ilikindir. C++'da byle nesneler bir ok durumda tanmlanmalaryla birlikte
dsal baz kaynaklar kullanmaya balar. Eer bu deikenler bloun en banda
tanmlanmak zorunda olsalard, ilk kullanldklar yere kadar gereksiz bir biimde kaynak
kullanmak zorunda kalrlard.
Bir ismin derleyici tarafndan tannabildii kaynak kod aralna bilinirlik alan (scope)
denir. C'de yerel deikenler blok bilinirlik alanna (block scope) uyar. Yani bildirilmi
olduklar bloun bandan sonuna kadar herhangi bir yerde bilinirler. C++'da bildirimler
blok balarnda yaplmak zorunda olmadndan, bilinirlik alan kuraln u biimde
deitirmek gerekir: C++'da yerel deikenlerin bilinirlik alan bildirildikleri yerden ilgili
bloun sonuna kadar olan kaynak kod blgesidir. C++'da da C'de olduu gibi, bir blok
iinde ayn isimli birden fazla deikenin bildirimi yaplamaz.
2. C++'da bool tr doal bir veri trdr.
C'de bool nceden tanmlanm bir veri tr deildir. (C99 standartlar ile C diline de bool
tr eklenmitir.)
voidfoo()
{
boolflag;
/***/
}
Yukardaki kod C++da geerli Cde geersizdir.
C'de byle bir gereksinim duyulduunda baz aralar kullanlabilir.
#defineBOOL
int
typedefintBOOL
enumBOOL{TRUE,FALSE}

/*nilemcikomutuyla*/
/*typedefbildirimiyle*/
/*numaralandrmatrolarak*/

Oysa C++'da bool doal bir trn ismidir ve bool bir anahtar szcktr. Bu trden
deerleri gsteren true ve false szckleri de C++'n anahtar szck kmesine
eklenmitir.
C++'da bool trden bir nesne true ve false deerlerini alabilir.
bool trden bir nesneye baka bir trden deer atanmas durumunda bu deerler atama
ncesinde otomatik olarak true ya da false deerlerine dntrlr. Yani dier doal
C++ Kitabi (11/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


trlerden bool trne otomatik tr dnm vardr. bool trden nesneye atanan 0 d
bir deerse true deerine 0 deeri ise false deerine dnm gerekleir. bool trden bir
nesneye bir adres bilgisi de atanabilir. NULL adresi atama ncesi false deerine
dntrlrken dier adres bilgileri true deerine dntrlrler.
bool trden bir deer de, dier doal trlere atanabilir. Bu durumda atama ncesi true
deeri int trden 1 deerine false deeri ise int trden 0 deerine dntrlr.
C'de karlatrma ileleri ve mantksal ileler int trden 1 ya da 0 deerini retir. Oysa
C++'da bu ileler bool trden true ya da false deerlerini retir.
3. C++'da deimez ifadesiyle ilkdeerini alan const deikenler deimez ifadesi
gereken yerlerde kullanlabilir.
C'de const deikenler, deimez ifadesi olarak kabul edilmez. const deikenleri ieren
ifadeler deimez ifadesi olarak ele alnmaz. Ancak C++'da deimez ifadeleri ile
ilkdeerini alan const deikenler, "deimez ifadesi" olarak kullanlabilir.
voidfoo()
{
constintsize=10;
inta[size];
/***/
}
Yukardaki kod C++da geerli Cde geersizdir.
const nesne tanmlamasnda C ile C++ dilleri arasndaki en nemli fark, C++'da const
anahtar szc ile tanmlanan deikenin simgesel deimez gibi ele alnmasdr. Yani
C++'da const anahtar szc #define ileminin derleme modl tarafndan yaplan
biimi gibidir. const bir deikenin kullanldn gren C++ derleyicisi, const deiken
yerine ona verilen ilk deeri deimez olarak ileme sokar.
4. C++'da yap, birlik, numaralandrma etiketleri (tags) ayn zamanda tr ismi olarak
kabul edilir.
structComplex{
/*....*/
};
enumPOS{OFF,ON};
Complexfunc(Complex,Complex);
POSposition;
Yukardaki rnekte func ilevinin bildirimi ve position deikeninin tanm C++da geerli
Cde geersizdir.
Cde bildirilen bu trlerin ismi struct Complex, enum Postur. Eer struct ve enum
szckleri kullanlmadan tr bilgisinin ifade edilmesi istenirse, Cde bir typedef bildirimi
yaplmaldr.
5. C++'da // atomuyla balayan yorum satr kullanm olana vardr. Bu yorum satr
biimi C'de geerli deildir.
C'de /* ve */ atomlar arasnda kalan kaynak kod blgeleri C derleyicileri tarafndan
yorum satrlar olarak ele alnr ve derleme ilemine sokulmaz.
x=func();/*xefuncileviningeridnde?eriatanyor*/

C++ Kitabi (12/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


/* ve */ atomlar arasnda kalan blgenin uzunluu bir satrdan daha byk olabilir.
x=func();
/*xde?ikeninefuncileviningeridnde?eriatanyor.Amagerek
programlardayorumsatrlarancakgerekendurumlardakullanlmal,yorum
satrlarnngereksizbirbiimdekullanlmasprogramlarn
okunabilirli?inizorlatrr*/
C++'da bu tr yorum satrlar tamamen geerli olmakla birlikte, ikinci bir yorum satr
biimi daha eklenmitir:
C++'da // atomunun bulunduu noktadan satr sonuna kadar olan ksm derleme
ilemine sokulmaz. Bu yorumlama biiminin zellikle ksa aklamalar iin daha kullanl
olduu sylenebilir. (C++ bu yorum satrn BCPL dilinden almtr.)
Ancak // yorum satr alt satrda devam edemez. Eer aklama ya da yorum bir satrdan
daha uzunsa, her satrn bana tekrar // atomu yerletirilmelidir.
C'de yorum satrnn kapatlmamas zor bulunan hatalara yol aabilir:
inta,b;
a=10;
b=20;

/*anesnesine10de?eriatand.
/*bnesnesine20de?eriatanmad!*/

Yukardaki rnekte birinci yorum satr kapatlmad iin


b=20
atamas derleme ilemine sokulmaz.
C++ biimi yorum satr tek bir atomla oluturulduu iin yukardaki yanlln yaplmas
olasl yoktur:
voidfoo()
{
inta,b;
a=10;
b=20;
/***/
}

//anesnesine10de?eriatand.
//bnesnesine20de?eriatand.

Yukardaki kod C++'da geerli C'de geersizdir.


Ancak C derleyicilerinin ou // yorum satrlarnn kullanmna izin verir. // yorum satrlar
C99 standartlaryla C diline de eklenmitir.
6. C++'da statik mrl deikenlere ilkdeer verilirken deimez ifadesi kullanma
zorunluluu yoktur. C'de statik mrl deikenlere deimez ifadeleriyle ilkdeer vermek
zorunludur.
intfoo();
intx=5;
inty=x;
voidfunc()
{
staticintz=foo();
/***/
}

C++ Kitabi (13/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Yukardaki rnekte global y deikenine ve statik yerel z deikenine, deimez ifadesi
olmayan ifadelerle ilkdeer verilmitir. Bu deyimler C++'da geerli iken C'de geersizdir.
7. C++'da for dng deyimi ayracnn birinci ksmnda, if, while, switch deyimlerinin
ayrac iinde deiken tanmlanabilir.
C'de yerel deikenler yalnzca blok balarnda ve ilev parametre ayralarnn iinde
tanmlanabilir. C++'da for dnglerinin birinci ksmnda, while dnglerinin ayralar
iinde ve if deyiminin ayrac iinde deiken tanmlama olana getirilmitir.
#include<cstdio>
intmain()
{
for(inti=0;i<100;++i)
printf("%d\n",i);
return0;
}
Yukardaki for deyimi C++da geerli, Cde geersizdir.
for dng deyimi ayracnn birinci ksmnda tanmlanan nesne herhangi bir trden olabilir.
Burada virgl ileci kullanlarak ayn trden birden fazla nesne de tanmlanabilir:
1998 ISO standartlar ncesinde if, while ve switch ayralar iinde bildirim yaplmasna
izin verilmiyordu. Ancak standartlar ile bu durumlar da mmkn klnd. Eski derleyicilerin
bu deyimlerin ayralar iinde deiken tanmlamasna izin vermeyebileceini hatrlatalm.
nk bu durum 1998 standartlar ile C++ diline eklenmitir.
Peki for ayracnn birinci ksmnda tanmlanan deikenin bilinirlik alan nedir? Yukardaki
programda, for dngsnn birinci ksmnda tanmlanan i deikeni nerelerde
kullanlabilir?
Bu tr deikenlerin bilinirlik alanna ilikin kural standartlar ile deitirilmitir. C++
standartlar ncesinde Baz derleyiciler halen bu kurala gre derlemektedir- bilinirlik
alanna ilikin kural u ekildeydi:
for ayrac iinde tanmlanan deiken, for dngsnn iinde bulunduu bloun sonuna
kadar, yani kapanan kme ayracna kadar bilinir.
Ancak 1998 standartlar, for ayrac iinde tanmlanan deikenlerin bilinirlik alann dng
gvdesi ile (loop body) snrlamtr. Yani aadaki kod paras daha nceki kurallara gre
geerliyken, C++ standartlarna gre geersizdir.
#include<cstdio>
intmain()
{
for(inti=0;i<100;++i)
printf("%d\n",i);
printf("i=%d\n",i);

//Geersiz

return0;
}
Dng deikeninin bilinirlik alanna ilikin bu deiiklik tehlikeli bceklerin kayna
olabilir.
C++ Kitabi (14/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

#include<cstdio>
inti=0;
intmain()
{
for(inti=0;i<100;++i)
printf("%d\n",i);
i=100;
//globalde?ikenolani'yeatamayaplyor.
//...
}
Yukarda programda
i=100;
atama deyimiyle, hangi i deikenine atama yaplmaktadr? Eski derleyicilere gre for
deyimi ayrac iinde tanmlanan i deikenine atama yaplmaktadr. nk dar bilinirlik
alannda olan ayn isimli deiken geni bilinirlik alanndaki ayn isimli deikeni maskeler!
Oysa standart ISO C++ dilinin kurallarna gre yalnzca global deiken olan i'ye
eriilebildii iin global deiken olan i'ye atama yaplr.
Dier denetim deyimlerinin ayralar iinde deiken tanmlanmas uygulamada bir fayda
getirir mi? Ana tema ayra iinde tanmlanan deikene bir ilev arsnn rettii geri
dn deerinin atanmas ve bu deikenin yalnzca denetim deyiminin gvdesinde
kullanlmasdr:
if(intx=get_value()){
//...
}
8. C++'da statik mrl deikenlere deimez ifadesi ile ilk deer vermek zorunlu
deildir.
C'de statik mrl deikenlere, yani global deikenler ve static anahtar szc ile
tanmlanm yerel deikenlere ilk deer verilmesi durumunda, ilk deer veren ifadenin
(initializer) deimez ifadesi olmas gerekir. Yani ilkdeer veren ifade iinde daha nce
tanmlanm bir deiken yer alamaz. Bunun nedeni C'de, statik mrl nesnelerin ama
kod iine ilk deerleriyle birlikte yazlmasdr. Bunun mmkn olabilmesi iin verilen
ilkdeerlerin derleme aamasnda belirlenmi olmas gerekir. Derleme aamasnda
saptanabilmesi iin ifadenin deimez ifadesi olmaldr. Oysa C++'da statik mrl
nesnelere her trden bir ifadeyle ilk deer verilebilir. Bu deikenlere ilk deer verilmemi
olsa da, bu deikenler 0 deeriyle ama kod iine yazlr. Programn alma zaman
srasnda ve main ilevinden nce ilk deerlerini alrlar.
9. C++ da iki karakterlik ayra atomlar tanmlanmtr. Derleyici ve nilemci program
bu kakarakter iftelerini grd yerde bunlara edeer karakterlerinin bulunduunu
varsayar:
<:
:>
<%
%>
%:

[
]
{
}
#
C++ Kitabi (15/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

C'de bu karakter ifteleri geerli deildir:


%:include<stdio.h>
voidcopy(chardest<::>,constcharsource<::>,size_tnbytes)
<%
while(nbytes)
*dest++=*source++;
%>
Yukardaki program C++'da geerli, C'de geersizdir.
10. C++da sonek konumundaki ++ ileci ile oluturulan ifade sol taraf deeridir. C'de
byle ifadeler sol taraf deeri deildir:
#include<stdio.h>
intmain()
{
intx=5;

++x=10;
printf("x=%d\n",x);
return0;
}
Yukardaki programda yaplan
++x=10;
atamas C++'da geerli, C'de geerli deildir.
11. C++'da koul ileci ile oluturulmu bir ifade, koul ilecinin ikinci ve/veya nc
terimleri nesne ise, bir sol taraf deeridir. C'de koul ileciyle yazlan bir ifade hi bir
zaman sol taraf deeri deildir:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
intmain()
{
intx,y;

x=y=0;

srand((unsignedint)time(0));

(rand()%2?x:y)=1;

printf("x=%d\n",x);
printf("y=%d\n",y);

return0;
}

C++ Kitabi (16/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Yukardaki programda yaplan
(rand()%2?x:y)=1;
deyimi C++'da geerli, C'de geersizdir.
12. C++'da virgl ileci ile oluturulmu bir ifade, virgl ilecinin sa terimi bir nesne ise
bu nesneye karlk gelir. C'de virgl ileciyle yazlan bir ifade hi bir zaman sol taraf
deeri deildir:
#include<stdio.h>
intmain()
{
intx=10;
inty;
(x,y)=30;
printf("x=%d\n",x);
printf("y=%d\n",y);

return0;
}
Yukardaki programda yazlan
(x,y)=30;
deyimi C++'da geerli iken C'de geersizdir.
13. C++'da bir typedef bildiriminin zde olarak yinelenmesi geerlidir. C'de bir typedef
bildiriminin ikinci kez yazlmas bir szdizim hatasdr.
typedefdoubledollar;
typedefdoubledollar;
Yukardaki bildirimler C++'da geerli, C'de geersizdir.
14. C++'da tr dntrme ilecinin ilevsel biimi vardr. ilecin byle kullanm C'de
geerli deildir.
voidfoo()
{
doubled=4.5;
intx;
x=int(d);
/***/
}
Yukardaki rnekte double trnden d deikeninin deeri atama ncesinde tr
dntrme ilecinin ilevsel biimi kullanlarak int trne dntrlyor.
Yukardaki kod C++'da geerli olmakla birlikte C'de geerli deildir.
15. C++'da geri dn deeri retmeyen bir ilevin return deyiminde return anahtar
szcn void trnden bir ifade izleyebilir. C'de byle ilevlerde return anahtar
szcn bir ifade izleyemez:

C++ Kitabi (17/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidfoo();
voidfunc()
{
/***/
returnfoo();
}
Yukardaki rnekte kullanlan return deyimi C++'da geerli, C'de geersizdir.
16. C++'da bir ilev tanmnda parametre deikenine isim vermek zorunlu deildir:
voidfunc(int)
{
/***/
}
Yukardaki rnekte func ilevinin tanm C++'da geerli C'de geersizdir. phesiz byle
bir ilev tanm yapldnda isim verilmeyen parametreyi ilev iinde kullanmak mmkn
deildir. Zaten C++'da da byle ilevlerin tanmlanmasnn nedeni "ilev yklemesi" ismi
verilen arala ilgilidir.
17. C++'da dizilere, yap ya da birlik nesnelerine ilkdeer verilirken, deimez ifadeleri
kullanmak zorunluluu yoktur. Ancak C'de bu durumlarda ilk deer verici ifade olarak
yalnzca deimez ifadeleri kullanlabilir.
voidfunc(intx)
{
inta[3]={x,x+1,x+2};
/***/
}
Yukardaki rnekte a dizisinin tanm C++'da geerli, C'de geersizdir.

C++ Kitabi (18/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

C ile C++ Arasndaki Kural Farkllklar


1. C'de bir numaralandrma tr derleyici asndan signed int trnden farkl deildir. Bu
yzden bir numaralandrma trnden nesnenin deeri <= INT_MAX >=INT_MIN (=ten
sonra boluk var m yok mu) olabilir. BLUE bir numaralandrma deimezi olmak zere
C'de
sizeof(int)==sizeof(BLUE)
ifadesi her zaman dorudur.
Oysa C++'da, derleyici numaralandrma tr iin kullanaca tamsay trnn seiminde
serbesttir. Numaralandrma tr iin signed int, unsigned int, signed long, unsigned long
trlerinden herhangi biri seilebilir. Bir ok sistem sz konusu olduunda C++ da C'ye
gre daha byk numaralandrma deimezi tanmlanabilir.
(*bo satr*)
C++ derleyicisi bir numaralandrma trnn bildirimini grdnde bildirmde kullanlan
numaralandrma deimezlerinin deerine bakar. Eer tm deerler int tr say
snrlarnda ise, numaralandrma tr olarak int tr seilir. Numaralandrma
deimezlerinin deer(ler)inin signed int trnde tutulamamas durumunda srasyla
unsigned int, signed long, unsigned long trlerinin uygunluu snanr.
Yukardaki rnek sz konusu olduunda
sizeof(int)==sizeof(BLUE)
ifadesi doru olmak zorunda deildir.
2. C++'da karakter deimezlerinin char trnden olduu varsaylr. Karakter deimez
ifadeleri char trdendir. C++da
sizeof('A')==sizeof(char)==1
olduu gvence altna alnmtr.
Cde karakter deimezlerinin int trnden olduu varsaylr ve karakter deimez
ifadeleri int trdendir. Cde
sizeof('A')==sizeof(int)
iken C++'da
sizeof('A')==sizeof(char)
ifadesi dorudur.
3. C'de const anahtar szc ile tanmlanm global nesneler dorudan d balantya
(external linkage)sahiptir. Oysa C++'da const global nesneler i balantya sahiptir.
Program oluturan baka modllerde bu nesnelere extern bildirimi ile eriilemez. Baka
bir deyile C++da const global nesneler, static anahtar szc ile tanmlanmasalar da
static anahtar szc ile tanmlanm gibi ele alnr.
(*bo satr*)
C++'da global const bir nesnenin d balantya sahip olmas isteniyorsa bu nesneler
extern anahtar szc ile tanmlanmaldr:
constintsize=10;
externconstintvalue=20;

//sizeC++'daiba?lantyasahip.
//valueC++'dadba?lantyasahip.
C++ Kitabi (19/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Yukardaki rnekte tanmlanan deikenlerden size i balantya sahipken value deikeni


d balantya sahiptir.
(*bo satr*)
4. C'de bir yapnn etiket ismi (structure tag) ait olduu yalanna katlmaz. Bir yapnn
etiket ismi hi bir zaman daha geni bir bilinirlik alanndaki ayn ismi maskelemez. Ancak
C++'da programc tarafndan tanmlanan trlere ilikin etiket isim, bildirimin yapld
bilinirlik alanna katlr.
inta[100];
voidfoo()
{
structa{inti;}
intn;
printf("sizeof(a)=%d\n",sizeof(a));
}
Yukardaki rnekte sizeof(a) ifadesinde kullanlan a C'de global diziye ilikin iken C++'da
foo ilevi iinde bildirilen a isimli yapya ilikindir.

C++ Kitabi (20/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

REFERANSLAR
Referanslar yazlmsal baz amalara salamak iin kullanlan dzeyi ykseltilmi
gstericiler olarak dnlebilir.

Referanslar Nasl Tanmlanr


Nasl bir gsterici tanmlanrken gsterici isminin nnde '*' atomu kullanlyorsa, bir
referans tanmlanrken de, referans isminden nce & atomu yazlr. rnein:
inti=20;
doubled=10.2;
int&ri=i;
//riinttrdenbirreferanstr.
double&rd=d;//rddoubletrdenbirreferanstr.
Gsterici deikenlerden farkl olarak, bir referans ayn trden bir nesne ile ilkdeer
verilerek tanmlanmaldr. Yukardaki rnekte, ri referans int trnden i nesnesi ile, rd
referans ise double trnden d nesnesiyle ilkdeer verilerek tanmlanyor. Yukardaki
tanmlamalarda kullanlan '&' bir ile deildir. Yalnzca tanmlanan nesnenin bir referans
olduunu derleyiciye bildirir. Referansn ilkdeer verilmeden tanmlanmas geersizdir.
Derleme zaman hatas olarak deerlendirilir. rnein:
int&a;
tanmlamas geersizdir.
Bir referans ilk deer olarak ona atanan nesnenin yerine geer.
int&r=b;
gibi bir tanmlamadan sonra artk r nesnesi, grlebilir olduu her kaynak kod noktasnda
b deikenin yerine geer, onun yerine kullanlabilir. Artk b deikenine ulamann bir
baka yolu da, b ismini kullanmak yerine dorudan r ismini kullanmaktr. Bu durum yle
de ifade edilebilir:
r referans b deikenine balanmtr.

Tanmlamadan Sonra Referansn Kullanlmas


Tanmlama ileminden sonra referans deikeni kullanlrsa, referansn baland
deiken kullanlm olur:
#include<iostream>
intmain()
{
inta=10;
int&r=a;
r=20;
std::cout<<"a="<<a<<std::endl;
return0;
}
Yukardaki main ilevini inceleyelim:
r referans daha nce tanmlanan a deikenine balanyor. Bylece r referans a
deikeninin yerine geiyor. Daha sonra r referansna yaplan atama, aslnda a
deikenine yaplm olur.
C++ Kitabi (21/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Bu ilemler referans deil de gsterici deiken kullanlarak yaplm olsayd, aadaki


gibi bir kod yazlabilirdi:
#include<iostream>
intmain()
{
inta=10;
int*ptr=&a;
*ptr=20;
std::cout<<"a="<<a<<std::endl;
return0;
}
Gerekten de derleyiciler her iki program iin de ayn makine kodlarn retir.
lk deerini alan bir referans, yani bir nesnenin yerine geen bir referans, bir ilecin terimi
olduunda, ile referans deil, referansn yerine getii nesneyi ileme sokar:
#include<iostream>
usingnamespacestd;
intmain()
{
inta=10;
int&r=a;

cout<<"a="<<a<<endl;
r+=2;
cout<<"a="<<a<<endl;
r=r;
cout<<"a="<<a<<endl;
return0;
}
r+=2
deyimiyle a deikeninin deeri 2 artrlyor. Artk a'nn yeni deeri 12 olur.
r=r;
deyimiyle a deikeninin deeri -12 yaplyor.
Bir referansn ilevini iyi anlayabilmek iin, kodun gsterici deikenlerle oluturulmu
edeer karlklar gz nne alnabilir. rnein yukardaki program parasnn gsterici
deiken ile oluturulmu edeer karl aadaki gibidir:
#include<iostream>
usingnamespacestd;
intmain()
{
inta=10;
C++ Kitabi (22/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


int*ptr=&a;

cout<<"a="<<a<<endl;
*ptr+=2;
cout<<"a="<<a<<endl;
*ptr=*ptr;
cout<<"a="<<a<<endl;
return0;
}

Tanmlanm Bir Referans Bir Baka Nesnenin Yerine Geemez


Bir referans, tanmlanmasyla birlikte bir nesnenin yerine geer. Artk sz konusu
referans, bilinirlik alan iinde hep ayn nesnenin yerine geer. Referansn daha sonra bir
baka nesneye balanmas mmkn deildir:
#include<iostream>
intmain()
{
inta=10;
intb=20;
int&r=a;
r=b;
std::cout<<"a="<<a<<std::endl;
return0;
}
Yukardaki main ilevinde tanmlanan r referans, a deikeninin yerine geiyor. Daha
sonra yaplan
r=b;
atamas, r referansnn b deikeninin yerine getii anlamna gelmez. Bu atamann
anlam udur: r referansnn baland nesneye b deikeninin deeri atanmaktadr.
Derleyicilerin rettii kod asndan bu durum u ekilde de deerlendirilebilir: Referanslar
kendisi const olan gstericilere karlk gelir. Yukardaki kodun bir referans ile deil de bir
gsteri deiken kullanlarak yazldn dnelim:
#include<iostream>
intmain()
{
inta=10;
intb=20;
int*constptr=&a;
*ptr=b;
std::cout<<"a="<<a<<std::endl;
ptr=&b;//Geersiz
return0;
}
Yukardaki rnekte ptr, kendisi const olan bir gsterici deikendir. ptr deikeninin
tanmndan sonra, ptr'ye artk baka bir nesnenin adresi atanamaz, deil mi?

C++ Kitabi (23/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Referanslarn const Olarak Bildirilmesi


Bir referans const anahtar szc ile tanmlanabilir. const anahtar szc &
atomundan nce yazlr. Bu ekilde tanmlanm bir referans deikeninin yerine getii
nesne, referans yoluyla deitirilemez. rnein:
intmain()
{
inta=10;
constint&r=a;
r=20;
//Geersiz!
return0;
}
main ilevi iinde yer alan
r=20
ifadesi geerli deildir. Atama aslnda a deikenine yaplr. const referans kullanlarak,
referansn yerine getii nesne deitirilemez. Ancak tabii, const referans sa taraf deeri
olarak ilemlere sokulabilir. Yukardaki program parasnn gstericilerle oluturulan
edeer C karl yle olur:
intmain()
{
inta=10;
constint*constptr=&a;
*ptr=20; //Geersiz
return0;
}
Burada ptr, hem kendisi const hem de gsterdii yer const olan bir gsterici deikendir.
ptrnin kendisine yaplan atamalar geersiz olduu gibi ptr'nin gsterdii nesneye yaplan
atamalar da geersizdir.
Peki const anahtar szc & atomundan sonra, referansn isminden nce kullanabilir
mi? Gsterici isminden nce * atomundan sonra const anahtar szcn
kullanldnda, bu durum gstericinin kendisinin const olduu anlamna geliyordu.
intx;
int*constptr=&x;
int&constr=x;

//Geersiz!

Yukardaki r isimli referansn tanm geersizdir. nk referanslar zaten tanmlar gerei


yalnzca belirli bir nesnenin yerine gemek zere yaratlr. Yani bir referans, zaten bir
nesne ile ilkdeerini aldktan sonra artk baka bir nesnenin yerine geemez. Referanslar
bu anlamlaryla zaten kendileri const nesnedir. Dolaysyla, const anahtar szcnn
yukardaki biimde kullanlmasna gerek yoktur.
const bir nesne adresinin, ancak gsterdii yer const olan bir gstericiye atanabileceini
anmsayn:

C++ Kitabi (24/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


constintx=10;
int*p1=&x;
//Geersiz
constint*p2=&x;
//Geerli
Benzer ekilde, const olmayan bir referans const bir nesnenin yerine geemez. const bir
nesnenin yerine ancak const bir referans geebilir.
constintx=10;
int&r1=x;
//Geersiz!
constint&r2=x; //Geerli

const Referanslar Neden Kullanlr


Gsterdii yer const olan gstericiler ne amala kullanlyorlarsa, const referanslar da ayn
amala kullanlr. const referanslar ile bunlarn balandklar nesneler deitirilemez. Byle
referanslar, yalnzca okuma amacyla nesnelerin yerine geer.

Referanslarn Parametre Deikeni Olarak Kullanlmas


C++da referanslar genellikle ilev tanmlamalarnda parametre deikeni olarak
kullanlr. Parametre deikeni referans olan ilevler, ayn trden bir nesne ile
arlmaldr. Byle bir ar sonucunda parametre deikeni olan referans argman olan
nesnenin yerine geer:
#include<iostream>
voidfunc(int&r)
{
r=20;
}
intmain()
{
inta=10;
func(a);
std::cout<<a<<std::endl;
return0;
}
Parametre deikenlerinin ilev arldnda otomatik olarak yaratldn hatrlayalm.
rnein func isimli ileve
func(a);
biiminde yaplan ar ile aslnda a deikeni, func isimli ilevin referans parametresine
ilkdeer olarak atanr. Yani ileve yaplan ar ile parametre deikeni olan r referans a
deikeninin yerine geer. func ilevine gnderilen a deikeninin kendisidir.
Aslnda derleyicinin rettii kod sz konusu olduunda, gerekte bir adres aktarm
yaplmaktadr. Parametresi referans olan bir ilevin bir adres bilgisiyle deil, bir nesnenin
kendisiyle arldna dikkat edin. ar bu biimde yaplsa da aslnda bir adres aktarm
sz konusu olur.
Aadaki rnei inceleyin:
#include<iostream>
usingnamespacestd;
C++ Kitabi (25/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidswap(int&a,int&b)
{
inttemp=a;
a=b;
b=temp;
}

intmain()
{
intx=10;
inty=20;
cout<<"x="<<x<<endl;
cout<<"y="<<y<<endl;
swap(x,y);
cout<<"x="<<x<<endl;
cout<<"y="<<y<<endl;
return0;
}

Burada swap isimli ilev iki deikenin deerini takas eder. lev
swap(x,y);
biiminde arlyor. swap ilevinin parametre deikenleri olan referanslar x ve y
nesnelerinin yerine geer. phesiz, ileve aslnda x ve y deikenlerinin adresleri
aktarlmaktadr. lev iinde kullanlan a aslnda x in, b ise ynin yerine geer. Yukardaki
programn gsterici deikenlerle oluturulmu edeer C karl da yledir:
#include<iostream>
usingnamespacestd;
voidswap(int*a,int*b)
{
inttemp;
temp=*a;
*a=*b;
*b=temp;
}
intmain()
{
intx=10;
inty=20;
cout<<"x="<<x<<endl;
cout<<"y="<<y<<endl;
swap(&x,&y);
cout<<"x="<<x<<endl;
cout<<"y="<<y<<endl;
return0;
C++ Kitabi (26/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


}

const Referans Parametreli levler


Bir ilevin parametresi const referans da olabilir. Byle bir ilev bir nesne zerinde
deiiklik yapmayan, yalnzca o nesnenin deerini kullanan bir ilevdir.
voidaccess(constT&r);
Yukarda bildirimde yer alan T isminin, bir tr bilgisi olduunu dnelim. access isimli
ilev, T trnden bir nesne zerinde ilem yapabilir, ama sz konusu nesneyi
deitiremez. access ilevi T trnden bir nesnenin yalnzca deerinden faydalanr.
voidmutate(T&r);
mutate isimli ilev de T trnden bir nesne zerinde ilem yapar ama sz konusu nesneyi
deitirebilir. Szdizim kurallar asndan bakldnda phesiz mutate ilevinin
kendisine gelen T trnden nesneyi deitirmesi konusunda bir zorunluluk yoktur. Ancak
byle bir ilevin kendisine gelen nesneyi deitirecei kabul edilmelidir. Eer nesneyi
deitirmeseydi ilevin parametresi const olarak seilirdi.
Bu durumda unu da syleyebiliriz: Bir ilev referans yoluyla adresini ald nesne
zerinde bir deiiklik yapmayacak ise, ilevin parametresi const referans yaplmaldr.
Bir ilevin parametresi const olmayan bir referans ise ve ilev ald nesne zerinde
deiiklik yapmyor ise, bu durum bir programlama hatas olarak deerlendirmelidir.
levin arayzn yani bildirimini gren programclar, ilevin gnderilen nesne zerinde
deiiklik yapacan dnrler.

Yap Nesnelerinin Referans Yoluyla levlere Geirilmesi


Bir yap nesnesinin bir ileve iki ekilde geirilebileceini biliyorsunuz.
1. Yap nesnesinin deerinin geirilmesi durumu (call by value). Bu durumda ilevin
parametre deikeni bir yap deikenidir. lev baka bir yap deikenin kendisi ile
arlr. Ayn trden iki yap deikeni birbirine atanabildiine gre, bu ar biimi de
geerlidir. Aadaki rnei inceleyin:

C++ Kitabi (27/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include<iostream>
structPerson{
charname[30];
intno;
};
voiddisplay_person(Persony)
{
std::cout<<y.name<<'\n'<<y.no<<std::endl;
}
intmain()
{
Personper={"NecatiErgin",123};
display_person(per);
return0;
}
Bu tr bir aktarmda, yapnn karlkl elemanlar birbirlerine blok olarak kopyaland iin
greli bir zaman kayb sz konusudur. Bu nedenle bu tr aktarm biimi C dilinde kt bir
teknik olarak kabul edilir ve pek kullanlmaz. Tabii ok kk yap nesnelerinin bu biimde
aktarlmas sz konusu olabilir. lev deerle arld iin, yani ilev ar ifadesindeki
argman olan yap nesnesi ilevin parametre deikenine kopyalanarak aktarld iin, bu
yolla argman olan yap nesnesinin ilev tarafndan deitirilebilmesi olas deildir.
2. Yap nesnesinin adresinin ileve geirilmesi durumu (call by reference). Bu durumda
ilev yap deikenin adresi ile arlr. levin parametre deikeni de ayn trden bir yap
gstericisi olur. Bu aktarm biiminde yap nesnesi ne kadar byk olursa olsun gerekte
aktarlan tek bir adres bilgisidir. lev tanm iinde adresi alnan yap nesnesinin
elemanlarna erimek iin parametre deikeni olan gsterici -> ilecinin terimi olur. Yap
deikenleri ounlukla ilevlere bu biimde geirilir. Aadaki rnei inceleyin:
voiddisplay_person(constPerson*ptr)
{
std::cout<<ptr>name<<'\n'<<ptr>no<<std::endl;
}
intmain()
{
Personper={"NecatiErgin",123};
display_person(&per);
return0;
}
Madem C++ dilinde referanslar bir eit gstericidir, o halde yaplarn da verimli bir
biimde referans yntemiyle aktarmlar da sz konusu olabilir. Byle bir aktarm
biiminde, ilev yap nesnesinin kendisiyle arlr. levin parametre deikeni ayn yap
trnden bir referans olur. Byle bir arda ilevin parametre deikeni olan referans,
ileve argman olarak gnderilen yap nesnesinin yerine geer. Peki ilev iinde yap
nesnesinin elemanlarna nasl eriilir? Nokta ileci ile mi, ok ileci ile mi? Evet nokta ileci
ile. nk artk yap referans kullanldnda, referans dardan gnderilen nesnenin
yerine geeceine gre parametre olan referans dardan gnderilen yap nesnesinin
yerine geer. Yani referansn kullanm bir adres belirtmez. O nedenle yap referans ile
yap elemanlarna eriimde nokta ileci kullanlr. Aadaki rnei inceleyin:
C++ Kitabi (28/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

#include<iostream>
usingnamespacestd;
structPerson{
charname[30];
intno;
};
voiddisplay_person(constPerson&r)
{
cout<<r.name<<'\n'<<r.no<<endl;
}
intmain()
{
Personper={"NecatiErgin",123};
display_person(per);
return0;
}

levin Parametre Deikeni Gsterici mi Referans m Olmal


C++ dilinde argman aktarmnda gsterici mi yoksa referans m kullanlmaldr? Nesne
ynelimli programlama sz konusu olduunda, gsterici kullanmak yerine mmkn
olduu kadar referans kullanmak gerektii sylenebilir. Bir ok programc u ilkeyi
benimser:
"Kullanabildiin her yerde referans kullan, ancak zorunlu olduun yerde gsterici kullan!"
(use references wherever you can, use pointers when you have to!).
Ancak C++ dili yalnzca nesne ynelimli programlama teknii ile program yazmak iin
kullanlmak zorunda deildir. C++ ile phesiz "prosedrel" programlama teknii
kullanlarak da program yazlabilir. Eer amacnz C++ daha iyi bir C olarak kullanmak ve
prosedrel programlama teknii ile program yazmak ise, makina dzeyinde olanlar daha
iyi betimledii iin gsterici kullanmay tercih edebilirsiniz.
C++da, a bir nesne olmak zere aadaki gibi bir ilev arsnn yapldn dnelim:
func(a);
Argman olan ifadede a nesnesinin ismi yazlmtr. Bu durumda iki olaslk sz
konusudur:
1. levin parametre deikeni ayn trden bir nesnedir. Bu durumda derleyici argman
olan nesnenin deerini parametre deikenine kopyalayacak bir kod retir. rnein:
voidfunc(intval)
{
val=20;
}
intmain()
{
inta=5;
func(a);
return0;
C++ Kitabi (29/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


}
Yukardaki rnekte a deikeninin deeri, ilev arldnda yaratlan, parametre
deikeni vale kopyalanr. Bu yzden func isimli ilevde yaplan
val=20;
atamasnn main ilevinin as ile bir ilgisi yoktur. Atama func ilevinin parametresi olan
val deikenine yaplr. func deerle arlan (call by value) bir ilevdir.
2. levin parametre deikeni ayn trden bir referanstr. Bu durumda gizli bir adres
aktarm sz konusudur. Yani derleyici, ar ifadesinde argman olarak kullanlan
nesnenin adresini arlan ilevin referans parametresine kopyalayacak bir kod retir.
#include<iostream>
usingnamespacestd;
voidfunc(int&r)
{
r=20;
}
intmain()
{
inta=5;
func(a);
cout<<"a="<<a<<endl;
return0;
}
r=20
atamasyla gerekte main ilevi iinde tanmlanan a deikeni deitirilir. func isimli
ilevin iinde kullanlan r a nesnesinin yerine geer. Bu durumu, a nesnesinin kendisinin
func ilevine gnderilmesi olarak grebilirsiniz.
C++da bir ilevin
func(a);
biiminde arldn gren programc, eer ilevin tanmn ya da bildirimini grmemise
standart Cdeki alkanlkla ilevin a deikenini deitiremeyeceini dnerek yanl bir
fikir edinebilir. Nesnenin deerinin mi, yoksa adresinin mi kopyalanacann net olarak
bilinmemesi baz durumlarda okunabilirlii azaltabilir. Bu durumu engellemek iin referans
kullanmna dikkat edilmelidir.
Ancak Nesne Ynelimli Programlama Teknii (NYPT), programn programlama dilinin
alma dzleminde deil de, problemin kendi dzleminde yazlmasn hedefler. Bu
durumda nesne ynelimli olarak yazlm bir programda, program okuyan a nesnesinin
deerinin mi adresinin mi ileve gnderildiini merak etmez, func ilevinin problem
dzlemindeki anlamyla ilgilenir. Yani C dilinde okunabilirlik asndan bir eksiklik olarak
grnen bu durum C++ dilinde bir eit veri saklama" (information hiding) olarak
grlr. C programclarnn C++a geite karlatklar temel zorluklardan biri budur. C
dili ile programlamada, genel ilke ortada gizliliin bulunmamasdr. Ancak C++ dilinin
C++ Kitabi (30/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


NYPT iin kullanlmasnda durum byle deildir. nk ana ama problemin kendi
dzlemine yaklamaktr. Program yazan, program hakknda dnrken programlama
dilinin aralar ile deil de, programn yazlma amac olan problemin paralar ile dnr.
Parametrenin deitirilmeyecei durumlarda referans kullanlabileceinden sz ettik.
Madem byle bir deitirme sz konusu deil, o halde okunabilirlii artrmak amacyla
referans da const olarak tanmlanmaldr.

Referanslar ile Gstericilerin Benzerlikleri ve Farkllklar


Hem gsterici deikenler hem de referanslar adres bilgileri tutan nesnelerdir. Ancak
gsterici deikenler kullanldnda ilerindeki adres bilgisi ele alnd halde, referans
kullanldnda artk referansn baland nesne ele alnr. Aadaki kodlar inceleyelim:
#include<iostream>
intmain()
{
inta[10]={1,2,3,4,5,6,7,8,9,10};
int*p=&a[0];
//int*p=a;

*p=10;
++p;
*p=20;
std::cout<<a[0]<<""<<a[1];
return0;
}
imdi de aadaki kodu inceleyelim:
#include<iostream>
usingnamespacestd;
intmain()
{
inta[10]={1,2,3,4,5,6,7,8,9,10};
int&r=a[0];

r=10;
++r;
r=20;
cout<<a[0]<<""<<a[1];
return0;
}
Referanslar tek bir elemann adresine ilikindir. Bir referansa adres ilkdeer verilirken
yerletirilir. Daha sonra bu adres bilgisi deitirilemez. rnein:
inta=10;
intx=20;
int&r=a;
r=x;
ilemleri yapldnda, x deeri referansa deil, referansn yerine getii nesneye yani aya
aktarlr. Referanslar arka planda kendisi const olan gsterici deikenlere karlk gelir.

C++ Kitabi (31/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Oysa bir gsterici deiken eer kendisi const deilse program iinde dinamik olarak
farkl nesneleri gsterebilir.
Bir diziyle ilgili genel ilem yapan ilev tanmlanabiliyordu. Byle ilevlere dizinin
balang adresi ve boyutu argman olarak gnderiliyordu. Dizinin balang adresini
ileve gndermek iin gsterici kullanyordu. Peki, byle bir ilevin parametresi bir
referans olabilir mi? Hayr! referanslarla bu i gstericilerle olduu gibi yaplamaz. Ancak,
rnein 10 elemanl int trden bir diziyi gsteren gsterici olduu gibi 10 elemanl int
trden bir dizinin yerine geecek bir referans da tanmlanabilir. Aadaki kodu inceleyin:
#include<iostream>
usingnamespacestd;
voiddisplay(int(&r)[10])
{
intk;

for(k=0;k<10;++k)
cout<<r[k]<<"";
cout<<endl;
}
intmain()
{
inta[10]={1,2,3,4,5,6,7,8,9,10};

display(a);

return0;
}
Referanslar daha ok, tek bir nesneyi adres yntemiyle ileve geirmek amacyla
kullanlabilir. rnein tek bir int deer ya da tek bir yap deikeni referans yoluyla ileve
geirilebilir. Ancak int trden bir dizi ya da bir yap dizisi bu yntemle ileve doal bir
biimde geirilemez.
Szdizimsel adan referanslarn gstericilere gre kullanm alanlar daha dardr. Gsterici
dizileri olur ama referans dizileri olamaz. Gstericileri gsteren gstericiler olabilir ama
referanslarn yerine geen referanslar olamaz.
Ancak phesiz bir gstericinin yerine geen bir referans olabilir. Aadaki kodu
inceleyin:
#include <iostream>
int main()
{
int x = 10;
int *ptr = &x;
int *&r = ptr;
*r = 20;
std::cout << "x = " << x << std::endl;
}

return 0;

C++ Kitabi (32/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


lev gstericileri olduu gibi ilev referanslar da olabilir. lev referanslarn ileride
ayrntl olarak inceleyeceiz.

NULL Adresi ve Referanslar


Deeri NULL adresi olan bir gsterici deiken hibir yeri gstermeyen bir gsterici
deikendir. NULL adresinin Cde ne kadar yaygn bir biimde kullanldn biliyorsunuz:
Bir ilev bir adrese geri dndnde baarszlk belirtmek amacyla NULL adresine geri
dnebilir. rnein standart bir C ilevi olan strchr ilevinde bir yaz iinde bir karakter
arar. Aranan karakteri yazda bulursa, bulduu yerin adresi ile bulamazsa NULL adresi ile
geri dner.
Dardan adres alan bir ileve zel bir bilgi iletmek amacyla NULL adresi geilebilir.
rnein standart time ilevi kendisine NULL adresi gnderilirse takvim zaman deerini
yani time_t trnden deeri bir adrese yazmaz yalnzca geri dn deeri olarak retir.
NULL adresi bir gsterici iin bir bayrak deeri olarak kullanlabilir. rnein bir kontrol
deyiminde bir gstericinin deerinin NULL adresi olup olmamasna gre farkl iler
yaplabilir.
Oysa hi bir nesnenin yerine gemeyen bir referans tanmlanamaz. Bir referans
tanmland zaman bir nesnenin yerine gemelidir.
C++da referanslarn eklenmesiyle gstericilere olan gereksinim tamamen ortadan
kalkmamtr. Ancak zellikle "Nesne Ynelimli Programlama Teknii"nin kolay ve doal
bir biimde uygulanmas referans kullanmn gerektirir.

Referanslar zerinde Adres lemleri


Bir referansn adres ileci ile adresi alnabilir. Bu durumda referansn yerine getii
nesnenin adres deeri elde edilir. rnein:
#include<iostream>
intmain()
{
inta=10;
int&r=a;
int*p=&r;
*p=20;
std::cout<<"a="<<a<<std::endl;
return0;
}
ilemlerini inceleyin. Burada:
p=&r;
deyiminde referans adres ilecinin terimi olmutur. Bu durumda referansn yerine getii
nesnenin adresi deeri elde edilir. rneimizde bu adres aslnda a deikeninin adresidir.
Elde edilen adresin referans tr ile ayn trden olduuna dikkat edin. Nihayet,
*p=20;
ile aslnda a nesnesine 20 deeri atanr.
Yukardaki program parasnn gsterici deikenlerle oluturulmu edeer C karl da
yledir:

C++ Kitabi (33/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include<iostream>
intmain()
{
inta=10;
int*p=&a;
int*ptr=&*p;
*ptr=20;
std::cout<<"a="<<a<<std::endl;
return0;
}

Referanslara Farkl Trden Bir Nesne ile lkdeer Verilmesi


Durumu
Bir referansn ayn trden bir deikenle ilkdeer verilerek tanmlanmas gerektiini
belirtmitik. Referansns farkl trden bir deikenle ilkdeer verilerek tanmlanmas
geersizdir. Aadaki rnei inceleyin:
voidfunc
{
doubled=10.5;
int&r=d;
//Geersiz
//...
}
Ancak const bir referansa baka trden bir nesne ile ilk deer verilmesi geerlidir:
voidfunc()
{
doubled=10.5;
constint&r=d;
//...
}

//Geerli

Bu durumda nce const referansa balanan farkl trden nesnenin deeri, referansn
trnden yaratlacak geici bir nesneye atanr. Referans da bu geici nesneye balanr.
Yani derleyici aadaki gibi bir kod retir:
intmain()
{
doubled=10.5;
inttemp=(int)d;
constint&r=temp;
return0;
}

Referanslara Deimezlerle lkdeer Verilmesi


Bir referansa bir deimez ile ilk deer verilmesi de geersizdir. Ancak bir const referansa
bir deimez ile ilk deer verilebilir:
int&r=10;
constint&r=10;

//Geersiz!
//Geerli

C++ Kitabi (34/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Bu durumda derleyici nce geici bir nesne yaratr. Geici nesneye deimezi atar,
referans geici nesneye balayan bir kod retir. Yukardaki atamada aslnda geri planda
unlar yaplr:
inttemp=10;
//geicinesne10de?eriileyaratlyor.
constint&r=temp;
//rreferansgeicinesneyeba?lanyor.

Referansa Geri Dnen levler


levlerin geri dn deerlerinin derleyici tarafndan nce geici bir blgeye alndn,
buradan ekilerek kullanldn anmsayn. rnein:
x=func();
gibi bir arda, nce func isimli ilev arlr. levin geri dn deeri geici bir nesnede
saklanr. Daha sonra bu geici nesneden ekilerek kullanlr:
Bunu kaba kod olarak aadaki biimde gsterebiliriz:
temp=returnifadesi;
x=temp;
Aslnda ilevin geri dn deerinin tr, bu geici nesnenin trn belirtir.
doublefunc()
{
//
returnifade;
}
rnein yukardaki func isimli ilevin geri dn deerinin yerletirilecei geici blge
double trdendir. Yani aslnda return deyimi ile bu geici nesneye ilkdeer verilmesi sz
konusudur.
levin geri dn deerinin referans olmas geici blgenin referans olmas anlamna
gelir. Bu durumda return ifadesi bir referansa ilk deerini verir, deil mi? Aadaki rnei
inceleyin:
#include<iostream>
intx=10;
int&func()
{
returnx;
}
intmain()
{
func()=20;
std::cout<<"x="<<x<<std::endl;
return0;
}
Burada geici blge int trden bir referanstr. Yani aslnda return deyimiyle yaplan:
int&temp=x;

C++ Kitabi (35/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


gibi bir ilemdir. Bu durumda geici nesne olan referans x nesnesine balanr. Bylece
ilev ar ifadesi artk bir nesne belirtir duruma gelmitir. Bu durumda
func()=20;
atamas gerekte global x deikenine yaplm olur.
Geri dn deeri bir referans olan ilevlerin, kendilerini aran kod parasna, dorudan
bir nesnenin kendisini ilettiini dnebilirsiniz. Byle ilevlere yaplan ar ifadeleri
nesne belirtir. Yani sol taraf deeri olarak kullanlabilirler. Geri dn deeri referans olan
ilevlerin ar ifadeleri return ifadesi ile belirtilen nesne anlamna gelir. Byle ilevlerin
return ifadelerinin de ayn trden bir nesne belirtmelidir.
Yukardaki programn gsterici deikenlerle oluturulmu karl aadaki gibi olur:
#include<iostream>
intx=10;
int*func()
{
return&x;
}
intmain()
{
*func()=20;
std::cout<<"x="<<x<<std::endl;
return0;
}
Her iki program iin retilecek makina kodlar tamamen edeerdir. Geri dn deeri
referans olan ilevlerin aslnda adresle geri dndn ama bu adres yoluyla ieriklerinin
alnarak kullanldn grebiliyor musunuz?
Yukardaki programda
*func()=20;
deyimini inceleyelim. Bu ifadede ile vardr. nce ilev ar ileci ele alnr, func ilevi
arlr. Bu ilev bir adres deeri dndrr. Daha sonra * ileciyle bu adresteki nesneye
eriilir. Eriilen nesne x nesnesinin kendisidir. Nihayet atama ileciyle 20 deeri ilevin
adresini dndrd nesneye, yani x deikenine atanr.

Referansa Geri Dnen lev Yerel Nesne le Geri Dnmemeli


Yukardaki rnekte x deikeni yerel olabilir miydi? Referansa geri dnen bir ilevin yerel
bir nesne ile geri dnmesi, adrese geri dnen bir ilevin yerel bir deikenin adresi ile
dnmesine edeer bir yanllktr. Yani bir gsterici hatasdr. levin geri dn deeri ile
kendisine aran kod parasna ilettii yerel nesnenin mr, ilevin kodunun
yrtlmesinin tamamlanmasyla sona erer. Ancak bu durum derleme zamannda bir hata
oluumuna neden olmaz. Derleyicilerin ou bu durumu mantksal bir uyar iletisi ile
bildirir.

Referanslar Neden Kullanlr

C++ Kitabi (36/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Referanslar temel olarak adres ilemlerinin daha yaln bir yazm biimiyle ifade edilmesi
amacyla kullanlr. rnein bir ilevin parametre deikeni gsterici yerine referans olsa,
ilev iinde adres yardmyla nesneye eriilecei zaman * ya da -> ilecini kullanmak
gerekmez. Bylece ifadeler daha yaln bir biimde yazlabilir. & ya da * ilecinin
kullanlmas programn yazmn programlama dilinin dzlemine yaklatrrken, problemin
kendi dzleminden uzaklatrc bir etki yapar.
Adres ya da ierik ilecinin kullanlmamas retilen makina kodunda bir klme
yaratmaz. nk derleyici referans yoluyla yaplan eriimleri tpk gstericilerde olduu
gibi yine adres ilemleriyle gerekletirir. Bunun dnda C++ dilinde nesne ynelimli
programlama tekniinin uygulanabilmesi iin eitli biimlerde referans trne gereksinim
duyulmutur. Yani referanslar C++da ileride greceimiz pek ok konunun uygulamas
iin gerekmektedir.

C++ Kitabi (37/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

PARAMETRE DEKENLERNE VARSAYILAN


DEERLERN AKTARILMASI
Cde bir ilevin ka tane parametre deikeni varsa ileve o kadar argman geilmelidir.
Oysa C++da bir ilev, parametre deikeni saysndan daha az sayda argmanla
arlabilir. Bir ilevin bir ya da birden fazla parametre deikeni varsaylan argman
(default argument) alabilir. Bunun anlam udur: lev ars ile ilevin parametre
deikenine bir deer aktarlmaz ise otomatik olarak daha nceden belirlenmi bir deer
aktarlr.
Bir parametre deikeninin nceden belirlenmi bir deer alaca ilevin bildiriminde ya
da ilevin tanmnda, parametre deikeninden sonra eittir (=) ilecinden yazlan bir
ifadeyle belirtilir. Aadaki rnei inceleyin:
#include<iostream>
voidfoo(intx=10,inty=20);
voidfoo(intx,inty)
{
std::cout<<"x="<<x<<'\t'<<"y="<<y<<std::endl;
}
intmain()
{
foo();
foo(100);
foo(100,200);

//x=10 y=20
// x=100 y=20
// x=100 y=200

return0;
}
foo ilevinin bildiriminde varsaylan argmanlar kullanlyor. main ilevi iinde yaplan ilk
arda foo ilevine hi bir argman gnderilmiyor. Bu durumda parametre deikenleri
olan x ve yye varsaylan deerler olan 10 ve 20 deerleri aktarlr. main ilevi iinde
yaplan ikinci arda, foo ilevine yalnzca 100 deeri gnderiliyor. Bu durumda birinci
parametre deikenine 100 deeri kopyalanrken, ikinci parametre deikenine varsaylan
deer olan 20 deeri kopyalanr. foo ilevine yaplan nc arda ise ileve 100 ve 200
deerleri gnderiliyor. Bu durumda, parametre deikenlerinden hibiri varsaylan bir
deer almaz. Grld gibi varsaylan deerler ilev arlrken ileve gnderilmeyen
deerlerdir.
Daha soldaki parametre deikenlerine ilev arsyla argman gnderilip, daha sadaki
dier argmanlar yazlmadan ilev arlrsa varsaylan deerler kullanlabilir. Ancak
bunun tersi geerli deildir. Aadaki ar biimi her durumda geersizdir:
foo(,10);
Bir parametre deikeni iin varsaylan bir deer belirlenmise, bu parametre
deikeninin daha sanda bulunan parametre deikenlerinin hepsi varsaylan deerler
almak zorundadr:
voidfunc(intx=10,inty);
voidfoo(intx,inty=20);

//Geersiz!
//Geerli

Varsaylan deer almam olan btn parametre deikenlerine ar ifadesi ile gereken
argmanlar gnderilmek zorundadr.
C++ Kitabi (38/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Bir ilevin parametre deikeni olan gsterici de varsaylan deer alabilir. Aadaki
rnei inceleyin:
#include<iostream>
voidput_message(constchar*p="Success!")
{

std::cout<<p;
}
intmain()
{
put_message("Failed!");
put_message();
return0;
}
Yukardaki programda put_message isimli ilevin gsterici olan parametre deikeni p iin
varsaylan argman olarak "Success!" dizgesi geiliyor. main ilevi iinde yaplan ilk
arda, ileve "Failed!" dizgesi argman olarak geilirken, ikinci arda ileve herhangi
bir argman gnderilmiyor. Yaplan ikinci aryla ekrana "Success!" yazs yazdrlr.
Varsaylan argman olarak belirlenen ifade, bir deimez ifadesi olmak zorunda deildir.
Deiken ieren ifadeler de varsaylan argman olarak kullanlabilir. Varsaylan argman
olarak kullanlan ifadelerde daha nce bildirimi yaplm global deikenler
kullanlabilecei gibi ilev arlar da yer alabilir.
intfunc1();
intfunc2(int);
intfunc3(double=3.14);
intg=10;
intfunc4(inta=func1(),intb=func2(g),intc=func3());
Yukarda yaplan tm ilev bildirimleri geerlidir. func4 ilevinin her parametresi de
varsaylan argman alyor. Birinci parametre olan a deikenine, ilev ar ifadesi ile bir
deer atanmaz ise, func1 ilevinin geri dn deeri atanr. kinci parametre deikeni
olan b'ye bir deer geilmez ise, func2 ilevinin geri dn deeri atanr. Bu arada
arlan func2 ilevine, global deiken olan g deikeninin deeri geilir. Son parametre
deikenine deer geilmedii zaman ise, bu parametre deikenine func3 ilevinin geri
dn deeri atanr ki, arlacak func3 ilevi de kendisine argman gnderilmedii iin
varsaylan deer olarak belirlenen 3.14 deerini alr.
Varsaylan argmanlara ilikin ifadelerin deerlendirilmesi ilevin arld noktada
gerekleir. Yani func4 ilevi eer arlmaz ise func1, func2 ve func3 ilevleri de
arlmaz.
Varsaylan argman olarak belirlenen deer yalnzca bir kez yazlmaldr. Ayn kaynak
dosyada varsaylan argmann ikinci bir bildirimde yeniden yazlmas geersizdir.
Aadaki rnei inceleyin:
///////file1.h
intfunc(inta,intb,intc=0);
///////file2.h
#includefile1.h"
intfunc(inta,intb,intc=0);

//Geersiz

C++ Kitabi (39/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Ancak ikinci kez yaplan bildirimde, bu kez daha nce varsaylan argman belirlenmemi
bir parametre deikeni iin varsaylan deer bildirilebilir. Tabii yine bu durumda daha
sada kalan tm parametre deikenleri iin mutlaka daha nce varsaylan deerlerin
belirlenmesi gerekir. file2.h dosyas aadaki gibi olsayd, derleme zamannda bir hata
olumazd:
///////file2.h///////////////////////////
#include"file1.h"
intfunc(inta,intb=1,intc);
intfunc(inta=2,intb,intc);
Varsaylan argman olarak belirlenen deerler yalnzca bir kez yazlmaldr. Bu deerler
ilevin arayznn bir parasdr. Doal olan varsaylan argmanlarn ilev bildiriminde
belirtilmesidir. Varsaylan argman deerin hem ilev bildiriminde, hem de ilev tanmnda
yer almas geersizdir:
voidfunc(intx=10,inty=20);
voidfunc(intx=10,inty=20)
{
}

//Geersiz.

Hatrlayacanz gibi, ilev bildirimlerinde parametre deikenlerinin isimleri yazlmak


zorunda deildir. Varsaylan bir deer alacak parametre deikeni iin de isim yazlmas
zorunlu deildir. Aadaki iki bildirim de geerlidir:
voidfunc(inta=10,intb=20);
voidfunc(int=10,int=20);
Ancak ilevin varsaylan deer alacak parametre deikeni bir gsterici ise ve ilev
bildiriminde parametre deikeni olan gstericiye isim verilmiyorsa dikkatli olunmaldr:
voidfunc(char*="Ahmet");

//

Geersiz!

Derleyici burada *= karakterlerini tek bir atom olarak ele alp ilemli atama ileci olarak
deerlendirir (En uzun atom kural - maximum munch). Bildirim geersizdir. Bu durumda
varsaylan argmana ilikin bu iki karakter bitiik yazlmamaldr:
voidfunc(char*="Ahmet");
Gsterici parametre deikenleri varsaylan argman alabildii gibi, referans parametre
deikenleri de varsaylan deerler alabilir:
#include<iostream>
intg=20;
voidfunc(int&r=g);
intmain()
{
inty=30;
func();
func(y);
return0;
}
C++ Kitabi (40/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

voidfunc(int&r)
{
std::cout<<r<<std::endl;
}

Varsaylan Argmanlar Neden Kullanlr?


Baz ilevlerin ok sayda parametre deikeni vardr. zellikle byle ilevler sz konusu
olduunda ve bu parametre deikenlerinin belli blmne ileve yaplan arda
ounlukla ayn deerler gnderiliyorsa, varsaylan argmanlarn kullanlmas byk bir
yazm kolayl salar. leve gnderilen argman saysnn azaltlmas hem programcnn
i ykn azaltr, hem de kodun okunabilirliini arttrr.
Parametre deikenleri iin varsaylan argman belirlenirken dikkat edilmelidir. Bir ilev
ounlukla ayn argman deerleriyle arlyorsa varsaylan argman alan parametre
deikeni kullanlabilir. Bir rnek verelim:
Standart olmasa da, C derleyicilerinin ounda stdlib ktphanesi iinde itoa isimli bir
ilev bulunur. lev verilen bir tamsay deerini verilen bir say sisteminde bir yazya
dntrerek, adresini ald bir diziye yazar:
char*itoa(int,char*,int);
levin
levin
levin
levin

birinci parametresi yazya dntrlecek deerdir.


2. parametresi yaznn yerletirilecei adrestir.
3. parametresi dnmn yaplaca say sistemidir.
geri dn deeri yaznn yerletirildii adrestir.

itoa ilevi ounlukla bir tamsayy onluk say sistemine gre oluturulmu bir yazya
dntrmek iin kullanldndan, ilevin nc parametresine ounlukla 10 deeri
geilir. imdi ayn ii yapan ancak varsaylan argman alan itoa_d isimli bir ilev yazalm:
#include<iostream>
#include<cstdlib>
char*itoa_d(intn,char*str,intbase=10)
{
returnitoa(n,str,base);
}
intmain()
{
chars[100];

itoa_d(123,s);
std::cout<<s;

return0;
}
Yazlan itoa_d isimli ilevin base isimli parametre deikeninin varsaylan argman alarak
10 deeri aldn gryorsunuz. lev iki argmanla arlrsa nc parametre olan
base isimli parametre deikenine 10 deeri geilir. levin kendi iinde itoa ilevini
ardn gryorsunuz. itoa ilevi bu durumda varsaylan argman alan itoa_d isimli
ilevi tarafndan sarmalanmtr.
Varsaylan argmanlar "Hibir deer almayacana bari u deeri alsn" fikriyle
kullanlmamaldr. Bylesi kullanmlar kaynak kodu inceleyen kiiyi yanltr.
Bazen parametre deikenine verilen varsaylan deerin zel bir anlam olmaz. Bu
varsaylan deer yalnzca ilevin varsaylan argmanla arlp arlmadn saptamak
C++ Kitabi (41/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


amacyla kullanlr. Gerek varsaylan deerler ilevin iinde ve bir dizi ilemle elde
edilebilir. Aadaki rnei inceleyin:
#include<cstdio>
#defineDEFAULT_CALL(1)
voidwrite_file(constvoid*ptr,unsignednbytes,FILE*fp,longoffset=
DEFAULT_CALL)
{
if(offset!=DEFAULT_CALL)
fseek(fp,offset,SEEK_SET);
fwrite(ptr,1,nbytes,fp);
}
intmain()
{
doubled=10.2;
FILE*f;
/*...*/
write_file(&d,sizeof(double),f);
/*...*/
return0;
}
write_file isimli ilevin tanmn inceleyelim: lev birinci parametresine geilen adresten
balayarak nbytes kadar byte' bir dosyaya yazar. levin offset isimli son parametresine
bir ofset deeri geilirse, ilev dosya konum gstericisini bu ofset deerine konumlandrr
ve yazma ilemini bu konumdan balatr. levin son parametresine bir deer geilmez
ise, yazma ilemi dosya konum gstericisinin gsterdii konumdan balayarak yaplr.

C++ Kitabi (42/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

LEV YKLEMES
C++ dilinde, bir kaynak dosyada ayn isimli birden fazla ilev tanmlanabilir. Nesne
ynelimli programlama tekniinin uygulanmasn kolaylatran bu ara ngilizce'de
"function overloading" (ilev yklemesi) olarak isimlendirilir. u sorulara yant aramakla
balayalm:
Neden iki ya da daha fazla sayda ilevin isimleri ayn olsun? ki ayr ileve ayn isim
vermenin nasl bir faydas olabilir? Bir rnekle balayalm:

Ayn Arayz Farkl lemler


C'nin aadaki standart ilevlerini
intabs(intx);
doublefabs(doublex);
longlabs(longx);
C'nin standart balk dosyalarndan biri olan math.h iinde bildirimleri yer alan yukardaki
ilevlerin hepsi aslnda ayn ilemi yapar. Bu ilevler, kendilerine argman olarak
gnderilen ifadenin mutlak deerini geri dn deeri olarak retir. Bu ilevlerin dardan
aldklar deerlerin trleri farkldr, dolaysyla rettikleri geri dn deerlerinin trleri de
farkldr. C dilinde ayn isimli ilevler tanmlanamayaca iin, bu ilevlere ayr isimler
verilmitir. Bu ilevlerin hepsinin ismi ayn olsayd, rnein hepsinin isimleri abs olsayd,
mutlak deer alma ilemi yapan programcnn, birden fazla ilev ismini bilmesi ya da
anmsamas gerekmezdi, deil mi?
Aslnda dilin temel ilelerini dndnz zaman benzeri bir aracn kullanma hazr bir
biimde sunulduunu grebilirsiniz. Toplama ilecini ele alalm. Toplama ileci ne i yapar?
ki deerin toplanmasn salar, deil mi?
10+20
Yukarda, 10 ile 20 deerlerinin toplama ilecinin terimleri olduunu gryorsunuz.
Toplama ileci bir ilemin yaplmasn salyor, yaplan ilemin sonucunda 30 deeri
retiliyor. imdi de aadaki ileme bakalm:
1,5+3.5
Yukardaki rnekte ise 1.5 ve 3.5 deerlerinin toplama ilecinin terimleri olduunu
gryorsunuz. Toplama ileci yine bir ilemin yaplmasn salyor, yaplan ilemin
sonucunda 5.0 deeri retiliyor. Oysa makina asndan bakldnda, tamsay trnden iki
deerin birbiriyle toplanmasyla, gerek say trnden iki deerin birbiriyle toplanmas
bambaka ilemlerdir. Bize ok doal grnen bu iki rnekte yaplan ilemi, aslnda
ayrntlarndan soyutlayarak "toplama" olarak ifade ediyoruz. Matematikte olduu gibi C
dilinde de, bu ilemleri yapmak iin, bir soyutlama kullanlarak, ayn ileler yani ayn
simgeler kullanlyor. ki ilem iin farkl iki simge kullanlm olsayd, alglama bu kadar
kolay olur muydu?
C dilinde ayn isimli ilevlerin bir arada bulunamamasnn nedeni nedir? C derleyicileri, bir
ilev ar ifadesi ile karlatnda, hedef koda (object code) yalnzca arlan ilevin
ismini yazar. rnein Borland derleyicileri, arlan ilevin isminin bana alttire karakteri
ekleyerek oluturduklar ismi hedef koda yazar. Aada bildirimi verilen ilevi rnek
olarak ele alalm:
intfoo(int,int);
Derleyici bu ilevin arlmas durumunda hedef koda

C++ Kitabi (43/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


_foo
gibi bir isim yazar. Oysa foo ilevinin bildirimi farkl olsa da, C derleyicisinin hedef koda
yazaca isim ayn olur. Ayn isimli fakat parametrik yaplar farkl, birden fazla foo ilevi
olsayd, derleyici bu ilevlerin hepsi iin ama kodda ayn ismi kullanrd. Bu durumda da,
balayc program ayn isimli ilevlerden hangisinin arlm olduunu anlayamazd.
C++ dilinde ayn isimli ilevlerin tanmlanabilmesi nasl mmkn oluyor? C++ dilinde
farkl olan nedir?
C++ derleyicisi, bir ilev ar ifadesinin karl olarak hedef koda, C derleyicisi gibi
yalnzca ilevin ismini yazmaz. C++ derleyicisi arlan ilevin ismini, ilevin parametre
deikenlerinin trleri ile birletirerek bir isim oluturur, bu ismi ama koda yazar. Ama
koda yazlmak zere oluturulan bu ismin oluturulma biimi, standartlarca kesin olarak
belirtilmemi, derleyiciyi yazanlara braklmtr. rnein bir C++ derleyicisi yukarda
bildirimi verilen foo ilevini hedef koda aadaki gibi yazabilir:
_foo@i@i
C++derleyicisinin, ilev isimlerinin sonuna @ karakterini izleyecek biimde, parametre
deikeninin trnn ba harfini yazdn varsayalm. Bu durumda
intfoo(double,double);
gibi ikinci bir foo ilevi var olsayd, derleyici bu ilevin ar ifadesi karl hedef koda bu
kez
_foo@d@d
yazard.
Bylece sra balayc programa geldiinde, balayc program ayn isimli birden fazla ilev
olmasna karn, hedef koda yazlan ismi grerek, ayn isimli ilevlerden hangisinin
arlm olduunu anlar.
Ayn isimli ilevlerin var olabilmesi iin gerekli koul da ortaya kyor:
Ayn isimli iki ilevin, ayn bilinirlik alannda var olabilmesi iin, ilevlerin parametrik
yaplarnn farkl olmas gerekir. Ayn isimli ilevlerin parametre deikeni says ve/veya
parametre deikenlerinin trleri bir farkllk gstermelidir. Eer ayn isimli iki ilevin, hem
parametre deikeni says ayn hem de parametre deikenlerinin trleri ayn ise, bu
durumda her iki ilev de hedef koda ayn ekilde yazlacandan, balayc program
yazlan isimlerden, hangi ilevin arlmak istendiini anlayamaz.
Yukardaki aklamalardan, C++derleyicilerinin arlan ilevi hedef koda yazarken
kullandklar ismin oluturulmasnda, ilevin geri dn deeri trnn hibir katks
olmadn anlamalsnz. Bu durumda, imzalar birbirleriyle tamamen ayn, ancak geri
dn deerleri farkl trlerden olan, ayn isimli iki ilev, ayn bilinirlik alannda
bildirilemez. Geri dn deeri tr dnda tm parametrik yaps ayn olan iki ilevin var
olduunu dnelim. Bu isimle bir ilev ars yapldnda, derleyici hangi ilevin
arldn anlayabilir miydi?
intfoo(int);
doublefoo(int);

//Geersiz!

intmain()
{
foo();
return0;
}
Yukardaki her iki bildirim de geerli olsayd, hangi foo ilevinin arld nasl anlalrd?
C++ Kitabi (44/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

levlerin parametre deikenlerinin says ile, her bir parametre deikeninin trn
kapsayan bilgiye ilevin imzas denir. levin geri dn deerinin tr bilgisi, ilevin
imzasnn bir paras deildir.
Ayn bilinirlik alannda ayn isimli iki ya da daha fazla sayda ileve ilikin bildirim varsa,
aadaki durumdan biri sz konusu olur:
i. Hem ilevlerin imzalar tamamen ayn hem de ilevlerin geri dn deerlerinin trleri
ayn ise, derleyici bu durumu, ayn ilevin bildiriminin birden fazla kez yapld biiminde
yorumlar. C'de olduu gibi C++'ta da, bir ilevin bildirimi zde olmas kouluyla birden
fazla yaplabilir:
//ilevbildirimiikikezyaplyor(functionredeclaration)
intfunc(int);
intfunc(int);
ii. Ayn isimli ilevlerin parametik yaplar birbirinden farkl ise, yani ilevlerin imzalar
farkl ise, derleyici bu durumu, ayn isimli fakat farkl ilevlerin bulunduu (function
overloading) biiminde yorumlar. Bu durumda ilevlerin geri dn trlerinin bir nemi
yoktur:
//functionoverloading(?levyklenmesi)
intfunc(int);
intfunc(int,int);
Ayn isimli iki ilevin parametrik yaps, yalnzca ilevin birinde varsaylan argman
kullanlmas biiminde farkllk gsteriyorsa, bu durum yine ilev bildiriminin yinelenmesi
olarak ele alnr:
//ilevbildirimiyineleniyor(functionredeclaration)
intmax(int*ptr,intsize);
intmax(int*,int=10);
iii. levlerin parametrik yaplar tamamen ayn, fakat ilevlerin bildirilen geri dn
deerlerinin trleri farkl ise, bu durumda derleyici, ilev bildiriminin zde olmayan
biimde yinelendii sonucunu kartr. Bu durumu bir szdizim hatas olarak belirler.
//ilevbildirimielikilibiimdeyineleniyor
intfunc(int)
doublefunc(int);

//Geersiz!

typedef bildirimi ile yeni bir tr yaratlm olmaz. typedef bildirimiyle var olan bir tre yeni
bir isim verilebilir. Eer ayn isimli iki ilevde, parametre deikenlerinin trlerinin
yazlmasnda birinde typedef ismi kullanlrken, dierinde trn gerek ismi kullanlm ise
bu durum "ilev yklemesi" olarak kabul edilmez. Aadaki rnei inceleyin:
typedefunsignedcharBYTE;
BYTEfoo(BYTE);
intfoo(unsignedchar);
Yukardaki iki bildirimin bir arada bulunmas geersizdir. Bildirilen her iki ilevin de imzas
ayn, geri dn deerlerinin trleri farkldr.
Peki C++'da, parametrik yaplar birbirlerinden farkl, ayn isimli ilevler
tanmlanabildiine gre, derleyici ayn isimli ilevlerden hangisinin arldn nasl anlar?
C++ Kitabi (45/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Bir ilev arsnn, hangi ileve ilikin olduunun saptanmas ilemine Yklenmi levin
Saptanmas" (function overload resolution) denir.
"Yklenmi ilevin saptanmas", derleyici tarafndan aamada yaplan bir ilemdir.
Birinci aamada, derleyici sz konusu ilev ars iin ele alnacak ayn isimli ilevleri
saptayarak bu ilevlerin parametrik yaps hakknda bilgi edinir. arlmas sz konusu
olan ayn isimli ilevlere "aday ilevler" (candidate functions) denir.
Aday ilevler, ilev ar ifadesinde kullanlan isimle ayn isme sahip olan, ilev ar
ifadesinin bulunduu yerde grlebilen (visible) ilevlerdir.
Birinci aamada derleyici, aday ilevler hakknda gerekli bilgiyi de edinir. Aday ilevlerin
parametre deikeni saylarn, parametre deikenlerinin trlerini renir.
kinci aamada, ilev ar ifadesinde yer alan argmanlar kullanlarak, hangi aday
ilevlerin geerli biimde arlabilecei saptanr. Sz konusu ilev arsyla, geerli
biimde arlabilen ilevlere, uygun ilevler (viable functions) denir.
Bir ilevin uygun ilev olarak belirlenebilmesi iin, aadaki koullar salamas gerekir:
i) lev ar ifadesindeki argman says ile, ilevin parametre deikeni saysnn ayn
olmas zorunludur. lev ar ifadesindeki argman says, ilevin parametre deikeni
saysndan daha az ise, bu durumda ilevin argman gnderilmeyen parametre
deikenleri varsaylan argman almaldr.
ii) Argman olan ifadenin, parametre deikeni olan nesneye uygun bir ekilde
dntrlebilmesi gerekir:
rnek olarak, aada bildirimleri verilen ilevleri inceleyelim:
voidfoo();
voidfoo(int);
voidfoo(double,double=3.4)
voidfoo(char*);

//1
//2
//3
//4

voidfunc()
{
foo(5);
}
func ilevi iinde foo isimli ileve yaplan arnn, ilevlerden hangisine ait olduunun
saptanmas aamalarn inceleyelim:
1. aama
levin arld noktada, tm ilev bildirimleri grlebilir (visible) olduundan bu
aamada, drt ilev de aday olarak belirlenir, parametrik yaplar hakknda bilgi edinilir.
2. aama
1 numaral ilevin parametre deikeni says (0) ile, ilev arsndaki argman says (1)
birbirine eit olmadndan, bu ilev uygun (viable function) olarak ele alnmaz.
2 numaral ilev uygundur. Parametre deikeni ile argman says uyumludur,
argmandan parametre deikenine geerli bir dnm sz konusudur.
3 numaral ilev uygundur. levin iki parametre deikeni vardr. Ancak ikinci parametre
deikeni varsaylan argman ald iin, ilev tek bir argman ile arlabilir. Argman
olan ifade int trden, bu argmann kopyalanaca parametre deikeni double trdendir.
Ancak atama ncesinde int tr, geerli olarak double trne dntrlebilir.

C++ Kitabi (46/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


4 numaral ilev uygun deildir. levin parametre deikeni says ile, ilev arsndaki
argman says birbirine eit olmasna karn, int trden ifade, dilin kurallarna gre char*
trne dntrlemez.
kinci aamada uygun bir ilev bulunmaz ise, ilev ars geersiz kabul edilir. Bu duruma
ngilizcede "no match" durumu (arlacak uygun bir ilevin bulunmamas) denir.
nc aama
nc yani son aamada, uygun ilevler iinde en uygun olan ilev belirlenir. Uygun
ilevler iinden seilerek, ar ifadesi ile elenecek ileve "en uygun ilev" (best viable
function / best match function) denir.
nc aamada, belirli sayda uygun ilev iinden, bir ilevin en uygun ilev olarak
seilebilmesi iin aadaki koullar yerine getirmesi gerekir:
lev ar ifadesindeki argmanlardan ilevin ilgili parametre deikenine yaplan
dnmn derecesi dier uygun ilevlere gre daha kt olmamas gerekir. En az bir
argman iin yaplacak dnmn dierlerine gre daha iyi olmas gerekir.
Birden fazla uygun ilev iinden, en uygun ilevin seilememesi durumunda "ift
anlamllk hatas" (ambiguity) denilen bir hata durumu oluur. Bu durumda, derleyici iin
kurallara uygun olarak arlabilecek birden fazla ilev sz konusudur.
"Argmanlardan parametre deikenlerine yaplacak dnmn derecesi" ne anlama
gelir?
C++ standartlar, argmanlardan parametre deikenlerine yaplabilecek otomatik
dnmleri 4 ayr dereceye ayrmtr.
1.
2.
3.
4.

Tam uyum (exact match)


Ykseltme (promotion)
Standart dnm (standard conversion)
Programcnn tanmlad dnm (user defined conversion)

Kurallara gre, "tam uyum" durumu "ykseltme"den, "ykseltme" durumu standart


dnmden, standart dnm de programcnn tanmlad dnmden daha iyi olarak
kabul edilir.
Yukardaki derecelendirmeleri ayrntl biimde inceleyelim:
1. Tam uyum durumu
Argman olan ifadenin tr ile, bu argmann kopyalanaca parametre deikeni olan
nesnenin tr tamamen ayn ise, bu durum tam uyum (exact match) olarak ele alnr.
Ancak aadaki durumlar da tam uyum olarak ele alnr:
i) Argman olan nesne bir sol taraf deeri, yani bir nesne ise, parametre deikenine
kopyalanacak deerin, bu nesneden alnmas. Bu duruma sol taraf deerinden sa taraf
deerine dnm denir (L-value to R-value transformation).
ii) Parametre deikeninin bir gsterici olmas, ilevin de ayn trden bir dizinin ismi ile
arlmas. Dizi isimlerinin bir ileme sokulduunda, ilem ncesinde otomatik olarak
dizinin ilk elemennn balang adresine dntrldn (array to pointer conversion)
biliyorsunuz.
iii) Parametre deikeninin bir ilev gstericisi (function pointer) olmas, ilevin de ayn
trden bir ilevin ismi ile arlmas. lev isimlerinin bir ileme sokulduunda, ilem
ncesinde otomatik olarak ilev blounun balang adresine dntrldn
biliyorsunuz.

C++ Kitabi (47/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


iv) lev parametre deikeninin, gsterdii yer const olan bir gsterici olmas, ilevin
ayn trden ancak const olmayan bir adres ile arlmas (qualification conversion).
2. Ykseltme durumu
Ykseltme (promotion), aadaki durumlar kapsar
i. char, unsigned char, short, unsigned short , bool trlerinden int trne yaplacak
dnm. Bu duruma "int trne ykseltme" (integral promotion) denir. Argman olan
ifade, int trnden kk trlerden ise, int trne ykseltme kural gerei, ilevin
parametre deikenlerine yaplan bir atama sz konusu ise, bu durum ykseltme olarak
ele alnr.
voidfunc(int);
intmain()
{
func('A'); //Ykseltme(integralpromotion)
func(true);//Ykseltme(integralpromotion)
//...
}
ii) Argman olan ifade float trden ise, ilevin bu argmana karlk gelen parametre
deikeni double trden ise, bu durumda, float trnden double trne yaplacak
dnm de ykseltme olarak deerlendirilir:
voidfunc(double);
intmain()
{
floatfx;
//...
func(fx);
//...
}

//ykseltme

iii. Bir numaralandrma trnden, o numaralandrma trne baz olan (underlying type)
tre yaplan dnm de, ykseltme olarak deerlendirilir. Aadaki rnei inceleyin:
enumPOS{OFF,ON,HOLD,STAND_BY};
intfunc(int);
intmain()
{
POSposition=OFF;
func(position);
func(STAND_BY);
//...
}

//Numaralandrmatrndeninttrneykseltme)
//Numaralandrmatrndeninttrneykseltme)

3. Standart dnmler
Standart dnm (standard conversions) bal altnda toplanan, 5 grup dnm sz
konusudur:
i. Tamsay trlerine ilikin dnmler
Bir tamsay trnden ya da bir numaralandrma trnden, baka bir tamsay trne
yaplan dnmler.
C++ Kitabi (48/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

ii. Gerek say dnmleri


Bir gerek say trnden baka bir gerek say trne yaplan dnmler
iii. Gerek say trleri ile tamsay trleri arasnda yaplan dnmler.
iv. Adres trlerine ilikin dnmler
0 deerinin herhangi trden bir gstericiye atanmas ya da void trden olmayan herhangi
bir adres bilgisinin void trden bir gstericiye atanmas durumu.
v. bool trne yaplan dnmler
Herhangi bir tamsay, gerek say, numaralandrma ya da adres trnden, bool trne
yaplan dnmler.
Aada standart dnmlere ilikin baz rnekler veriliyor:
voidfunc(int);
voidfoo(long);
voidsample(float);
voidpf(int*);
voidvfunc(void*);
intmain()
{
intx=10;
foo(x);
foo('A');
func(20U);
sample(7.5);
pf(0);
vfunc(&x)
//...
return0;

//standartdnm(inttrdenlongtrne)
//standartdnm(chartrdenlongtrne)
//standartdnm(unsignedinttrndenint)
//standartdnm(doubletrdenfloattrne)
//standartdnm(0de?erininbirgstericiyeatanmas
//standartdnm(int*trdenvoid*trne)

}
4. Programcnn tanmlad dnmler.
Bu durumu snflara giri yaptktan sonra ele alacaz. Ancak imdilik u kadarn
syleyebiliriz: Bu dnmler, bir snf trnden nesnenin baka bir snf trne ya da
doal bir veri trne dntrlmesine ilikindir. Derleyicinin bu tr dnmleri
gerekletirebilmesi iin, programcnn zel dnm ilevleri tanmlam olmas gerekir.
simleri "Dntrme kurucu ilevleri" ya da "tr dntrme ilevleri" olan bu ilevleri
ilerde ayrntl bir ekilde inceleyeceiz.
Hangi ilevin arlm olduunun saptanmas konusunda rnekler verelim:

C++ Kitabi (49/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


intfoo(int);
intfoo(double);
voidfoo(char);
longfoo(long);
voidfoo(int,int);
voidfoo(char*);
voidfoo(int*);

//1
//2
//3
//4
//5
//6
//7

voidfunc()
{
foo(10);
foo(3.4F);
foo((double*)0x1FC0);
foo(6U);
}
func ilevi iinde yaplan ilev arlarn teker teker ele alalm:
foo(10);
ars iin
1, 2, 3, 4, 5, 6, 7 numaral ilevler adaydr.
1, 2, 3, 4 numaral ilevler uygundur.
Tam uyum salad iin, 1 numaral ilev en uygun olandr.
foo(3.4F)
ars iin
1, 2, 3, 4, 5, 6, 7 numaral ilevler adaydr.
1, 2, 3, 4 numaral ilevler uygundur.
Ykseltme durumu olarak deerlendirildiinden, 2 numaral ilev en uygun olandr.
foo((double*)0x1FC0)
ars iin
1, 2, 3, 4, 5, 6, 7 numaral ilevler aday ilevlerdir.
Uygun ilev yoktur (no match).
lev ars geersizdir.

foo(6U)
ars iin
1, 2, 3, 4, 5, 6, 7 numaral ilevler adaydr.
1, 2, 3, 4 numaral ilevler uygundur.
1, 2, 3 ve 4 numaral ilevler iin standart dnm uygulanabilir. ift anlamllk hatas
(ambiguity) sz konusudur. lev ars geersizdir.

const Yklemesi
Bir ilevin parametre deikeni gsterdii yer const olan bir gsterici iken, ayn isimli bir
baka ilevin parametre deikeni, gsterdii yer const olmayan bir gsterici olabilir:
voidfoo(constint*);
voidfoo(int*);
Bu durum da ilev yklemesi olarak ele alnr. Yani iki ayr ilev sz konusudur. foo
ilevine int trden bir nesne ile ar yapldnda, hangi ilev arlm olur?

C++ Kitabi (50/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidfunc()
{
intx=20;
foo(&x);//hangiileva?rlr?
}
Bu durum "const yklemesi" (const overloading) olarak bilinir. Hangi ilevin arlaca,
ileve gnderilen nesnenin const olup olmamasna gre belirlenir. Eer ilev ars const
bir nesne adresi ile yaplrsa, parametre deikeni gsterdii yer const gsterici olan ilev
arlrken, ilev ars const olmayan bir nesnenin adresi ile yaplrsa, arlan dier
ilev olur:
voidfoo(constint*);
voidfoo(int*);
voidfunc()
{
intx=20;
constinty=30;
foo(&x);
//voidfoo(int*);
foo(&y);
//voidfoo(constint*);
}
phesiz const yklemesi, parametre deikeninin referans olmas durumunda da
geerlidir:
voidfoo(constint&);
voidfoo(int&);
voidfunc()
{
intx=20;
constinty=30;
foo(x);
//voidfoo(int&);
foo(y);
//voidfoo(constint&);
}
Aada yer alan programda, ift anlamllk hatasnn olduu bir baka tipik durum
gsteriliyor:

C++ Kitabi (51/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include<iostream>
usingnamespacestd;
voidfoo(int&r)
{
cout<<"voidfoo(int&)"<<endl;
}
voidfoo(intx)
{

cout<<"voidfoo(int)"<<endl;
}
intmain()
{
inta=20;
//foo(a);iftanlamllkhatas
foo(5);//voidfoo(int);
return0;
}
Yukardaki programda, ilk tanmlanan foo ilevinin parametre deikeni int trden bir
referans iken, ikinci foo ilevinin parametre deikeni int trden bir nesnedir. Bunlar farkl
ilevdir. main ilevi iinde, yorum satr iine alnm birinci ilev ars ift anlamllk
hatasna neden olur. Yani bu durumda, deerle arma(call by value) ya da adresle
arma (call by reference) birbirine gre ncelikli deildir. Ancak ikinci ilev arsnda,
argman olan ifade bir deimezdir. Bir referansa bir deimez ifadesi ile ilk deer
verilemeyeceine gre, arlabilecek tek bir ilev vardr. unu da ekleyelim: Birinci
ilevin parametre deikeni const referans olsayd, ikinci ilev ars da ift anlamllk
hatas durumuna derdi.
Hangi ilevin arlm olduunu saptamak, derleme zamannda yaplan bir ilemdir. Yani
kaynak kod derlenip hedef dosya haline getirildiinde, artk hangi ilevin arlm olduu
bilinir. nk arlan ilevin kimlii bir ekilde hedef koda yazlm olur. Baka bir deyile
"ilev yklemesi" aracnn, programn alma zaman asndan bakldnda bir ek
maliyeti sz konusu deildir. Ancak byle bir ara derleyici zerindeki yk de artrr.
Derleyici programn boyutunun bymesine neden olur. Kk bir dil olarak tasarlanan C
dilinde, bu aracn bulunmamasnn nemli bir nedeni de budur.
Ayn isimli ilevler gereksiz yere tanmlanmamaldr. lev yklemesinin ana amac,
alacak kodlar gerekte birbirinden farkl olan ilemleri, ayn isim altnda soyutlamaktr.
Farkl iler gren ilevlerin, ayn ismi tamas okunabilirlii bozar. Birden fazla ilevin ayn
ismi tamas, kullanc kodlarn iini kolaylatrmaya yneliktir.

C++ Kitabi (52/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

SINIFLAR
Snflar, nesne ynelimli programlama tekniinin temel yap tadr. Nesne ynelimli
programlama tekniine "snflar kullanarak program yazma" teknii diyebiliriz. Bu
blmde snflara bir giri yapacak, snflara ilikin temel kavramlar aklayacaz. Bundan
sonraki blmlerde ise arlkl olarak snflarn kullanlmas zerinde duracaz.

Snf Nedir
Snflar ncelikle szdizim asndan ele alacaz. Snf C++ dilinin, programcnn yeni bir
tr yaratmasna olanak veren bir aracdr. C'de, programcnn yeni bir tr yaratmas, yap
(struct), birlik (union) ve enum aralaryla mmkn oluyordu. C++ dilinde bu aralara bir
de snf (class) eklenmitir.
Snf (class) nesne ynelimli programlama tekniinin uygulanmasna olanak salayan, C
dilinde olmayan yeni bir yazlmsal birimdir. Snflar, Cdeki yaplara benzetilebilir. Ancak
Cdeki yaplar yalnzca eleman (member) ierirken, C++da snflar yaplardan fazla olarak
hem veri eleman hem de ye ilevleri (member function) ierir. Snflar, yaplara gre ek
bir ok zellie sahiptir. Bu zelliklerin ou Nesne Ynelimli Programlama Tekniini
destekleme amacyla eklenmitir.
Nasl bir "yap" tr programc tarafndan tanmlanm bir tr (user defined type) ise,
snflar da programcnn tanmlam olduu trdr. Programc, nce yeni bir tr
derleyiciye tantr, daha sonra bu yeni trden nesne, gsterici, referans tanmlayabilir.
Snflar kullanabilmek iin ilk yaplmas gereken ilem, bir snfn tanmn yapmaktr. Bir
snfn tanmn yapmak, bu snf hakknda derleyiciye bilgi vermek anlamna gelir.
Derleyici ald bilginin sonucunda, bu snf trnden bir nesne tanmlanmas durumunda,
hem bellekte ne kadar yer ayracan bilir, hem de programcnn yazm olduu koda
ilikin baz kontrol ilemlerini yapma olanana kavuur.
Snflar yaplara gre temel olarak iki nemli farklla sahiptir:
i. Snf bildirimi iinde snflarn elemanlar, ismine public, protected ya da private denilen
ayr blgede yer alabilir.
ii. Snflar yalnzca veri elemanlar deil ilevler de ierir. Bu ilevlere snfn ye ilevleri
(member functions) denir.
nce bu iki yeni zellik stnde ayrntl bir biimde duracaz:

Snf Tanm
Bir snfn tanm, yani derleyiciye tantlmas zel bir szdizim ile olur:
Snf bildiriminin genel biimi yledir:
class[snf_ismi]{
[private:]
//
[protected:]
//
[public:]
//
};
class bir anahtar szcktr. Trke "snf" anlamna gelir. Genel biimdeki snf_ ismi(class
tag), bildirimi yaplan snfn ismidir. Snf ismi, isimlendirme kurallarna uygun herhangi
bir isim olabilir.
C++ Kitabi (53/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Bir snf tanmnda yer alan blok, private, protected ve public isimli blmden oluur.
public, private ve protected C++n anahtar szckleridir. Bu szcklere bundan sonra
eriim belirteci diyeceiz. Bir blm, eriim belirtecini izleyen iki nokta st ste (:) ayrac
ile balatlr, dier bir eriim belirtecinin kullanlmasna kadar srer. blmn, hepsinin
bir snf bildiriminde bulunmas zorunlu deildir. Hi bir eriim belirtecinin kullanlmamas
durumunda snfn private blm anlalr. Yani snf bildirimi iinde varsaylan (default)
blm private blmdr.
ye ilevlerin yalnzca bildirimleri snf bildirimi iine yazlr. Bu ilevlerin tanmlamalar,
normal bir ilev gibi ancak farkl bir szdizim kural ile snf bildiriminin dnda yaplr.
Ancak ye ilevlerin tanm snf bildiriminin iinde de yaplabilir. Bu durumu ileride, snf
ii inline ilevler balyla inceleyeceiz.
C++da, snfn tanm iinde bildirilen ilevlerle snfn dnda bildirimleri yaplan ilevleri
birbirlerinden ayrabilmek iin yeni terimler kullanlr. Snfn iinde bildirilen bir ileve, o
snfn ye ilevi (member function) denirken, dier ilevlere global ilevler (global
functions) denir. Yani C dilinde daha nce tanmlamaya alm olduumuz ilevlere artk
bundan byle global ilevler diyeceiz.
Snfn elemanlar, yaplarda olduu gibi snf iinde tr bilgileri ile bildirilir. Aadaki
rnei inceleyin:
classA{
private:
inta;
voidfunc1();
protected:
longb;
intfunc2(int);
public:
doublec;
doublefunc3();
};
Yukardaki snf bildiriminde, snfn blmnn de kullanlm olduunu gryorsunuz.
Snfn her blmnde, birer eleman ile birer ilev bildiriliyor. Snf bildirimi iinde, birden
fazla eriim belirteci kullanlabilir. rnein yukardaki bildirim aadaki gibi de
yaplabilirdi:
classA{
protected:
longb;
private:
inta;
public:
doublefunc3();
protected:
intfunc2(int);
public:
doublec;
private:
voidfunc1();
};
Snf bildirimi bir eriim belirteci ile balatlmamsa, private blm zerinde ilem
yapld anlalr. Aadaki rnei inceleyin:

C++ Kitabi (54/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

classA{
longb;
inta;
public:
doublefunc3();
protected:
intfunc2(int);
public:
doublec;
private:
voidfunc1();
};
Yukardaki rnekte, A isimli snfn a ve b elemanlar snfn private blmnde bildiriliyor.
imdi de aadaki snf bildirimini inceleyin:
classDate{
intday,mon,year;
boolverify_date();
public:
voidset_date(int,int,int);
voiddisplay_date();
};
Yukarda, ismi Date olan bir snf tanmlanyor. Yukardaki tanmla, Date isimli yeni bir veri
tr yaratlm olur. C ile C++n bu noktadaki farkn da hatrlayn: C++da bu veri
trnn ismi hem class Date hem de Date'dir. Yani bir typedef bildirimi yaplmakszn
Date ismi bu trn ismi olarak kullanlabilir. Oysa C dilinde yaplar sz konusu olduunda,
bir yap ismini (structure tag) bir tr ismi olarak kullanmak iin bir typedef bildirimi
yapmak gerekir.
Bir snf ismi (class tag), isimlendirme kurallarna uygun olmak kouluyla, istenildii gibi
seilebilir. Ancak programclarn ou, yalnzca ilk harfi byk dier harfleri kk olan
isimleri seerler.
Date isimli snfn tanmn incelemeyi srdrelim:
int trden day, mon, year isimli elemanlar snfn private blmnde bildirilmi. Bir eriim
belirteci kullanlmad zaman snfn private blmnn anlald sylenmiti. Baka bir
deyile, int, mon ve year, Date snfnn private elemanlardr. Date snfnn bildirimi
iinde, verify_date, set_date ve display_date isimli ilevin bildiriminin yapldn
gryoruz. Bu ilevler, Date snfnn ye ilevidir. verify_date isimli ilevin bildirimi snfn
private blmnde yaplm iken, set_date ve display_date ilevlerinin bildirimleri Date
snfnn public blmnde yaplm. yle de sylenebilirdi: set_date ve display_date,
Date snfnn public ye ilevleridir. verify_date Date snfnn private ye ilevidir. Peki,
snfn ye ilevleri ile bizim daha nceden bildiimiz ilevler arasnda bir fark var m?
Snflarn ye ilevleri ne ie yaryor, nasl tanmlanyor? Btn bu konular ayrntl bir
ekilde ele alacaz.
Mantksal olarak bir snf ile ilikilendirilmi ilevlere ye ilevler (member functions)
denir. Her ye ilev, snfn elemanlarna dorudan eriebilir. Snfn elemanlar, ye
ilevler tarafndan ortaklaa kullanlan deikenlerdir. Snfn ye ilevleri, bir konuya
ilikin eitli alt ilemleri yapar. Bu ilemleri yaparken de snfn elemanlarn ortaklaa
olarak kullanrlar. Bir ii gerekletiren bir dizi ilevin snf ad altnda ele alnmas,
alglamay ve tasarm kolaylatrr, derleyicinin baz denetimleri yapmasna olanak verir.
Yaplarla olduu gibi, snflarla da almak iin nce snf tanmn yapmak, sonra da bu
snf trnden nesneler tanmlamak gerekir.
C++ Kitabi (55/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Snf tanm kaynak kodun neresinde yaplmaldr? Bir snfn tanm kaynak kodun
herhangi bir yerinde yaplabilir. Ancak tanmn bilinirlik alannn (scope), dosya bilinirlik
alannda (file scope) ya da blok bilinirlik (block scope) alannda olmas, farkl anlamlar
ierir. rnein Date snfnn tanm, btn bloklarn dnda yani global dzeyde yaplrsa,
dosya bilinirlik alanndaki bu bildirim sonucunda Date snfn, dosyadaki tm ilevler bilir.
Yani snf bildiriminden sonra dosyann sonuna kadar her noktada Date snf kullanlabilir.
Oysa bildirim yerel dzeyde yani bir blok iinde yaplrsa, ilgili snf yalnzca bildirimin
yapld blok iinde bilinir.
Yaplar gibi snflar da ounlukla balk dosyalar iinde tanmlanr. ou zaman bir snfn
tanm hizmet veren kodlarn arayznn bir parasdr. Ancak, C++ dilinde balk
dosyalarnn kullanlmas konusunu daha sonraki blmlere brakyoruz.
Snf tanm, bir snfn elemanlar ile ye ilevlerinin derleyiciye tantlmas ilemidir. Snf
tanm ile derleyici bellekte herhangi bir yer ayrmaz, yalnzca snf hakknda bilgi edinir.
Snflar zerinde baz ilemlerin yaplabilmesi iin, snf trnden nesnelerinin
tanmlanmas gerekir. imdi snf nesnelerinin tanmlanmasn ele alacaz:

Snf Trnden Deikenlerin Tanmlanmas


Daha nce bildirimi yaplm bir snf trnden, bir deiken tanmlanabilir. Doal
trlerden deikenler nasl tanmlanrsa snf trnden deikenler de ayn biimde
tanmlanr. Bildirimde nce tr bildiren szck ya da szckler, daha sonra tanmlanan
deikenin ismi gelir. Daha nceki rneklerde tanmlanan A ve Date isimli snflar
dnelim.
Aa;
a deikeni A snf trnden bir snf deikenidir.
Datedate1,date2;
date1 ve date2 isimli deikenler Date snf trndendir. C++da yap ve snf trnden
deikenler tanmlarken, struct ve class anahtar szcklerinin yazlmasna gerek
olmadn biliyorsunuz. Bu anahtar szcklerin kullanlmas herhangi bir soruna yol
amaz. Yani yukardaki bildirim
classDatedate1,date2;
biiminde de yaplabilirdi. Ancak class anahtar szcnn gereksiz bir ekilde
kullanlmas tercih edilen bir biim deildir.

ye levlerin Tanmlanmas
Bir snfn ye ilevi, belirlenmi bir szdizim ile snfn dnda tanmlanr:
[geridnde?erinintr]<snf_ismi>::<ilev_ismi>([parametre
de?ikenleri])
{
//
}
Szdizimi inceleyelim:
nce ilevin geri dn deerinin trnn yazldn gryorsunuz. Sonra snfn ismi
yazlyor. Daha sonra gelen :: atomunu, ilevin ismi izliyor. ki tane "iki nokta st ste"nin
yan yana getirilmesiyle oluturulan :: atomuna, bundan sonra "znrlk atomu"
diyeceiz. Bu atom bir ile olarak kullanldnda "znrlk ileci" (scope resolution
operator) ismini alr.

C++ Kitabi (56/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Date snfnn, parametre deikeni olmayan, geri dn deeri retmeyen display_date
isimli ye ilevi yle tanmlanabilir:
voidDate::display_date()
{
//
}

Snf Nesneleri Yoluyla Snfn Elemanlarna ve ye levlerine


Eriim
Yaplarda olduu gibi, bir snfa ilikin nesne yoluyla snfn veri elemanlarna ve ye
ilevlerine nokta ileci ile eriilebilir. rnein object bir snf trnden nesne, m ise bu
snfn bir eleman ve func da bu snfa ilikin bir ye ilev olsun. Eriim aadaki gibi
gerekletirilir:
object.m
Bir ye ilev ancak bir snf nesnesi iin ile arlabilir. Global ilevlerde olduu gibi
dardan dorudan arlamaz. rnein object isimli nesnenin ait olduu snfn func
isimli bir ye ilevi varsa, bu ilev
func();
biiminde arlamaz. Eer byle bir ar yaplrsa derleyici global bir func ilevinin
arldn anlar. ye ilev ars aadaki gibi yaplabilir:
object.func();
Yukardaki deyimde object bir snf trnden nesne ve func da object in ait olduu snfn
ye ilevlerinden birinin ismidir.
Bir snfn ye ilevi, snf trnden bir gsterici ya da referans araclyla da arlabilir.
Bu durumlar biraz daha ileride ele alacaz.

ye levlere Yaplan arlarn Ama Kod ine Yazlmalar


C++da global bir ileve yaplan arnn ama kod iine nasl yazldna daha nce
deinmitik. lev ismi parametre deikenlerinin says ve trleriyle birletirilerek bir isim
elde ediliyor ama koda bu isim yazlyordu. Bir snfn ye ilevi arldnda derleyici bu
kez ye ilev ismini, parametre deikenlerinin says ve trlerinin yan sra snfn ismiyle
de birletirerek ama kod iine yazar. Bu durumda bir program iinde, ayn isimli ve ayn
parametrik yapya sahip global bir ilev ile bir snfa ilikin ye ilev birlikte bulunabilir. Bu
iki ilevin ama koda yazlmalarnda bir sorun ortaya kmaz. rnein Borland C++ 3.1
derleyicisinde
voidfunc();
global ilevi
@func$qv
biiminde, X snfna ilikin
X::voidfunc()
ilevi ise
@X@func$qv
C++ Kitabi (57/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

biiminde ama kod iine yazlr. Derleyiciler, ayn isimli global ilevlerle ye ilevleri ar
biimlerine bakarak ayrabilir. rnein:
a.func();
gibi bir ar, snf nesnesi ile yapldna gre, derleyici a hangi snf trnden bir nesne
ise func isimli ilevi de o snfn bir ye ilevi olacak biimde arayacaktr.. Oysa ar
func();
biiminde yaplrsa, derleyici global olan func ilevinin arldn anlard.
C++da ilevlerin ama kod iine yazlmalarnda herhangi bir standart sz konusu deildir.
Her derleyici ye ilevlerin isimlerini snf ismiyle ve parametre trleriyle kombine ederek
ama kod iine yazar. Ancak bu yazma ilemine ilikin kesin bir notasyon(yazm ekli)
standart olarak belirlenmemitir. Bu nedenle farkl C++ derleyicileriyle derlenmi
modllerin birletirilmesinde sorunlar kabilir.
Peki, bir snf nesnesinin elemanlar bellee ne ekilde yerletirilir?
Bir snf nesnesi tanmlandnda derleyici yalnzca snfn elemanlar iin bellekte yer
ayrr. Snfn ye ilevleri snf nesnesi iinde herhangi bir yer kaplamaz. ye ilevler
yalnzca mantksal bakmdan snf ile ilikilendirilmitir. Snfn iki blm belirten anahtar
szc arasna yazlan veri elemanlar, ilk yazlan dk adreste olacak biimde bitiik
yerletirilir. Blmlerin birbirlerine gre yerleim biimleri standart olarak
belirlenmemitir, derleyiciden derleyiciye deiebilir. Aadaki rnei inceleyin.
classA{
private:
inta;
intb;
public:
intc;
intd;
protected:
inte;
intf;
private:
intg;
inth;
};
Burada A snf trnden bir snf nesnesinin bellekte kaplad alan 8 * sizeof(int) kadar
olur. Nesne iinde, a ile b, c ile d, e ile f ve g ile h veri elemanlar bitiik olarak yerletirilir.
Ancak bu gruplarn kendi aralarndaki yerleimleri derleyiciden derleyiciye deiebilir.
Blmler arasndaki yerleim standart bir biimde belirlenmemi olsa da derleyicilerin
hemen hepsi daha yukar yazlan blmleri dk adrese yerletirir. Yani yukardaki
rnekte derleyicilerin byk blm veri elemanlarn srasyla dk adresten balayarak
yukardan aaya doru yerletirir. Blmler aras yerleim standart olmadna gre,
nesnenin elemanlarnn yerleimine ilikin yazlan kodlarda tanabilirlik sorunlar ortaya
kabilir.
Nesnenin bellekte kaplad alan, derleyicinin hizalama (alignment) ilemleri etkin hale
getirilmise veri elemanlarnn toplam uzunluundan fazla olabilir.

Snflarda Temel Eriim Kural


Global bir ilev iinde bir snf nesnesi, gstericisi ya da referans ile snfn her blmne
eriilemez. Hangi elemanlara ya da hangi ye ileve eriebilecei, snfn elemanlarnn ya
C++ Kitabi (58/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


da ye ilevlerin yerletirilmi olduklar yer ile ilgilidir. Eriim kurallarn iki blme
ayrarak inceleyeceiz:

Global levlerin Eriim Kural


Bir snf nesnesi, gstericisi ya da referans ile, global bir ilevden ancak snfn public
blmndeki elemanlara ve ye ilevlerine eriilebilir. Global bir ilev iinde snfn private
ya da protected blmlerindeki elemanlara ve ye ilevlere snf nesnesi yoluyla
eriilemez. Aadaki rnekleri inceleyin:
#include<iostream>
#include<cstdlib>
classDate{
intday,month,year;
boolverify_date();
public:
voidset_date(int,int,int);
voiddisplay_date();
};
//yeilevtanmlamalar...
usingnamespacestd;
intmain()
{
Datedate;
date.day=10;

//Geersiz!

if(!date.verify_date()){
//Geersiz!
cout<<"Geersiztarih"<<endl;
exit(EXIT_FAILURE);
}
date.set_date(10,10,1997);
date.display_date();

//Geerli!
//Geerli!

return0;
}
Bir snf nesnesi referans ya da gstericisi yoluyla snfn yalnzca public blmndeki veri
elemanlar ile ilevlerine dorudan eriilebilir: Yukardaki rnekte date.day veri eriimi ile
date.verify_date() ye ilevinin ars bu nedenle geerli deildir. Fakat snfn public
blmnde bulunan set_date ve display_date ye ilevlerine yaplan arlar geerlidir.
Bu ilev arlar derleme zamannda herhangi bir soruna yol amaz. Snflardaki eriim
kuralna uyulmamasndan dolay oluan hatalara ilikin iletiler Microsoft derleyicilerinde,
xxxcannotaccessprivatememberdeclaredinClassYYY
Borland derleyicilerinde ise,
YYY::xxxnotaccessible
biimindedir.

ye levlerin Eriim Kural


C++ Kitabi (59/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Bir snfn ye ilevi, hangi blmde bildirilmi olursa olsun snfn her blmndeki
elemanlarna dorudan eriebilir. Snfn ye ilevlerini dorudan arabilir. rnein,
bildirimini yukarda verdiimiz Date snfnn set_date isimli ye ilevi yle tanmlanm
olsun:
voidDate::set_date(intd,intm,inty)
{
date=d;
//Geerli.
month=m;
//Geerli.
year=y;
//Geerli.
if(!verify_date(d,m,y)){
//Geerli.
cout<<"Geersiztarih"<<endl;
exit(EXIT_FAILURE);
}
}
Grld gibi set_date isimli ye ilevin tanm iinde, verify_date isimli ye ilev
dorudan arlyor. verify_date ye ilevi, sz konusu tarihin geerli bir tarih olup
olmadn snyor. Eer tarih geersiz ise program sonlandrlyor. set_date ye ilevi
iinde snfn day, month, year isimli private elemanlarna dorudan eriiliyor. Yine
set_date ilevi iinde snfn private ye ilevi olan verify_date isimli ilevi arlyor.
private blmde olan bu isimlere eriim geerlidir. nk bir ye ilev kendi snfnn her
blmne eriebilir.
Snfn ye ilevleri iinde tanmlanan ayn snfa ilikin nesneler, referanslar ya da
gsterici deikenler ile snfn her blmne eriebilir. rnein Date snfnn
process_date isimli bir ye ilevi daha olsa,
voidDate::process_date()
{
Datedate;
date.day=day;
//Geerli.
date.month=month;
//Geerli.
date.year=year;
//Geerli.
if(!date.verify_date()){
//Geerli.
cout<<"Geersiztarih:<<endl;
exit(EXIT_FAILURE);
}
}
process_date ye ilevi iinde tanmlanan date snf deikeni ile snfn her blmne
eriilebilir. nk date deikeni snfn ye ilevi iinde tanmlanyor. Bir ilevin
parametre ayracnn ii de ilevin ii kabul edilir. Bu durumda bir ye ilevin parametre
deikeni ayn snf trnden bir nesne, referans ya da gsterici ise, parametre deikeni
ile nokta ya da ok ilecinin kullanlmasyla snfn private elemanlarna ya da ye
ilevlerine eriilebilir.

ye levlerin Snfn Elemanlarna Erimesi


Bir ye ilev hangi snf nesnesi iin arlmsa, ye ilevin iinde kullanlan veri
elemanlar da o nesneye ilikindir. Aadaki rnei inceleyin:
class A {
public:
void set(int, int);
void display();
private:
int a, b;
C++ Kitabi (60/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


};
void A::set(int x, int y)
{
a = x;
b = y;
}
#include <iostream>
using namespace std;
void A::display()
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
int main()
{
A a1;
a1.set(10, 20);
a1.display();
A a2;
a2.set(30, 40);
a2.display();
return 0;
}
Burada set ve display ye ilevleri tanmlar iinde dorudan kullanlan a ve b elemanlar,
bu ilevler hangi nesne ile arlmsa o nesnenin elemanlardr. display ye ilevine
yaplan
a1.display()
arsnda a1 deikeninin elemanlar,
a2.display()
arsnda ise a2 deikeninin elemanlar kullanlr.

Bir ye ilevin baka bir ye ilevi armas durumunda, arlan ye ilev aran ye
ilev ile ayn elemanlar kullanr. rnein A snfnn set ye ilevi display ye ilevini
dorudan arm olsun:

C++ Kitabi (61/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidA::set(intx,inty)
{
a=x;
b=y;
display();
}
Bu durumda set ye ilevi hangi snf nesnesi ile arlmsa, display ye ilevi de onun
elemanlarn kullanr.
intmain()
{
Aa1;
a1.set(10,20);
return0;
}
Yukardaki main ilevinde arlan set ve display ye ilevleri a1 snf nesnesinin
elemanlarn kullanr. Yani set ve display ilevlerinin iindeki a ve b elemanlar a1
nesnesine ilikindir.

Snf Elemanlarna Eriim ve this Gstericisi


Bir ye ilevin kendi snfnn elemanlarna ve ye ilevlerine dorudan eriebildii
sylendi. Peki, gerekte bu nasl oluyor? Yalnzca bir grup ilev tarafndan eriilebilen bir
nesne, C dilinde ne anlama gelir? Bir ilev kendi iinde tanmlanmayan bir yap nesnesinin
elemanlarna nasl eriebilir? levin bu yerel nesnenin adresini almas gerekir, deil mi?
C, C++dan daha doal bir dildir. Yani bilgisayarda olanlar daha iyi betimler. Bir ilem pek
ok programlama dilinde farkl bir biimde yaplyorsa, gerekte ilem Cdekine(C
dilindekine) benzer bir biimde yaplr. Bir ilemin C dilinde neye karlk geldiini
aratrmak onun gerekte nasl olduunu yani makina dili dzeyinde neye karlk
geldiini aratrmak anlamna gelir. rnein snf bilinirlik alan diye bir kavram C dilinde
olmadna gre bu durum doal deildir. Aslnda Cdeki(C dilindeki) doal baka
mekanizmalarla karlanabilir.
Bir ye ilevin snfn elemanlarna erimesi ye ileve gizlice geirilen bir adres yoluyla
yaplr. Bu adres, ye ilev hangi nesne ile arlmsa o nesnenin adresidir. rnein bir
ye ilevin hi parametre deikeni yoksa, aslnda gizli bir parametre deikeni vardr. O
parametre deikenine ilev arsyla bir snf nesnesinin adresi aktarlr. rnein aada
tanmlanan Myclass snfnn display isimli ye ilevini inceleyelim.
Grne gre display ilevinin parametresi yoktur:
voidMyclass::display()
{
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
}
Ancak aslnda ileve gizlice bir argman gnderilir. Bu argman ar ifadesindeki snf
nesnesinin adresidir. Aslnda display ilevinin makina kodlar incelenirse byle bir
argmann geirildii grlebilir. Bu durumda, display ilevinin C karl yle olur:
voidA::display(A*constthis)
{
cout<<"a="<<this>a<<endl;
cout<<"b="<<this>b<<endl;
}

C++ Kitabi (62/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Bir ye ilev iinde snfn bir eleman kullanldnda, derleyici o elemana ileve gizlice
geirilen bir adres ile eriir. Adres geirme ileminin gizlice yaplmas kolay yazm
salamak iin dnlmtr. rnein bir ye ilevinin aka yazlm drt parametresi
olsa, gerekte derleyici bu ileve be argman geirir.
ye ileve nesnenin adresi gizlice geiriliyor olsa da, ye ilevler iinde bu adres this
anahtar szc ile kullanlabilir. rnein,
voidMyclass::display()
{
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
}
tanmyla,
voidMyclass::display()
{
cout<<"a="<<this>a<<endl;
cout<<"b="<<this>b<<endl;
}
tanm arasnda hi fark yoktur. Zaten rnein, this->a denmese bile a eleman
kullanldnda derleyici gizlice geirilen snf nesnesi adresiyle a elemanna eriir.
this bir anahtar szcktr ve hangi snfa ilikin ye ilev iinde kullanlrsa o snf
trnden bir adres belirtir. rnein this anahtar szc Myclass snfna ilikin bir ye
ilev iinde kullanlrsa, this Myclass snf trnden bir adres belirtir.
this ayn zamanda kendisi const bir gstericidir. indeki adres deitirilemez. ye ilev
iinde
this=adr;
gibi bir atama geersizdir.
ye ilev hangi nesne iin arlmsa this gstericisine o nesnenin adresi geirilir. Tabii
eer ye ilev bir adres yoluyla arlyorsa this gstericisine ye ilevin arld
gsterici iindeki adres geirilir. rnein, func X snfnn bir ye ilevi, a bu snf trnden
bir nesne ve p de bu snf trnden bir gsterici olsun,
a.func();
arsnn C karl,
Xfuncv(&a);
biimindedir. Benzer biimde,
ptr>func();
arsnn C karl ise,
Xfuncv(ptr);
biimindedir. C karlklarn yazarken ye ilevlerin snf isimleriyle ve parametre trleriyle
birletirildiini vurgulamak iin bana ve sonuna ekler getirdik.
Aadaki program yazarak altrn:

C++ Kitabi (63/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classX{
public:
voiddisplay();
voidset(int);
private:
inta;
};
#include<iostream>
usingnamespacestd;
voidX::set(intval)
{
cout<<"X::set()cagrildi"<<endl;
cout<<"this="<<this<<endl;
a=val;
}
voidX::display()
{
cout<<"X::display()cagrildi!"<<endl;
cout<<"this="<<this<<endl;
cout<<"a="<<a<<endl;
}
intmain()
{
Xmyx;
cout<<"&myx="<<&myx<<endl;
myx.set(10);
myx.display();
X*ptr=&myx;
ptr>display();
return0;
}
Elde edilen adres deerleri birbirinin ayns, deil mi?
Bu durumda bir ye ilevin baka bir ye ilevi armasnn da ne anlama geldii de
aktr. ye ilev dardan gizlice ald this adresini gizlice baka bir ye ileve geer.
voidA::set(A*constthis,intx,inty)
{
this>a=x;
this>b=y;
display(this);
}
Peki, bir snf gstericisi iinde rastgele bir deer varken o gstericiyle bir ye ilev
arlrsa ne olur? rnein:
intmain()
{
X*p;
p>func();
return0;
}
C++ Kitabi (64/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Burada p, yerel bir gsterici deiken olduundan iinde bir p deer vardr. Bu durumda
func ilevine this adresi olarak bir p deer geilir. Yani func ilevi rastgele bir bellek
blgesini snf nesnesi gibi kullanr. Byle bir durum bir gsterici hatasna yol aar.
imdi yle bir soru soralm: Madem bir snfn ye ilevi iinde snf nesnesinin
elemanlarna dorudan eriiliyor, o zaman neden this diye bir anahtar szck var? ye
ilev iinde snf nesnesinin adresinin elde edilebilmesinin ne gibi faydalar olabilir? this
adresi bir ye ilev iinde aadaki amalar iin kullanlabilir:
1. ye ilev hangi snf nesnesi iin arlmsa, o snf nesnesinin adresi, ye ilev tanm
iinde bir baka ileve argman olarak gnderilebilir:
classA{
public:
//...
voida_func();
private:
//...
};
voidg_func(A*);
voidA::a_func()
{
//...
g_func(this);
}
intmain()
{
Aa;
a.a_func();
return0;
}
Yukardaki programda, A snfnn a_func isimli ye ilevi iinde arlan g_func isimli
global ileve, this adresi argman olarak gnderiliyor. main ilevi iinde tanmlanan A
snf trnden a nesnesi ile a_func ye ilevi arldnda, a nesnesinin adresi gizlice
a_func ilevine geirilir. Bu ilev iinden de, bu adres global g_func ilevine gnderilir.
2. ye ilev iinde, ye ilevi aran snf nesnesinin kendisine eriilebilir. Madem ki this
adresi ye ilevi aran snf nesnesinin adresidir, bu durumda
*this
ifadesi bu nesnenin kendisidir, deil mi? Aadaki kodu inceleyin:

C++ Kitabi (65/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidg_func(A);
voidA::a_func()
{
Aa;
a=*this;
//...
g_func(*this);
}
intmain()
{
Ax;
x.a_func();
return0;
}
A snfnn a_func ilevi iinde tanmlanan A snf trnden a nesnesine *this ifadesi
atanyor. main ilevi iinde a_func ilevi x nesnesi ile arldndan, a_func ilevi iindeki
a ya x nesnesinin deeri atanyor. Bu kez global g_func isimli ilevin parametre
deikeninin A snf trnden olduunu gryorsunuz. a_func ye ilevi iinde arlan
global g_func ilevine bylelikle main ilevi iindeki yerel x nesnesinin deeri aktarlm
olur.
3. arlan bir ye ilev, hangi snf nesnesi iin arlmsa, o snf nesnesini ya da o snf
nesnesinin adresini geri dndrebilir. Bu durum ileride anlatlacak baz aralarda youn
bir biimde kullanlr. Aadaki rnei dikkatle inceleyin:
classA{
public:
//...
Aa_func1();
A*a_func2();
A&a_func3();
private:
//...
};
A snfnn ye ilevlerinden a_func1, A snf trnden bir deerle, a_func2 ilevi A snf
trnden bir adresle, a_func3 ilevi ise A snf trnden bir referansla geri dnyor.
imdi bu ilevlerin tanmlarna bir bakalm:
AA::a_func1()
{
//...
return*this;
}
A*A::m_func2()
{
//...
returnthis;
}
A&A::m_func3()
{
//...
C++ Kitabi (66/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


return*this;
}

a_func1 ye ilevi hangi snf nesnesi iin arlmsa, o snf nesnesinin deerini geri
dndrr.
a_func2 ye ilevi hangi snf nesnesi iin arlmsa, o snf nesnesinin adresini geri
dndrr.
a_func3 ye ilevi hangi snf nesnesi iin arlmsa, o snf nesnesinin kendisini geri
dndrr.
4. this gstericisi, snf elemanlarnn yerel deikenler tarafndan maskelenmesi
durumunda, snf elemanlarna erimek amacyla da kullanlr. Bu durum "snf bilinirlik
alan" bal altnda incelenecek.

Snf Bilinirlik Alan


C dilinde bilinirlik alanlarnn drde ayrldn anmsayn. Bunlar dardan genie doru
ilev bildirim bilinirlik alan (function prototype scope), blok bilinirlik alan (blok
scope), ilev bilinirlik alan (function scope) ve dosya bilinirlik alan (file scope) dr.
Blok bilinirlik alan bir ismin yalnzca bir blok iinde, ilev bilinirlik alan bir ilevin her
yerinde, dosya bilinirlik alan ise tm ilevler iinde bilinmesi, kullanlabilmesi anlamna
gelir. C++da bu bilinirlik alanlarna ek olarak bir de snf bilinirlik alan (class scope)
tanmlanmtr. Snf bilinirlik alan, bir ismin hem snf bildirimi iinde, hem de snfn tm
ye ilevleri iinde bilinmesidir. Snfn elemanlar ile ye ilevleri, snf bilinirlik alan
kuralna uyar. Snf bilinirlik alannn darlk genilik bakmndan ilev bilinirlik alan ile
dosya bilinirlik alan arasnda bulunduuna dikkat edin. Bu durumda C++daki bilinirlik
alanlar dardan genie doru,
1.
2.
3.
4.
5.

lev bildirimi bilinirlik alan (function prototype scope)


Blok bilinirlik alan (block scope)
lev bilinirlik alan (function scope)
Snf bilinirlik alan (class scope)
Dosya bilinirlik alan (file scope)

biimindedir. imdi de ayn isimli deikenlerin durumuna bir gz atalm: Ayn isimli
deikenler konusunda u kural anmsatalm: Cde(C dilinde) olduu gibi C++da ayn
bilinirlik alanna ilikin ayn isimli birden fazla deiken tanmlanamaz. Fakat farkl
bilinirlik alanna ilikin ayn isimli birden fazla deiken tanmlanabilir. Bir blok iinde ayn
isimli birden fazla deiken etkinlik gsteriyorsa, o blok iinde dar bilinirlik alanna sahip
olana eriilebilir.
Aadaki rnei inceleyin:

C++ Kitabi (67/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include<iostream>
voidfunc();

//ilevbildirimi

inta=50;

//globalde?iken

classX{
public:
voidfoo(int);
voidfunc();
private:
inta;
};
usingnamespacestd;
voidX::func()
{
cout<<"Xsnfnnfuncisimliyeilevi"<<endl;
}
voidfunc()
{
cout<<"Globalfuncisimliilev"<<endl;
}
Bu rnekte hem a isimli global bir deiken tanmlanyor, hem de X snfnn a isimli bir
eleman var. Snfn foo ye ilevi de yle tanmlanm olsun:
voidX::foo(inta)
{
cout<<a<<endl;
//Parametrede?ikeniolana
{
inta=30;
cout<<a<<endl;
//Blokiindekia
}
func();
//yeilevolanfunc
}
imdi drt tane a sz konusu. Global olan a, snfn eleman olan a, parametre deikeni
olan a ve i blokta tanmlanm olan a. Dar bilinirlik alanna sahip olana erime kuralna
gre, i blokta kullanlan a o blokta tanmlanan a deikenidir. D bloktaki ise ilevin
parametre deikenidir. arlan ilev ye ilev olan func isimli ilevdir. nk ilev
isimleri de deiken gibi ele alnr, ayn bilinirlik alan kuralnda uyar. Global ilevler dosya
bilinirlik alanna, ye ilevler ise snf bilinirlik alanna sahiptir. imdi foo ilevinin
parametre deikeninin ismini deitirelim:
voidX::foo(intx)
{
a=x;
{
inta=30;
cout<<a<<endl;
}
func();
}

//Snfnelemanolana
//Blokiindekia

//yeilevolanfunc

C++ Kitabi (68/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


imdi d bloktaki a, snfn eleman olan a olarak ele alnr. Peki, bir ye ilev iinde snfn
elemanlar ya da ye ilevleriyle ayn isimli global deikenlere ya da ilevlere erimek
mmkn olabilir mi? te znrlk ileci ile bu durum mmkn klnmtr.

znrlk leci
znrlk ileci iki : karakterinin :: biiminde yan yana getirilmesiyle elde edilir.
znrlk ilecinin tek terimli nek (unary prefix) ve iki terimli araek biiminde (binary
infix) iki kullanm vardr. nce tek terimli nek biim zerinde duracaz:

znrlk lecinin Tek Terimli nek Kullanm


Bu kullanm biiminde znrlk ilecinin tek terimi vardr. le bu durumda her zaman
global olan isme eriimi gerekletirir. Aadaki rnei inceleyin:
#include<iostream>
usingnamespacestd;
inta=10;
intmain()
{
inta=20;
::a=50;
cout<<a<<endl;
{
inta=30;
::a=100;
cout<<a<<endl;
}
cout<<::a<<endl;

//Globala
//Yerela

//Globala
//Yerela
//Globala

return0;
}
znrlk ileci, ayn isimli hem yerel hem de global bir deikenin tanml olduu
durumda global olana erimek amacyla kullanlabilir. Yukardaki rnekte blok ilerinde a
deikeninin :: ileci ile kullanlmasyla global olan a deikenine eriilir.
Burada bir de uyar yapalm: :: ileci bir st blokta tanml olana eriimi deil, her zaman
global olana eriimi salar. Bir yukardaki bloa erimenin ciddi bir faydas yoktur. Oysa
global deikene eriim pek ok durumda gerekebilir.
Tek terimli nek kullanm sklkla bir snfn ye ilevleri iinde snfn elemanlar ile ayn
isimli global deikenlerin bulunmas durumunda, global olana eriimi salamak iin
kullanlr. Aadaki rnei inceleyelim:

C++ Kitabi (69/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include<iostream>
voidfunc();

//Globalilev

classX{
public:
voidfunc();
voidfoo();
};
usingnamespacestd;
voidfunc()
{
cout<<"Globalfuncisimliilev"<<endl;
}
voidX::func()
{
cout<<"Xsnfnnfuncisimliilevi"<<endl;
}
voidX::foo()
{
cout<<"Xsnfnnfooisimliilevi"<<endl;
func();
//Xsnfnnyeileviolana?rlyor
::func();
//Globalolana?rlyor
}
foo ye ilevinde,
func()
Biiminde normal olarak arlan dar bilinirlik alan kuralna gre X snfna ilikin olan
func ilevidir. Oysa
::func();
biiminde arlm olan global func ilevidir.
Baz programclar global olanla ayn isimli bir ye ilev olmasa bile, ye ilevler iinde
global ilevleri okunabilirlii artrmak iin :: ileciyle arrlar. rnein,
CMyDialog::CMyDialog()
{
hProcess=::GetProcessHeap();
}
GetProcessHeap ilevin CMyDialog snfnn ye ilevi olmadn dnelim. Bu durumda
ilevin :: ileci ile arlmasna gerek yoktur, deil mi? nk bilinirlik alanlarnn
akmas sz konusu olmad iin nasl olsa GetProcessHeap dendiinde global olan
anlalr. Ancak programc kodu inceleyen kiiye yardmc olmak iin durumu vurgulamak
istemi olabilir. Snflarn youn olarak kullanld ktphanelerde bu tr vurgulamalarla
olduka sk karlaabilirsiniz.

znrlk lecinin ki Terimli Araek Kullanm


C++ Kitabi (70/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


znrlk ileci iki terimli araek (binary infix) olarak da kullanlr. Byle bir kullanmda
sol terim bir snf ismi, sa terim ise snfn bir eleman ya da ye ilevi olmak zorundadr.
Bu kullanmla her zaman snfa ilikin olan elemana ya da ye ileve eriilir. rnein Date
isimli bir snfn int trden day, month, year isimli veri elemanlar olsun. set_date bu
snfn bir ye ilevi olmak zere
classDate{
public:
voidset_date(int,int,int);
private:
intday,month,year;
};
voidDate::set_date(intday,intmonth,intyear)
{
Date::day=day;
Date::month=month;

Date::year=year;
}
Parametre deikenlerinin isimleriyle snfn elemanlarnn isimlerinin ayn olduuna dikkat
edin. Bu durumda ye ilev iinde snfn elemanlarna erimek iin iki terimli znrlk
ileci kullanlyor. Kullanm biimini inceleyin:
Date::month=month;
Atama ilecinin sol tarafnda kullanlan month ismi snfn elemanna ilikin iken, atama
ilecinin sa tarafnda bulunan month ismi parametre deikenine ilikindir.
Grld gibi znrlk ilecinin iki terimli ara ek biimi, snfn elemanlar ile ayn
isimli yerel deikenler ya da parametre deikenlerinin olmas durumunda snfn
elemanlarna eriilmesi amacyla kullanlr. Bunun dnda znrlk ilecinin snflarn
tretilmesi ilemlerinde de benzer amalarla kullanldn greceksiniz.

Snfn Kurucu levleri


Bir snf nesnesi yaratldnda ismine kurucu ilev (constructor) denilen bir ye ilev
derleyici tarafndan otomatik olarak arlr. Derleyici kurucu ilevleri isimlerine bakarak
saptar. Kurucu ilevlerin ismi ait olduklar snfn ismidir. Kurucu ilevlerin geri dn
deerleri yoktur. "Geri dn deerleri yoktur" demekle geri dn deerlerinin void
olduunu anlatmak istemiyoruz. Bu ilevlerin geri dn deerleri diye bir kavramlar
yoktur. Yazarken geri dn deeri yerine hi birey yazlmaz. Kurucu ilevlerinin
parametrik yaps herhangi bir biimde olabilir.
Aadaki snf bildirimini inceleyin:
classDate{
public:
Date();
voiddisplay();
private:
intday,month,year;
};

Date();
biiminde bildirilen ilev snfn kurucu ilevidir. Bu ilevin isminin snf ismiyle ayn
olduuna dikkat edin. Bildirimde geri dn deeri yerine hibir ey yazlmyor. Bu durum
C++ Kitabi (71/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


yukarda da belirttiimiz gibi geri dn deerinin int ya da void olduu anlamna
gelmiyor. Date snfnn kurucu ilevinin tanm dier ye ilevler gibi yaplr:

Aadaki rnekte Person isimli snfn kurucu ilevi hangisidir?


classPerson{
public:
Person(constchar*,int);
voiddisplay();
voidset_name(constchar*);
voidset_no(int);
//
private:
char*name;
intno;
};

//Kurucuilev

Person snfnn kurucu ilevi,


Person(constchar*,int);
biiminde bildirilen ilevdir. Bu ilevin tanm aadaki gibi olabilir:
Person::Person(constchar*nm,intn)
{
//
}
Kurucu ilevlerin parametrik yaps herhangi bir biimde olabilir. C++da imzalar farkl
ayn isimli ilevler olabildiine gre, bir snfn da farkl imzalara sahip birden fazla kurucu
ilev de olabilir. Bir baka deyile kurucu ilevler de yklenebilir. rnein Date isimli bir
snfn birden fazla kurucu ilevi olabilir:
classDate{
public:
Date();
Date(int,int,int);
Date(constchar*);
//
private:
intday,intmonth,year;
};
Yukarda tanmlanan Date snf iin kurucu ilev bildirimi yaplyor: Parametre
deikeni olmayan, parametre deikenli olan ve tek parametre deikenli olan. Bir
snfn parametre deikeni olmayan, ya da tm parametre deikenleri varsaylan
argman alan kurucu ilevine "varsaylan kurucu ilev" (default constructor) denir.

C++ Kitabi (72/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Kurucu ilevler snf nesneleri yaratldnda derleyici tarafndan otomatik olarak arlr.
Yani derleyici nce snf nesnesi iin bellekte yer ayrr, daha sonra uygun olan kurucu
ilevi arr. Yerel deikenlerin programn aknn tanmlama noktasna geldiinde,
global deikenlerin ise programn bellee yklenmesiyle yaratldn anmsayn. Buna
gre yerel bir snf nesnesine ilikin kurucu ilev nesnenin tanmland yerde, global bir
snf nesnesine ilikin kurucu ilev ise programn bellee yklenmesiyle, yani main
ilevinden nce arlr. C++ dilinde main ilevinden nce alan bir kod da olabilir.
Bir snfn birden fazla kurucu ilevi olabildiine gre, derleyici bunlardan hangisi
aracan nasl saptar? Hangi kurucu ilevin arlaca nesnenin tanmlanma ifadesiyle
belirlenir. Eer nesne isminden sonra ayra alm, ayra iine bir argman listesi
yazlmsa, uygun imzaya sahip kurucu ilev arlr. rnein:
Datebdate(6,1,1966);
gibi bir tanmlamayla snfn
Date(int,int,int);
parametre yapsna sahip olan kurucu ilevi arlr. Burada, 6, 1 ve 1966 snfn kurucu
ilevine yaplan arda, ileve gnderilen argumanlardr. Benzer biimde:
Complexc(10.2,5.3);
gibi bir nesne tanmlamasnda da parametre yaps
Complex(double,double);
biiminde olan kurucu ilev arlabilir. Nokta ieren ve sonuna ek almam olan
deimezlerin double trden deimez olarak ele alndn anmsayn. Peki, aadaki
rnekte Person isimli snfn hangi kurucu ilevi arlr?
Persony("NecatiErgin");
Dizgelerin ileme sokulduunda tr dntrme ilemiyle otomatik olarak const char *
trne dntrldn anmsayn. Bu durumda y isimli snf nesnesinin
tanmlanmasyla Person isimli snfn, const char * trnden gsterici parametresine sahip
olan kurucu ilevi arlr.
Eer tanmlama ilemi dier trden nesnelerde olduu gibi ayra almadan yaplmsa,
nesne yaratlrken varsaylan kurucu ilev yani parametresi olmayan kurucu ilev arlr.
rnein:
Datedate;
Personperson;
Complexc;
Yukardaki date, person ve c nesneleri iin varsaylan kurucu ilevler arlr.
Eer bir snf nesnesi ilk deer verilerek tanmlanyorsa, ilk deer olarak verilen tre
uygun kurucu ilev arlr. X bir snf olmak zere:
Xa=b
tanmlamasyla
Xa(b)
C++ Kitabi (73/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

tanmlamas tamamen edeerdir. Bu durumda rnein:


Persony="NecatiErgin";
gibi bir tanmlamayla,
Persony("NecatiErgin");
tanmlamas ayn anlamdadr. Bu biimde yalnzca tek parametreli kurucu ilevler
arlabilir. Zaten snf nesnelerine birden fazla deerle ilkdeer(ilk deer) verilemez. Snf
nesnelerine yaplarda olduu gibi kme ayralar arasnda ilkdeer(ilk deer) verme de
sz konusu deildir. rnein,
Xa={10,20,30};

//Geersiz

a, X trnden bir snf nesnesi ise bu biimde ilkdeer(ilk deer) verilemez. Aslnda
istisna olarak zel baz snflara kme ayralar ile ilk deer verilebilir. Ancak bu konuyu
ileride ele alacaz.
Aadaki snf bildirimini inceleyin, izleyen rnei yazarak altrn:
#include<iostream>
#include<ctime>
classDate{
public:
Date();
Date(int,int,int);
voiddisplay();
private:
intday,month,year;
};
usingnamespacestd;
Date::Date()
{
time_ttimer=time(0);
tm*tptr=localtime(&timer);
day=tptr>tm_mday;
month=tptr>tm_mon+1;
year=tptr>tm_year+1900;
}
Date::Date(intd,intm,inty)
{
day=d;
month=m;
year=y;
}
voidDate::display()
{
cout<<day<<'/'<<month<<'/'<<year;
}
intmain()
{
C++ Kitabi (74/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Datedate1;
date1.display();
Datedate2(28,10,1998);
cout<<endl;
date2.display();
cout<<endl;
return0;
}
rneimizde,
Datedate1;
tanmlamasyla snfn varsaylan kurucu ilevi arlyor. Varsaylan kurucu ilev sistem
tarihini alarak snfn elemanlarna yerletiriyor. rnein, kurucu ilev altrldnda date
nesnesinin elemanlar yle doldurulmu olsun.

rneimizde daha sonra,


date1.display();
arsnn yapldn gryorsunuz. display ilevi ile ekrana yazdrlan day, month ve
year, date1 nesnesinin elemanlardr deil mi? Yerel snf nesnelerine ilikin kurucu
ilevler, programn ak nesnenin tanmlama noktasna geldiinde arlacana gre,
Datedate2(4,3,1964);
gibi bir tanmlamayla
Date(int,int,int);
bildirimine uygun olan kurucu ilev arlr. Bu ilev argman olarak gnderilen deerleri
snfn elemanlarna yerletirir. Bu durumda date2 nesnesinin elemanlar kurucu ilev
arldktan sonra yle olur:

rneimizde daha sonra,


date2.display()
C++ Kitabi (75/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

ile date2 nesnesinin veri elemanlarnn yazdrldn gryorsunuz.


Global deikenler programn bellee yklenmesiyle yaratldklarna gre, global snf
nesnelerine ilikin kurucu ilevler de main ilevinden nce altrlr. Aadaki rnei
inceleyin:
class X {
int a;
public:
X(int);
void display();
};
#include <iostream>
using namespace std;
X::X(int n)
{
a = n;
cout << "X snfnn kurucu ilevi" << endl;
}
void X::display()
{
cout << a << endl;
}
X g = 20;
int main()
{
cout << "main ilevi balad" << endl;
g.display();
}

return 0;

rneimizde g snf nesnesine ilikin kurucu ilev main ilevinden nce arlr. Ekranda
unlar grmeniz gerekir:
Xsnfnnkurucuilevi
mainilevibalad
20
Eer birden fazla global snf nesnesi tanmlanmsa kurucu ilevlerin arlma sras
yukardan aaya dorudur. Yani daha yukarda tanmlanm snf nesnesinin kurucu
ilevi daha nce arlr.
Kurucu ilevler de varsaylan argmana sahip olabilir. Aada rnekte verilen Complex
snfn inceleyin:
classComplex{
doublereal,imag;
public:
Complex(double,double=0.);
voiddisplay();
};
Complex::Complex(doubler,doublei)
C++ Kitabi (76/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


{
real=r;
imag=i;
}

voidComplex::display()
{
cout<<real;
if(imag!=0)
cout<<"+"<<imag;
cout<<'\n';
}
intmain()
{
Complexc1(10);
c1.display();

//Complexx(10,0)

Complexc2(10,20);
c2.display();
return0;
}
Bir kurucu ilevin tm parametre deikenleri varsaylan deer alyorsa o kurucu ilev
varsaylan kurucu ilev olarak da kullanlabilir. rnein, Complex snfnn kurucu ilevi
aadaki gibi bildirilmi olsun:
classComplex{
public:
Complex(double=0,double=0);
//
};
Aadaki tanmlamalarn hepsi geerlidir:
Complexx;
Complexy(10);
Complexz(10,20);

// Complex(0,0)ileaynanlamda
// Complex(10,0)ileaynanlamda

Bir snf iin hi bir kurucu ilev yazlmayabilir. Bu durumda derleyici varsaylan kurucu
ilevi kendisi yazar. Yani bir snf iin hibir kurucu ilev yazlmasa da, varsaylan kurucu
ilev varm gibi nesne tanmlanabilir. rnein:
classPoint{
public:
voidset(int,int);
voiddisplay();
private:
intx,y;
};
Grld gibi, Point snfnn hi kurucu ilevi yok. Bu durumda varsaylan kurucu ilev
varm gibi nesne tanmlanmas, herhangi bir hataya yol amaz.

C++ Kitabi (77/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Pointpt;

//Geerli

Peki derleyicinin yazd varsaylan kurucu ilev tam olarak ne i yapar? Bu konuyu
ileride ele alacaz. imdilik yle dnebiliriz: Bir kurucu ilevin yapmas gereken baz
isel ilemler sz konusudur. Bu ilemlerin her durumda yaplmas gerekir. Derleyici bu
isel ilemler iin bir kod yazar. Derleyicinin yazd bu kod, programcnn yazd her
kurucu ilevin en bana eklenir. Kurucu ilev programc tarafndan tanmlanmaz ise,
derleyicinin yazd varsaylan kurucu ilev, yalnzca derleyicinin yazd kod parasndan
oluur.
Snfn en az bir kurucu ilevi varsa, ama varsaylan kurucu ilevi yoksa bu durumda
varsaylan kurucu ilev arlacak biimde nesne tanmlanmas geersizdir. nk bu
durumda artk derleyici otomatik olarak varsaylan kurucu ilevi yazmaz. rnein:
classPoint{
public:
Point(int,int);
//...
private:
intx,y;
};
gibi bir snf bildiriminden sonra,
Pointpt;

//Geersiz!

Biiminde bir nesne tanmlanamaz. Fakat tabi,


Pointpt(10,20);
gibi bir nesne tanmlamas geerlidir.

Kurucu levin Snfn protected ya da private Blmnde


Bildirilmesi
Bir ye ilev nasl snfn herhangi bir blmnde bildirilebiliyorsa, snfn kurucu ilevi de
snfn herhangi bir blmnde bildirilebilir. Yani kurucu ilevin snfn public blmnde
bildirilmesi zorunda deildir.
Kurucu ilevin snfn private blmnde bildirildiini dnelim. Peki, bu durumda ne
olur? Global bir ilev iinde snfn private blmne eriilemeyeceine gre, bir snf
nesnesi yaratlmas durumunda derleme zamannda hata oluur, deil mi?
Aadaki rnei inceleyin:
classA{
private:
A();
voidfoo();
};
intmain()
{
Aa;
//Geersiz!
}
Bir ye ilev iinden, private blmde bildirilen bir baka ye ilev arlabilir, deil mi?
Bu durumda, rnein A snfnn bir baka ye ilevi olan foo ilevi iinde A snf trnden
bir nesne tanmlanabilir:
C++ Kitabi (78/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

voidA::foo()
{
Aa;
//Geerli
}
leride, kurucu ilevin private ya da protected blmde bildirilmesinden fayda
salanabilecek baz kod kalplar da inceleyeceiz.
Kurucu ilevleri dier ye ilevlerden ayran bir baka zellik de, bu ilevlerin programc
tarafndan dorudan arlamamasdr:
classX{
public:
X();
};
Voidfoo()
{
Xobject;
X.X();
}

//Geersiz!

Snfn Sonlandrc levi


Bir snf nesnesi bellekten boaltlaca zaman derleyici tarafndan arlan ye ileve
snfn sonlandrc ilevi (destructor) denir. Nasl kurucu ilev nesne yaratldnda
arlyorsa, sonlandrc ilev de nesnenin bellekten boaltlaca zaman, yani nesnenin
mr sona erdiinde arlr.
Sonlandrc ilevin ismi snf ismiyle ayndr. Ancak ismin nne ~ atomu eklenmitir. Yani
sonlandrc ilevin ismi ~Snfsmi biimindedir. Aadaki snf bildirimini inceleyin:
classPerson{
public:
Person(constchar*);
//Di?eryeilevler
~Person();
private:
char*name;
intno;
};

//Kurucuilev
//Sonlandrcilev

Person snfnn sonlandrc ilevi,


~Person();
bildirimi ile belirtilmi olandr. Bu ilevin tanm da kurala uygun olarak,
Person::~Person()
{
//...
}
biiminde yaplr. Sonlandrc ilevlerin de geri dn deerleri yoktur. Geri dn
deerinin tr yerine hi birey yazlmaz. Bu durum onlarn int ya da void geri dn
deerine sahip olduu anlamna gelmez.
Snfn sonlandrc ilevi tektir. Parametresi void olmak zorundadr. Yani parametresi
olmamak zorundadr. C++da parametre ayrac iine void yazmakla hibir ey
C++ Kitabi (79/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


yazmamann ayn anlama geldiini anmsayn. Bu durumda snfn birden fazla sonlandrc
ilevi de olamaz.
Snfn sonlandrc ilevi, snf nesnesi bellekten boaltlaca zaman arlr. Yerel
deikenlerin program aknn tanmlanma blounu bitirmesiyle, global deikenlerin ise
programn sonlanmasyla bellekten boaltldn anmsayn. Bu durumda yerel snf
nesnelerine ilikin sonlandrc ilevler deikenin tanmland blounun sonunda, global
snf nesnelerine ilikin sonlandrc ilevler de main ilevi sonlandnda arlr.
Aadaki rnei inceleyin:

#include <iostream>
#include <cstdio>
#include <cstdlib>
class File {
public:
File(const char *);
void type();
~File();
private:
FILE *fp;
};
using namespace std;
File::File(const char *fname)
{
if ((fp = fopen(fname, "r")) == NULL) {
cout << "Cannot open file..." << endl;
exit(EXIT_FAILURE);
}
}
void File::type()
{
int ch;
fseek(fp, 0L, SEEK_SET);
while ((ch = fgetc(fp)) != EOF)
putchar(ch);
}
File::~File ()
{
fclose(fp);
}
int main()
{
File file = "c:\\autoexec.bat";
{
File file = "c:\\config.sys";
file.type();
}
file.type();
}

return 0;

C++ Kitabi (80/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Verilen rnekte File snfnn kurucu ilevi ismini ald dosyay ayor. Alan dosyaya
ilikin FILE trnden adres snfn fp isimli elemannda saklanyor. Sonlandrc ilev de
alm olan dosyay kapatyor. Dosyann almas ve kapatlmas ilemlerinin kurucu ve
sonlandrc ilevler tarafndan otomatik olarak yapldn gryorsunuz. rneimizdeki
kurucu ve sonlandrc ilevlerin arlma yerlerine dikkat edin. Yerel snf nesneleri iin
sonlandrc ilevler tanmlandklar bloklarn sonlarnda arlr.
C++da kurucu ve sonlandrc ilevlere ilikin her zaman geerli olan yle bir kural
vardr: Sonlandrc ilevler kurucu ilevler ile ters srada arlr. Yani kurucu ilevi daha
nce altrlan snf nesnesinin sonlandrc ilevi deha sonra altrlr. rnein a
nesnesinin kurucu ilevi b nesnesinin kurucu ilevinden daha nce arlmsa a
nesnesinin sonlandrc ilevi de b nesnesinin sonlandrc ilevinden daha sonra arlr.
Yukardaki rnekte grdnz gibi, x nesnesinin kurucu ilevi ak dikkate alndnda y
nesnesinin kurucu ilevinden daha nce arlmtr.
Bu zellik ayn bilinirlik alan iindeki snf nesneleri iin daha nemlidir. rnein,
{
Date date1, date2;
//
}
Burada kurucu ilevler nce date1 sonra date2 srasyla, sonlandrc ilevler ise ters
srada yani nce date2 sonra date1 srasyla arlr.
Global snf nesnelerine ilikin sonlandrc ilevler main ilevinden sonra arlr. Yukarda
verilen kurala gre, birden fazla global snf nesnesi varsa kurucu ilevlerin arlma
srasna ters srada sonlandrc ilevler arlr. Yani kaynak kod iinde en aada
tanmlanan nesnenin sonlandrc ilevi en nce arlr.
Aadaki programda kurucu ve sonlandrc ilevler hangi srada arlr?
classX{
//
};
Xa;
Xb;
intmain()
{
Xc;
Xd;
//
{
Xe;
//..
}
}
Burada programn ak dikkate alndnda kurucu ilevlerin arlma sras a, b, c, d, e
biiminde, sonlandrc ilevlerin arlma sras ise e, d, c, b, a biiminde olur.
Bir ilev return deyimi ile sonlandrlrsa, ilev sonlandrlmadan nce, o noktaya kadar
tanmlanm btn yerel snf nesneleri iin sonlandrc ilevler arlr. X bir snf olmak
zere rnein:

C++ Kitabi (81/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


intfoo()
{
Xa;
//
{
Xb;
//
if(func())
return1;
//
}
Xc;
//
return0;
}
Yukardaki foo isimli ilevde, i blokta func ilevi arlarak geri dn deeri snanyor. Bu
ilevin geri dn deeri sfr d bir deerse, ilev sonlandrlyor. Derleyici ilev
sonlanmadan nce, yaratlm olan a ve b nesneleri iin sonlandrc ilevleri de arr. c
nesnesinin programn aknn return ileminin yapld noktaya gelene kadar
tanmlanmadn gryorsunuz. Tabii bu durumda c nesnesi iin sonlandrc ilev
arlmaz.
Bir snf iin sonlandrc ilev yazmak zorunlu deildir. Sonlandrc ilev yazlmamsa,
derleyici snfn sonlandrc ilevini kendisi yazar. Derleyicinin yazaca sonlandrc ilevin
imdilik syle olduunu varsayabilirsiniz:
Myclass::~Myclass()
{
}
Zaten her snfn sonlandrc ileve sahip olmas gerekmez. Fakat kurucu ilev ile
yaplanlarn otomatik olarak geri alnmas isteniyorsa sonlandrc ilevin yazlmas
anlamldr. Genel olarak dsal bir kaynak kullanan snflar, kurucu ilevleriyle kendilerine
balanan bir kayna, sonlandrc ilevler ile serbest brakrlar ya da geri verirler.
Son olarak herhangi bir ilev iinde tm programn exit ilevi ile sonlandrlmas zerinde
duralm. exit ilevi nerede arlm olursa olsun, program iinde tanmlanm tm global
snf nesneleri iin eer varsa sonlandrc ilevler arlr. Tabii exit ilevi ile programn
sonlandrlmas durumunda yerel snf nesneleri iin sonlandrc ilevler arlmaz.

Kurucu ve Sonlandrc levler Ne Amala Kullanlr


Kurucu ilevler snfn elemanlarna belirli ilkdeerleri vermek ve eitli ilk ilemleri
yapmak amacyla tanmlanr. Bir snf nesnesi tanmlandnda eitli ilk ilemlerin kurucu
ilevler tarafndan gizli bir biimde yaplmas alglamay kolaylatrr. Bylece snf
nesnesini kullanan kodlar (client), snf nesnesini kullanmadan nce herhangi bir ilem
yapmak zorunda kalmazl. Gerekli ilemler snfn kendi kodu tarafndan yaplr. Bu ekilde
bir snf nesnesinin kararl bir ekilde ilk deerini almas salanr. lkdeer verme ilemi
otomatik olarak arlan bir ilev tarafndan deil de, snf kullanan kod paras
tarafndan aka arlmas gereken bir ilev tarafndan yaplsayd, hata oluma riski ok
daha fazla olurdu, deil mi? Kurucu ilevler, veri gizleme (data hiding) prensibinin
gerekletirilmesini salayan temel aralardan biridir.
Ayn ekilde sonlandrc ilev ise kurucu ilev ile yaplan ilk ilemlerin geri alnmas iin
kullanlr. rnein, kurucu ilev bir dosyay amsa, sonlandrc ilevi dosyay kapatabilir.
Ya da kurucu ilev seri portu eitli deerlerle ayarlam olabilir. Bu durumda sonlandrc
ilevi de bu ayarlar eski haline getirebilir. Ancak en sk karlalan durum, kurucu
ilevinin(ilevin) new ileci ile dinamik olarak bellekte bir yer ayrmas ve sonlandrc
ilevin de ayrlan yeri delete ileci ile bu alan geri vermesidir. Aadaki rnei inceleyin:
C++ Kitabi (82/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

#include <iostream>
#include <cstdlib>
class Array {
public:
Array(int);
void display();
int get_item(int);
void set_item(int,int);
int get_max();
~Array();
private:
int *pArray;
int size;
};
using namespace std;
Array::Array(int length)
{
pArray = new int[size = length];
}
Array::~Array()
{
delete [] pArray;
}
void Array::display()
{
cout << '(';
for (int i = 0; i < size; ++i)
cout << pArray[i] << ' ';
cout << ')';
}
int Array::get_item(int index)
{
if (index < 0 || index >= size) {
cout << "Geersiz index: " <<
exit(1);
}
return pArray[index];
}

index << endl;

void Array::set_item(int index, int val)


{
if (index < 0 || index >= size) {
cout << "Geersiz index: " << index << endl;
exit(EXIT_FAILURE);
}
pArray[index] = val;
}
int Array::get_max()
{
int max = pArray[0];

C++ Kitabi (83/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


for (int i = 1; i < size; ++i)
if (max < pArray[i])
max = pArray[i];
return max;
}
const int size = 10;
int main()
{
Array x = size;
for (int i = 0; i < size; ++i)
x.set_item(i, rand());
x.display();
cout << "max = " << x.get_max() << endl;
return 0;
}
rneimizde int trden bir dizi bir snfla temsil ediliyor. Snfn kurucu ilev bir dizi iin
free store alanndan bir blok ayrm sonlandrc ilevi de bu dinamik blou geri veriyor.
get_item ve set_item ilevlerinin snr kontrol yaparak diziye eleman yerletirme ve
dizinin elemannn deerini alma ilemlerini yaptn gryorsunuz. Ayrca, get_max
isimli ilev dizinin en byk elemann buluyor. display ilevi ise dizinin btn elemanlarn
ekrana yazdryor.

Snf Trnden Gstericiler ve Adresler


Bir snf nesnesinin adresi alnabilir. Elde edilen adres nesnenin ilikin olduu snfn
trndendir, ayn trden bir gsterici deikene atanmaldr. Daha nceki rneklerde
bildirilen Date isimli snfa ilikin bir gsterici deiken tanmlanm olsun:
Date*p;
ile p gsterici deikeninin gsterdii yer, yani *p, Date snf trndendir. Baka bir
deyile, p gstericisinin gsterdii yerde Date snf trnden bir nesne vardr. Derleyici bu
adresten balayarak ilk sizeof(int) kadar byte snfn day eleman, sonraki iki sizeof(int)
kadar byte ise srasyla month ve year elemanlar olarak ele alr. imdi bir snf
nesnesinin adresinin bir snf gstericisine atandnda neler olduunu adm adm
inceleyelim:
Aadaki ekil int trnn 4 byte olduu varsaymyla izilmitir. 00501FC0 yalnzca
konuya aklk getirmek amacyla kullanlan rastgele bir adrestir.
Datedate;

//Datesnfnnverielemanlariinyerayrlyor.

Date*ptr;
ptr=&date;

C++ Kitabi (84/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Artk ptr adresinden balayan bilgiler date snf nesnesinin elemanlar olarak yorumlanr.
Bu durumda *ptr ifadesi ile date ayn nesneleri belirtir.
Snf trnden bir gsterici yoluyla snfn elemanlarna ve ye ilevlerine -> ileci ile
eriilebilir. rnein artk:
ptr>display()
ile display ye ilevi arlabilir. Bu durumda display ye ilevi ptr adresindeki yani ptrnin
deeri olan adresten balayan elemanlar kullanr. Daha ak bir anlatmla,
date.display();
gibi bir arda display ye ilevi date nesnesinin veri elemanlarn kullanyor. Yani display
ilevi iinde kullanlan day, month, year deikenleri Date snfnn elemanlardr. te,
ptr>display();
arsyla da display ye ilevi p adresindeki nesnenin elemanlarn kullanr. ptr adresinde
ptr=&date
atamas ile date nesnesinin adresi olduuna gre, display ilevi de datein elemanlarn
kullanr, deil mi? Yani iki ilem edeerdir.
Tabii -> ileci yerine ncelik ayrac ve nokta ilelerini de kullanlabilir:
(*ptr).display();
ile
ptr>display();
edeerdir. Snf gstericisi yoluyla snfn elemanlarna yine -> ileci ile eriilebilir. Ancak
phesiz elemanlarn eriilebilir olmas yani snfn public blmnde bildirilmi olmalar
gerekir. rnein:
ptr>day=10;
gibi bir ifadenin geerli olmas iin day elemannn snfn public blmnde olmas gerekir.
Aadaki kodu yazarak snayn:
intmain()
{
Datex;
Date*p;
p=&x;
p>display();
return0;
}

C++ Kitabi (85/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Snfn kurucu ilevi yalnzca snf nesnesi yaratlrken arlr. Bir snf trnden gsterici
deiken tanmlandnda kurucu ilevi arlmaz. rnein,
Datedate;
Date*p;

//Kurucuileva?rlr,nknesneyaratlm!
//Kurucuileva?rlmaz,yalnzcagstericiyaratlm!

Snf Trnden Referanslar


Bir referans deikeni bir snf nesnesinin de yerine geebilir. Snf trnden referanslar
ayn trden bir snf nesnesi ile ilkdeer vererek tanmlanr:
Complexa(10,20);
Complex&r=a;
Burada Complex snf trnden r isimli referansa yine Complex snf trnden a
nesnesiyle ilkdeer veriliyor. Bylece artk r referans a nesnesinin yerine geer. rnin
kullanld her yerde a nesnesi kullanlm olur. r referans a nesnesinin yerine getiine
gre, referans yoluyla snfn elemanlarna ve ye ilevlerine -tpk yaplarda olduu gibinokta ileci ile eriilir. rnein Complex snfnn display isimli bir ye ilevi olduunu
varsayalm. Bu ye ilev r referans ile,
r.display();
biiminde arlabilir. Bir referans ile bir ye ilev arldnda, ye ilev referansn
yerine getii nesnenin elemanlarn kullanr. rnein yukardaki arda display ye ilevi
r referansnn yerine getii nesnenin elemanlarn kullanr.
Snf trnden bir referansa bir deimez ile ya da baka trden bir nesneyle ilkdeer
verme ilemi baz durumlarda geerli olabilir. Bu durumu "dntren kurucu ilev"
(conversion constructor) bal altnda ele alacaz. Aadaki rnei yazarak altrn:

C++ Kitabi (86/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include <iostream>
class Complex {
public:
Complex(double = 0, double = 0);
void display();
private:
double real, imag;
};
using namespace std;
Complex::Complex(double r, double i)
{
real = r;
imag = i;
}
void Complex::display()
{
cout << real;
if (imag > 0)
cout << "+ ";
else
cout << " ";
cout << imag << "i";
}
int main()
{
Complex a(10, -20);
Complex &r = a;
r.display();
return 0;
}
ncelikle bir nokta zerinde aklama yapalm. Complex snfnn kurucu ilevinin
parametre deikenleri varsaylan deerler alyor. Bu kurucu ilev, hem tek parametreli
kurucu ilev hem de varsaylan kurucu ilev olarak kullanlabilir. rneimizde r isimli
referansa a nesnesi ile ilkdeer verildiini gryorsunuz. Bu durumda r referans a
deikeninin yerine geer. Artk, r.display() arsnda, display ye ilevi r referansnn
yerine getii elemanlar kullanr.

Snf Nesnelerinin levlere Geirilmesi


Bir snf nesnesiyle ilgili ilerin, bir snfn ye ilevleri tarafndan yaplmas zorunlu
deildir. phesiz global ilevler de snf nesneleri zerinde ilemler yapabilir. imdi snf
nesnelerinin ilevlere geirilmesi zerinde duracaz. Snf nesnelerinin ilevlere
geirilmesi, tpk yaplarda olduu gibi yolla yaplabilir.

Snf Nesnesinin Deerinin leve Aktarlmas


Bu yntem bildiimiz "deerle arma" (call by value) ynteminden baka bir ey
deildir. Bu yntemde ilevin parametre deikeni snf trnden bir nesne olur. lev de
baka bir snf nesnesinin deeri ile arlr. nk C++da tpk yaplar gibi ayn trden
snf nesneleri de birbirlerine dorudan atanabilir. Byle bir atama srasnda snfn
elemanlar karlkl olarak birbirine kopyalanr.
C++da bir snf nesnesi baka bir snf nesnesi ile ilk deer verilerek tanmlanrsa,
tanmlanan snf nesnesi iin zel bir kurucu ilev arlr. Bu kurucu ileve "kopyalayan
kurucu ilev" (copy constructor) denir. Programc kopyalayan kurucu ilevi tanmlamaz ise
derleyici bu ilevi kendi tanmlar. Derleyicinin yazd kopyalayan kurucu ilev yaratlan
C++ Kitabi (87/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


snf nesnesinin tm elemanlarna, ilkdeer veren snf nesnesinin elemanlarnn deerini
atar. Kopyalayan kurucu ilevi ileride ayr bir balk altnda ele alacaz.
Daha nce verdiimiz Date snfnnn kullanld aadaki rnei inceleyin:
voidfunc(Dated)
{
//
a.display();
}
intmain()
{
Datedate;
func(date);

return0;
}
Bu rnekte func ilevi arsnda kullanlan date deikeni func ilevinin parametre
deikeni olan a deikenine ilkdeerini verir. Bu durumda date deikeninin tm
elemanlar bire bir dnin elemanlarna kopyalanr. Ancak byle bir ar, nesnenin btn
elemanlarnn kopyalanmasn gerektirdiinden ounlukla tercih edilmez. Bu durum
aktarm srasnda gereksiz bir zaman kayb oluturur. arlan ilev yerel bir snf nesnesi
zerinde deiiklik yapamaz.

Nesnenin Adresinin leve Geirilmesi


Bu ar biiminde ileve bir snf nesnesinin adresi gnderilir. levin parametre deikeni
de ayn snf trnden bir gsterici deiken olur. Bu durumda yalnzca snf nesnesine
ilikin veri blounun adresi ileve geirilir. lev iinde nesnenin elemanlarna ve snfn
ye ilevlerine -> ileci ile eriilebilir.
Aadaki rnei inceleyin:
voidfunc(Date*pdate)
{
//
pdate>display();
}
intmain()
{
Datedate;
func(&date);

return0;
}
phesiz, bir snf nesnesinin adres yoluyla ilevlere geirilmesi, snfn elemanlarnn
bellekte bitiik bir biimde bulunmas ile mmkn olur. Bu yntemle ilev parametre
olarak ald adresteki nesneyi de deitirebilir.

Nesnenin Referans Yoluyla leve Geirilmesi


Referanslar da aslnda adres tutan deikenler olduuna gre, nesnenin adresi referans
yoluyla da ilevlere geirilebilir. Bu yntemde ilev snf nesnesinin kendisi ile arlr.
levin parametre deikeni de snf trnden bir referans olur. levin parametre
deikeni olan referans ileve gnderilen argman olan nesnenin yerine geer. Artk ilev
C++ Kitabi (88/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


iinde nesnenin elemanlarna ve snfn ye ilevlerine nokta ilecinin terimi olan referans
ile eriilir.
Aadaki rnei de inceleyin:
voidfunc(Date&rdate)
{
//
rdate.display();
}
intmain()
{
Datedate;
func(date);
return0;
}
Snf nesnesinin referans yoluyla aktarm gsterici yoluyla aktarm ile edeer
verimliliktedir. Ancak referanslar konusunda da belirtildii gibi, bir ilev ald adresteki
bilgiyi deitirmiyorsa okunabilirlik bakmndan const referans ya da const gsterici tercih
edilmelidir.

Snf Blmlerinin ve Eriim Kurallarnn Anlam


Daha nce de akladmz gibi snfn ye ilevleri ve elemanlar snfn istenilen bir
blmne yerletirilebilir. Yani programc bu konuda zgrdr. Ancak genellikle snfn
darya hizmet veren ye ilevlerinin bildirimleri snfn public blmne, snfn veri
elemanlar ise snfn private blmne yerletirilir. Yukarda verilen rnekleri
incelediinizde bu ynde hareket edildiini greceksiniz.
Snfn darya hizmet veren ye ilevleri snfn public, snfn elemanlar da snfn private
blme yerletirilirse, dardan snf nesnesi ya da gstericisi yoluyla ye ilevlere
eriilebilir fakat snfn elemanlarna eriilemez. Bu durumda elemanlar dorudan deil
ancak snfn ye ilevleri yardmyla kullanlabilir.

Snfn kodlarn yazan kii byle bir durumda snfn elemanlarna eriimi salamak
istiyorsa snfn private elemanlarnn deerlerini alan ve onlara deer yerletiren bir grup
ye ilev yazabilir: Bu ye ilevler ngilizce genellikle GetXXX ya da SetXXX biiminde
isimlendirilir. rnein:

C++ Kitabi (89/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


class Date {
private:
int day, month, year;(mDay, mMonth, mYear)
public:
Date();
Date(int d, int m, int y);
void display();
//Snfn elemanlarnn deerlerini alan ye ilevler
int get_day ();
int get_month();
int get_year();
//Snfn elemanlarna deer yerletiren ye ilevler
void set(int, int, int);
void set_day(int);
void set_month(int);
void set_year(int);
// Dier ye ilevler
};
Yukarda verilen Date snfnn day, month ve year elemanlar private blme
yerletirilmi. Bu yzden bu elemanlara dorudan erimek mmkn olmaz. rnein date,
Date trnden bir nesne olsun. date nesnesinin year elemannn deerini almak ya da
year elemanna bir deer verilmek istensin.
x=date.year;
date.year=2000;

//Geersiz!
//Geersiz!

gibi ilemler eriim kurallarna gre geerli deildir. Ancak bu ilemler get_year ve
set_year ye ilevleri arlarak gerekletirilebilir:
x=date.get_year();
date.set_year(2000);
ounlukla bir snf baka kod paralarna hizmet verir. Snf kodlarndan hizmet alan
kodlar (client codes) snfn public arayzne gre yazlr. Zaten daha nce de akland
gibi snftan hizmet alan bir kod parasnn snfn private blmne erimesi mmkn
deildir. Snfn public blm ya da snfn public arayz, snf bildiriminde public eriim
belirteci altndan bildirilen blmdr.
Snfn elemanlarnn private blme yerletirilmesinin en nemli faydas snfn
elemanlarnn genel yaps deitirildiinde, snftan hizmet alan kodlarn bundan
etkilenmesinin engellenmesidir. Yani snfn public arayzne bal kalmak kouluyla
snfn private ksmnda yaplacak deimeler sonucunda, snftan hizmet alan kodlarda bir
deiiklik yaplmas gerekmez. Aslnda yaplan i, snfn arayzyle (interface) snfn
kendi kodlarnn (implementation) birbirinden ayrlmas olarak tanmlanabilir. Snfn
arayznde bir deiiklik yapmadan snfn kendi kodlarn deitirmek snf kullanan
kodlarda bir deiiklik yaplmasn engeller. Byk projeler sz konu olduunda kodlarda
bir deiiklik yaplmasnn maliyeti ok azaltlm olur. Aadaki Date snfnn kodlarn ve
onu kullanan rnek bir kodu inceleyin:
#include <iostream>
#include <ctime>
using namespace std;
Date::Date()
{
time_t timer = time(0);;
tm *tptr = localtime(&timer);
C++ Kitabi (90/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

day = tptr -> tm_mday;


month = tptr -> tm_mon + 1;
year = tptr -> tm_year + 1900;

Date::Date(int d, int m, int y)


{
set(d, m, y);
}
void Date::display()
{
cout << day << " " << month << " " << year;
}
int Date::get_day()
{
return day;
}
int Date::get_month()
{
return month;
}
int Date::get_year()
{
return year;
}
void Date::set(int d, int m, int y)
{
day = d;
month = m;
year = y;
}
void Date::set_day(int d)
{
day = d;
}
void Date::set_month(int m)
{
month = m;
}
void Date::set_year(int y)
{
year = y;
}
Bu rnekteki day, month ve year elemanlarnn snfn public blmnde bildirilmi
olduunu gryorsunuz. day, month ve year elemanlarna erimek iin ye ilevleri
kullanmaya gerek yok, deil mi? Eriim dorudan gerekletirilebilir. imdi eriimin
dorudan yapld bir kod rnei verelim:

C++ Kitabi (91/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


intmain()
{
Datedate;
intd,m,y;
d=(date.day>15)?date.day1:date.day+1;
m=(date.month>6)?date.month1:date.month+1;
date.set_date(d,m,y);
//
return0;
}
Burada da Date snf trnden bir nesne tanmlanm. Date snf nesnesinin elemanlarna
snfn kurucu ilevi tarafndan o anki tarih bilgisi yerletirilir. Daha sonra bu tarih
bilgisinin gn ve ay deerlerine baklm ve duruma gre bu deerler bir artrlm ya da
azaltlm. Sonra da elde edilen deerin yeniden snfn veri elemanlarna set_date ye
ilevi ile yerletirildiini gryorsunuz. Buradaki kodu ok anlaml bulmayabilirsiniz;
rnek yalnzca snf kullanan koda rnek olarak verildi. Tabii siz snf kullanan kodun
yalnzca main olduunu dnmemelisiniz.
Snfn elemanlarn private blme yerletirip onlara ye ilevler yoluyla eriilmesinin bir
faydas olabilir mi? imdi buna da bir rnek verelim: Yukardaki Date snfnn veri
elemanlarnn genel yapsnn deitirildiini dnelim. rnein artk tarih bilgisinin int
trden day, month year veri elemanlarnda deil "dd/mm/yyyy" biiminde 11 elemanl
char trden bir dizi iinde tutulmasna karar verilmi olsun. Bu durumda snfn
elemanlarn dorudan kullanan kodun bir geerlilii kalacak m? Hayr! rnein,
d=(x.day>15)?x.day1:x.day+1;
m=(x.month>6)?x.month1:x.month+1;
Artk Date snfnn day ve month iiminde bir eleman olmadna gre bu kodlar da
geersiz hale gelir. O halde snf kullanan btn kodlar yeniden yazlmaldr. te eer bu
elemanlar snfn public blmne yerletirmeseydi o zaman bu elemanlara dorudan
eriilmeyecekti. Onlara erimek iin zorunlu olarak snfn public ye ilevleri
kullanlacakt. rnein, snfn day, month, year elemanlar snfn private blmnde
olsayd, kullanc kodlar da yle yazlm olurdu:
intmain()
{
Datex;
intd,m,y;
d=(x.get_day()>15)?x.get_day()1:x.get_day()+1;
m=(x.get_month()>6)?x.get_month()1:x.get_month()+1;
x.set_day(d,m,y);
return0;
}
imdi snfn veri yaps deitirildiinde snf kullanan kodlarn yeniden dzenlenmesine
gerek kalmaz. Tek yaplacak ey, ye ilevlerin yeni veri yapsna uygun olarak yeniden
yazlmalardr. rnein, tarih bilgisi karakter dizisi biiminde tutulacak olduunda snfn
ye ilevleri aadaki gibi deitirilirse, snf kullanan kodlarn hi biri deitirilmek
zorunda kalmaz:

C++ Kitabi (92/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

classDate{
public:
//
private:
chardate[11];
};
usingnamespacestd;
Date::Date()
{
time_ttimer=time(NULL);
structtm*tptr=localtime(&timer);
sprintf(date,"%02d/%02d/%04d",tptr>tm_mday,tptr>tm_mon+1,tptr
>tm_year+1900);
}
Date::Date(intd,intm,inty)
{
sprintf(date,"%02d/%02d/%04d",d,m,y);
}
voidDate::display()
{
puts(date);
}
intDate::get_day()
{
returnatoi(date);
}
intDate::get_month()
{
returnatoi(date+3);
}
intDate::get_year()
{
returnatoi(date+6);
}
voidDate::set_date(intd,intm,inty)
{
day=d;
month=m;
year=y;
}
voidDate::set_day(intd)
{
sprintf(date,"%02d",d);
date[2]='/';
}
voidDate::set_month(intm)
C++ Kitabi (93/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


{
sprintf(date+3,"%02d",d);
date[5]='/';
}

C++ Kitabi (94/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidDate::set_year(inty)
{
sprintf(date+5,"%02d",d);
date[5]='/';
}
intmain()
{
Datedate;
intd,m,y;
d=(date.get_day()>15)?date.get_day()1:date.get_day()+1;
m=(date.get_month()>6)?date.get_month()1:date.get_month()+
1;
date.set_day(d,m,y);
return0;
}
Gelin sonucu zetleyelim: Snfn isel yaps deitirildiinde snf kullanan kodlarn bu
deiimden etkilenmesi istenmiyorsa, snfn elemanlar private blme yerletirilmeli ve
eriimler ye ilevlerle yaplmaldr. Bylece snfn veri yaps deitirildiinde yalnzca
ye ilevleri yeniden yazmak yeterli olur.

Dinamik Snf Nesneleri


new ileciyle yalnzca C+ n doal veri trleri iin deil, snflar ve yaplar iin de dinamik
nesneler yaratlabilir: rnein:
classDate{
public:
Date();
Date(int,int,int);
//Di?eryeilevler
private:
intday,month,year;
};
Date*p=newDate;
deyimiyle sizeof(Date) uzunluunda dinamik bir blok elde ediliyor. Elde edilen dinamik
bloun balang adresi p gsterici deikenine atanyor. Bylelikle p gsterici deikeni
Date nesnesini gsteriyor.
Artk p gsterici deikeni ok ileci ile kullanlarak ye ilevler arlabilir. rnein,
p>display();
gibi bir ilemde display ye ilevi p gstericisinin iindeki adreste bulunan yani dinamik
olarak elde edilmi olan nesnenin elemanlarn kullanr.
Snfn kurucu ilevi yalnzca tanmlama yntemiyle nesne yaratldnda deil, dinamik
olarak nesne yaratldnda da arlr. rnein,
p=newDate;

//Kurucuileva?rlr

ilemiyle Date trnden dinamik bir nesne yaratlyor. Yaratlan bu dinamik nesne iin de
kurucu ilev arlr. Yani yukardaki ilemde srasyla unlar yaplr:

C++ Kitabi (95/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


1. sizeof(Date) uzunluunda free store zerinde dinamik bir blok elde edilir.
2. Elde edilen dinamik blok iin kurucu ilev arlr. arlan kurucu ileve this gstericisi
olarak elde edilen bloun balang adresi geirilir.
3. Yaratlan nesnenin adresi p gstericisine atanr.
Peki, dinamik olarak yaratlan snf nesneleri iin hangi kurucu ilev arlr? te eer snf
isminden sonra ayra alp parametre listesi yazlmamsa varsaylan kurucu ilevi
(default constructor) arlr. rnek verelim:
p=newDate;
burada yaratlan alan iin varsaylan varsaylan kurucu ilev arlr. Eer snf isminden
sonra ayra alp bir parametre listesi yazlrsa, o zaman parametre deikeni listesine
uygun olan kurucu ilevi arlr. rnein:
p=newDate(2,2,1989);
gibi bir yer ayrma ilemiyle parametrik yaps
Date(int,int,int);
biiminde olan kurucu ilev arlr. Peki aadaki gibi bir yer ayrma ileminde Person
snfnn hangi kurucu ilevi arlr?
p=newPerson("ErdemEker");
Dizgeler const char trden bir adres belirttiklerine gre, parametresi char trden gsterici
olan kurucu ilev arlr? Ayrca, snf isminden sonra ayra iine birey yazlmamas da
geerli bir durumdur. Bu durum, yaratlan dinamik nesne iin varsaylan kurucu ilevin
arlaca anlamna gelir.
p=newDate();
ile
p=newDate;
tamamen ayn anlamdadr.
new[] ileci ile birden fazla dinamik nesne yaratlabilir. rnein:
p=newDate[n];
burada n tane Date trnden nesnenin sabilecei byklkte bir bellek blou elde
ediliyor. Elde edilen bloun balang adresi p gsterici deikenine atanyor.

C++ Kitabi (96/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Bu biimde birden fazla snf nesnesi iin yer ayrldnda her snf nesnesi iin tek tek
varsaylan kurucu ilev arlr. Snf nesneleri iin baka bir kurucu ilevi armann yolu
yoktur. Aadaki gibi bir szdizimin geerli olabileceini dnebilirsiniz:
p=newDate[10](10,10,20);
Ancak byle bir szdizim geerli deildir!
C++da dinamik bellek ynetimi iin neden malloc ilevi yerine new gibi bir ilecin
kullanldn imdi belki de daha iyi anlayabilirsiniz. Dinamik yer elde etme ileminden
sonra derleyicinin kurucu ilevi arabilmesi iin, yer ayrma ileminin hangi trden
nesne iin yapldnn derleme zamannda bilinmesi gerekir. Eer byle bir anahtar
szck olmasayd, yer ayrma ilemleri yine malloc ileviyle yaplyor olsayd, derleyici bir
snf nesnesi iin yer ayrma ilemi yapldn nasl anlayabilirdi?
Bir snf nesnesi iin dinamik olarak ayrlan bellek blou delete ileci ile free store alanna
geri verilebilir. Bu durumda derleyici, dinamik bellek alann geri vermeden nce snfn
sonlandrc ilevini (destructor) arr. rnein p, Date trnden bir adres olsun:
delete p;
ilemiyle nce p adresindeki nesne iin sonlandrc ilevi arlr. Daha sonra bu nesne
iin ayrlm olan alan geri verilir.
Eer bir dizi snf nesnesi iin dinamik olarak yer ayrlmsa, derleyici tm dinamik
nesneler iin tek tek sonlandrc ilevleri arr:
#include <iostream>
class A {
public:
A();
~A();
};
A::A()
{
std::cout << "A::A()" << std::endl;
}
A::~A()
{
std::cout << "A::~A()" << std::endl;
}
int main()
{
A *pd = new A[5];
delete[] pd;
}

return 0;

Dinamik bir snf dizisi iin ayrlan alann boaltlmas durumunda [] unutulmamaldr. Eer
[] unutulursa, sorunlu durumlarla karlalabilir. Bu durumu new ve delete ile
ilevlerinin ayrntl olarak anlatld blmde ele alacaz.

Dinamik Snf Nesneleri Ne Amala Kullanlr


Bildiimiz gibi, kurucu ilevler nesne yaratldnda, sonlandrc ilevler ise nesne
bellekten boaltlaca zaman arlr. Bu durumda yerel snf nesnelerinin yaratlmas ve
C++ Kitabi (97/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


bellekten boaltlmas tanmlama noktasna baldr. Bir snf nesnesinin istenilen bir
noktada yaratlmasn ve istenilen bir noktada yok edilmesi ancak dinamik bellek
ynetimiyle salanabilir. rnein:
{
p=newX;
}
deletep;
Nesnelerin yaratlp boaltlma yerlerine bakn. Nesne yerel olarak yaratlsayd bu blok
yapsyla byle bir sonucu elde edilebilir miydi? Bir snfn bir ye ilevi iinde baka bir
snf nesnesinin yaratlmas ve baka bir ye ilev iinde de yok edilmesi durumlarna
sklkla rastlanr. rnein:
voidWnd::initialize()
{
pScr=newScr;
//...
}
voidWnd::close()
{
//...
deletepScr;
}
Burada Scr snf trnden nesne Wnd snfnn initialize ye ilevi iinde dinamik olarak
yaratlyor, close ye ilevi iinde yok ediliyor. Bu ilem ancak nesnenin dinamik olarak
yaratlmasyla gerekletirilebilir. Bu rneklerden de grld gibi nesnenin dinamik
olarak yaratlmasnn asl nedeni dinamik bellek kullanmak deildir. Snfn kurucu ilevinin
ve snfn sonlandrc ilevin istenilen yerlerde arlmasn salamaktr.

C++ Kitabi (98/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

const ye levler ve const Snf Nesneleri


ncelikle const anahtar szcnn daha nce rendiimiz anlamlarn hatrlayalm:
const anahtar szc bir deikenin tanmlanmasnda kullanldnda, tanmlanan
deikenin deerinin deitirilemeyeceini gsteriyordu:
constintx=5;
x=10;

//xnesnesininde?eride?itirilemez.
//Geersiz

Deikenin bir gsterici olmas durumunda ise, const anahtar szcnn verdii anlam
anahtar szcn kullanld yere gre deiiyordu:
intx=5;
constint*ptr=&x;
*ptr=1; //Geersiz!
Yukardaki rnekte ptr gsterdii yer const olan bir gsterici deikendir. ptr deikenine
baka bir adres atanabilir ama *ptr, yani ptrnin gsterdii nesne atama yoluyla
deitirilemez.
intx=5,y=10;
int*constptr=&x;
ptr=&y; //Geersiz!
Yukardaki rnekte ptr kendisi const olan bir gstericidir. ptr gstericisinin gsterdii
nesneye, yani *ptr ifadesine atama yaplabilir. Ancak ptr nesnesine bir atama yaplamaz.
Yani ptr gstericisinin bir baka nesneyi gstermesi salanamaz.
intx=5,y=10;
constint*constptr=&x;
*ptr=1;
//Geersiz!
ptr=&y;
//Geersiz!
Yukardaki rnekte ise const anahtar szcnn her iki anlam birletiriliyor. Yani ptr
hem kendisi hem de gsterdii yer const olan bir gsterici deikendir. Ne ptr nesnesine
ne de ptrnin gsterdii nesneye, yani *ptr nesnesine atama yaplabilir.
const anahtar szc bir ilev bildiriminde ya da tanmnda ilevin geri dn deerinin
tr bilgisinden nce de yazlabilir :
constchar*func();
Yukardaki bildirimden func ilevin geri dn deeri olan adresteki nesnenin
deitirilemeyecei sonucu kar:
*func()='m'; //Geersiz!
phesiz yukardaki kurallarn hepsi referanslar iin de geerlidir.
intx=5;
constint&r=x;
r=20;
//Geersiz!
constchar&func();
func()=5; //Geersiz!

const Anahtar Szcnn Yeni Bir Anlam

C++ Kitabi (99/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


C++ dilinde bir ye ilev const anahtar szc ile bildirilebilir. Bunun iin const anahtar
szcn hem ilevin bildiriminde hem de ilevin tanmnda, parametre ayracnn sana
yerletirmek gerekir. rnein:
classDate{
public:
Date(int,int,int);
voidset(int,int,int);
intget_day()const;
intget_mon()const;
intget_year()const;
voiddisplay()const;
//
private:
intday,mon,year;
};
Yukardaki rnekte Date isimli snfn get_day, get_mon, get_year ve display isimli ye
ilevleri const ye ilevler olarak bildiriliyor. Bu ilevlerin tanmlar da aadaki gibi
yaplabilir:
#include<iostream>
intDate::get_day()const
{
returnday;
}
intDate::get_mon()const
{
returnmon;
}
intDate::get_year()const
{
returnyear;
}
voidDate::display()const
{
std::cout<<day<<""<<mon<<""<<year;
}
const anahtar szcnn yalnzca ilevin bildiriminde deil, ilevin tanmnda da
yazlmas zorunludur. Yalnzca birinde yazlm olmas geersizdir. Ayrca const anahtar
szcnn yerletirildii yere de dikkat edilmelidir. Eer bu anahtar szck en sola
konulmu olsayd, ilevin geri dn deerinin const olduu, yani deitirilemeyecei
anlamna gelirdi.

const ye lev ne Anlama Gelir


const bir ye ilev ait olduu snfn elemanlarn deitiremez. Yukardaki rnekte
get_day, get_mon, get_year ve display ilevleri Date snfnn day, mon, year
elemanlarnn deerlerini kullanabilir. Ancak ilerindeki deerleri deitiremez. day, mon,
year isimli elemanlar snfn public blmnde olsalard da bu ilevler tarafndan
deitirilemezlerdi. const anahtar szc bu kullanm ile okunabilirlii artrr. Kodu
inceleyen kii bu ilevlerin elemanlarn deitirmeyeceini bilirse, kod hakknda daha
fazla bilgi edinmi olur. yi bir tasarmda const anahtar szc kararl bir biimde

C++ Kitabi (100/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


kullanlmaldr. Eer kararl bir biimde kullanlrsa artk const olmayan ye ilevlerin
snfn elemanlarn deitirecei dnlebilir.
Yalnzca ye ilevler const olabilir. Global bir ilev const anahtar szc ile
tanmlanamaz.

const ye levlerin Snfn Dier ye levlerini armas


Bir ye ilev iinde baka bir ye ilevin dorudan arlabildiini, bu durumda arlan
ye ilevin aran ye ilev ile ayn snf nesnesinin elemanlarn kullandn hatrlayalm.
const bir ye ilev iinde const olmayan bir ye ilevin arlmas geerli deildir.
Yukardaki rnekte Date snfnn display ye ilevi const bir ye ilevdir. Bu ilevin const
olmayan bir ye ilevi armas geersizdir. Eer bu duruma derleyici tarafndan izin
verilseydi display ilevi rnein set ilevini ararak snfn elemanlarn dolayl bir
biimde deitirebilirdi:
voidDate::set(intd,intm,inty)
{
day=d;
mon=m;
year=y;
}
intDate::display()const
{
set(3,5,1980);
//Gecersiz.
cout<<day<<""<<mon<<""<<year;
}
Yukardaki rnekte Date snfnn display ilevi iinde yine ayn snfn set isimli ilevine
yaplan ar geersizdir. const bir ye ilev const olmayan bir ye ilevi aramaz.

Snf Elemanlarnn Adresine Geri Dnen const ye levler


const bir ye ilev iinde snfn elemanlarnn const olduu varsaylr. Eer const bir ye
ilev snfn bir elemann adresi ile geri dnecekse, elemannn const olduu
varsayldndan ilevin geri dn deerinin de const bir gsterici ya da referans olmas
gerekir.
classA{
inta;
public:
//...
int*get_adr()const;
};
int*A::get_adr()const
{
return&a; //Geersiz
}
Yukardaki rnekte A snfnn get_adr ilevi const bir ye ilevdir. levin tanm iinde,
hangi snf nesnesi iin arlmsa, o nesnenin elemanlar da const olarak ele alnr. Bu
durumda yukardaki ilevde const bir nesnenin adresi gsterdii yer const olmayan bir
gstericiye atanr. Hata durumunun ortadan kaldrlmas iin, ya ilevin geri dn deeri
const int * olmal ya da get_adr ilevi const ye ilev olmamaldr.
phesiz bir referansa geri dnen ye ilevler iin de yukardaki anlatlan durum
geerlidir. Yani const bir ye ilev snfn elamannn kendisi ile dnecekse bu durumda
ilevin geri dn deeri const referans olmaldr.
C++ Kitabi (101/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Kurucu ve Sonlandrc levler const Olamaz


Snfn kurucu ve sonlandrc ilevleri const olamaz. Kurucu ilevler snfn elemanlarna
ilkdeer vermek amacyla kullanldna gre const olmalarnn zaten bir anlam olmaz.
Benzer biimde sonlandrc ilevlerin de snfn elemanlarn deitirmesi gerekebildii iin
const olarak tanmlanmas yasaklanmtr.

Snf Nesnelerinin Bitsel ve Soyut Durumlar


Bir snf nesnesi bellekte bir yer kaplar, bu ynyle nesne bytelar ve bytelar oluturan
bitler topluluudur. Ancak snf nesnesi problem dzleminde bir varla karlk gelir.
Nesnenin elemanlarnn bitsel deerleri deitiinde nesnenin gzlenebilir durumunda bir
deiiklik olmayabilir. Dier taraftan nesnenin elemanlarnn bitsel deerlerini
deitirmeksizin, nesnenin gzlenebilir durumunda bir deiiklik yaratmak da olasdr.
Bir snf nesnesi bellekte kendi kaplad yerin dnda bir ya da birden fazla kayna
kontrol ediyor olabilir. rnein baz snf nesneleri, dinamik olarak elde edilmi bir bellek
alann kontrol eder. Aadaki rnei inceleyin:
className{
char*pstr;
intlen;
public:
Name(constchar*);
voidset_at(int,int);
//...
};
#include<iostream>
#include<cstring>
Name::Name(constchar*str)
{
len=strlen(str);
pstr=newchar[len+1];
strcpy(pstr,str);
}
voidName::set_at(intindex,intch)
{
pstr[index]=ch;
}
Yukardaki rnekte Name snfnn kurucu ilevi, snf nesnesi iin dinamik bir yer elde
ediyor. Elde edilen dinamik bloun balang adresi, char trden bir gsterici olan pstr
isimli elemanda tutuluyor. set_at ilevi ise elde edilen dinamik bloktaki index indisli
nesneye, ikinci parametre deikenine gnderilen deeri atyor.
set_at ilevi const olarak tanmlanmal mdr? set_at ilevi snfn elemanlarn, yani len ve
pstr elemanlarn deitirmese de, const olarak tanmlanmamaldr. Snf nesnesinin yer
ald bellek blouna bir veri yazlmasa da, snf nesnesinin deerinde bir deiiklik
yapld iin, set_at ilevinin const olmamas gerekir. Yani bir ye ilevin const olup
olmamas kararnda, nesnenin fiziksel durumundaki deiiklik deil, soyut durumundaki
deiiklikler dikkate alnmaldr. Nesne yalnzca fiziksel ya da somut durumu ile yani
bellekte kaplad yer ile deerlendirilmemelidir. Bazen bir ye ilev snf nesnesinin
bellekte kaplad yere bir veri aktarmamasna karn bir snf nesnesinin durumunu
deitirebilir. Bir Name nesnesinin grevi bir isim tutmaktr, deil mi? Bir Name
nesnesinin tuttuu ismin deimesi demek, nesnenin soyutlanm durumunun da
deimesi demektir. Byle bir deiiklik Name nesnesinin fiziksel durumunda bir deiiklik
yapmadan gerekletirilebilir.
C++ Kitabi (102/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Yukardaki set_at ilevi bu durum iin rnek olabilir. Bu durumda ilevin const olmayan
ye ilev olmas gerekir.

const ye levlerin Derleyici Asndan Anlam


Derleyici asndan bakldnda bir ye ilevin const olmas ne anlama gelir? ye
ilevlerin aslnda gizli bir parametre deikenine sahip olduunu biliyorsunuz. Bir ye
ilev hangi snf nesnesi ile arlyorsa, ye ilevin gizli parametre deikenine o
nesnenin adresi aktarlr, deil mi? Bir ye ilev iinde bu gstericiye this anahtar szc
ile eriilebildiini hatrlyorsunuz.
classA{
intx;
public:
voidmember_func();
};
Yukardaki snf bildirimine A snfnn public ye ilevi olan member_func isimli ye ilevin
parametre deikenine sahip olmadn gryorsunuz. Oysa derleyici asndan
bakldnda bu ilevin bir parametre deikeni vardr:
voidA::member_func(A*constthis);
this gstericisinin kendisi const bir gsterici olduunu anmsayalm. Bu durumda this
gstericisine ilev iinde bir atama yaplamaz. rnein aadaki kod geersizdir:
Aa;
voidA::member_func()
{
this=&a; //Geersiz!
}
Ancak this gstericisi gsterdii yer const olan bir gsterici deildir. Yani this
gstericisinin gsterdii nesneye atama yaplabilir. Ya da this gstericisinin gsterdii
nesnenin elemanlarna atama yaplabilir.
Peki dardan gizlice adresi alnan snf nesnesinin ye ilev iinde atama yoluyla
deitirilmesi engellenmek istenseydi, this gstericisinin, gsterdii yer const olan bir
gsterici olmas tercih edilirdi, deil mi?
voidA::member_func(constA*constthis);
Byle bir durumda this gstericisinin gsterdii nesneye yani *this nesnesine atama
yaplmayaca gibi, this gstericisinin gsterdii nesnenin elemanlarna da atama
yaplmas engellenmi olurdu. te derleyici asndan bakldnda const ye ilev tam bu
anlama gelir. const olarak bildirilmi bir ilevin this gstericisi gsterdii yer const olan bir
gstericidir.
ye ilev iinde snfn elemanlarna dorudan eriilebilir. Ama gerekte derleyici bu
elemanlara ulamak iin this gstericisini kullanr.
voidA::member_func()
{
x=10;
//this>x=10;
}
ye ilev const olduunda this gstericisi de gsterdii yer const olan bir gsterici
olduundan bu atama artk geerli olmaz:
C++ Kitabi (103/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

voidA::foo()const
{
x=10;
//Geersiz!
}
imdi de bir ye ilevin tanm iinde snfn baka bir ye ilevinin arlmas durumunu
ele alalm. Bu duruma derleyici asndan bakalm. aran ye ilev dardan gizlice
ald adresi, yani this gstericisinin deerini, ard ileve gizlice argman olarak
geer. Yani aran ye ilevin this gstericisinin arlan ye ilevin this gstericisine
atanmas, kopyalama yoluyla aktarlmas sz konusudur.
C++'da gsterdii yer const olmayan bir gstericiye gsterdii yer const olan bir
gstericinin deerinin atanmas geerli deildir:
constint*cptr;
int*p;
p=ptr;
//Geersiz!

mutable Anahtar Szc


Bir ye ilev kendisini aran snf nesnesinin bir elemannn deerini deitirmi olsa da,
nesnenin soyutlanm anlam zerinde hibir gzlenebilir deiiklik yapmam olabilir. Bu
durumda okunabilirlik asndan phesiz sz konusu ilevin const ye ilev olmas
gerekir.
Peki, const ye ilev snfn elemanlarn deitiremediine gre bu nasl mmkn olur?
Bu durumda snfn elaman mutable anahtar szc ile bildirilir. Snfn bir elemannn
mutable anahtar szc ile bildirilmesinin derleyiciye verdii bilgi udur: Bu eleman
const ye ilevler tarafndan da deitirilebilir. Aadaki rnei inceleyin:
classX{
mutableboolflag;
//..
public:
//...
voidfoo()const;
};
voidX::foo()const
{
flag=false;
//...
}
X snfnn bool trden flag isimli eleman mutable anahtar szc ile bildiriliyor. Snfn
foo isimli const ye ilevinin, snfn flag isimli elemanna atama yapmas geerlidir.

const Snf Nesneleri


const bir snf nesnesi deeri hi deimeyecek bir snf nesnesidir.
Bir snf nesnesi const olarak tanmlanabilir. const bir snf nesnesinin elemanlar
kullanlabilir ama herhangi bir biimde deitirilemez. rnein,
constDatebirth_date(4,3,1964);
gibi bir bildirimle birth_date isimli snf nesnesi const olarak tanmlanyor. Artk birth_date
nesnesinin elemanlar deitirilemez. Date snfnn day, month ve year elemanlar public
blmde olsayd bile,
C++ Kitabi (104/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

birth_date.day=10;
gibi bir atamayla elemann deitirilmesi mmkn olmazd.
Bir snf nesnesinin elemanlar, snfn ye ilevleri tarafndan da deitirilebilir. O halde
const bir snf nesnesinin, snfn elemanlarn deitirebilecek bir ye ilevi de
aramamas gerekir! rnein:
constDatebirth_date(4,3,1964);
birth_date.set(6,1,1966);//Geersiz.
gibi bir ilemde set ye ilevi, birth_date nesnesinin elemanlarn deitirir. Gvenlik ve
okunabilirlik alarndan bu durumun da engellenmesi gerekir. Peki, ama derleyici set
ilevinin snfn elemanlarn deitirip deitirmeyeceini nasl anlar? levin koduna
bakarak bu bilgiyi almas mmkn olmayabilir. nk program birka modl halinde
yazlm olabilir. lgili ilev o modlde bulunmayabilir. Dilin kurallarna gre, const bir snf
nesnesi ile ancak snfn const ye ilevlerini arlabilir. nk const ye ilevlerin snfn
elemanlarn deitirmeyecei baka bir kontrolle zaten gvence altna alnmtr.
rnein:
constAa;
a.func();
Yukardaki kod parasnda derleyici A snfna ilikin func ilevinin bildirimine bakarak
onun const bir ye ilev olup olmadn saptar. Eer func const bir ye ilev ise ar
geerlidir, deilse ar geersizdir. Durum bir hata iletisiyle bildirilir.
Derleyici asndan bakldnda durum son derece aktr:
a.func();
arsyla const a nesnesinin adresi gizlice func ilevinin parametre deikenine atanr. a
nesnesinin adresi
(constA*)
trndendir. Bu adres ancak gsterdii yer const olan bir gstericiye atanabilir. Oysa func
ilevi const ye ilev deil ise, ilevin gizli parametre deikeni
A*
trndendir. Dolaysyla ilev ars geerli deildir.
Gsterdii yer const olan bir snf gstericisi ya da const bir snf referans da sz konusu
olabilir. Byle bir gsterici ya da referans yoluyla bir snf nesnenin elemanlar
deitirilemez. Aadaki rnei inceleyin:
voiddisplay_totaldays(constDate*pDate)
{
cout<<pDate>totaldays();
//totaldaysileviconstde?ilse
geersiz!
}
intmain()
{
Datedate
display_totaldays(&date);
return0;
}
C++ Kitabi (105/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Burada display_totaldays ilevinin parametre deikeni, gsterdii yer const bir snf
gstericisidir. Bu gstericinin gsterdii snf nesnesinin elemanlar deitirilemez ve bu
nesne iin snfn const olmayan bir ye ilevi arlamaz. Ayn durum const referanslar
iin de sz konusudur. rneimizi aadaki biime dntryoruz:
voiddisplay_totaldays(constDate&r)
{
cout<<r.totaldays();
//totaldaysileviconstde?ilsegeersiz!
}
intmain()
{
Datedate;
display_totaldays(date);
return0;
}
const anahtar szcnn, genel olarak okunabilirlii artrmak amacyla kullanldn
anmsayalm. Hizmet alaca snfn arayznde const bir snf gstericisini ya da
referansn gren programc, bu gsterici ya da referans yoluyla snfn elemanlarnn
deitirilemeyeceini anlayarak daha fazla bilgi edinir. Bir ilevin adresini ald snf
nesnesinin elemanlarn deitirmeyecek ise, yani bir set ilevi deil ise, ilevin parametre
deikeni gsterdii yer const olan bir gsterici ya da referans olmaldr.

const Snf Nesneleri in Kurucu levin arlmas


const bir snf nesnesi yaratlrken snfn kurucu ilevleri normal olarak arlr. nk
kurucu ilevlerin amac bir snf nesnesine ilkdeer vermektir. Nasl doal trlerinden
const bir nesneye ilk deer verilebiliyorsa, const bir snf nesnesine de kurucu ilev
yardmyla ilkdeer verilebilir. Yani kurucu ilevin arlmas nesnenin deerini
deitirilmesi deil nesneye ilk deer verilmesi anlamna gelir. rnein:
constDated(29,5,1992);
deyimi ile snfn kurucu ilevi snfn nesnesinin elemanlarna ileve gnderilen
argmanlar ile ilkdeerini verir. Yani kurucu ilev, snfn elemanlarn atama yapmaz,
onlara ilkdeerini verir.
Snfn elemanlarn deitirmeyen ilevler, const ye ilev olarak tanmlanmazlarsa, bu
ilevlerin const snf nesneleri tarafndan arlmas engellenmi olur. Yani bu ilevler
const snf nesnelerine hizmet veremez.

Snfn const Elemanlar


C++ dilinde const anahtar szcnn bir kullanm daha vardr. Snf bildirimi yaplrken
snfn bir eleman da const olarak bildirilebilir:
classA{
inta;
constintb;
//...
public:
voidfunc();
};
voidA::func()
{
b=10;
//Geersiz!
}
C++ Kitabi (106/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Yukardaki bildirimde A snfnn b isimli eleman const olarak bildiriliyor. A snfnn ye


ilevleri iinde b elemannn deeri deitirilemez.
Ancak bir snfn elemannn const olarak bildirilmesi durumunda, snfn kurucu ilevinin
zel bir szdizim kuralna gre tanmlanmas gerekir. M.I.L szdizimi diye
isimlendireceimiz bu kurala ileride ayrntl olarak deineceiz.

const Yklemesi

Bir snf ayn isimli ve ayn parametre yapsna sahip biri const biri const olmayan iki ye
ileve sahip olabilir. Bu duruma const yklemesi (const overloading) denir.
ye ilevlerin ama kod iine yazlmasnda snf isimleri ve parametre trlerinin yan sra
const anahtar szc de bir ekilde kodlanr. Baka bir deyile const ilevin imzasnn bir
parasdr. Byle bir durumda ayn simli ye ilev arldnda gerekte hangi ye ilevin
arlm olduu, ar ifadesinde kullanlan nesnenin const olup olmadna baklarak
saptanr. Eer ar ilemi const bir snf nesnesi ile yaplmsa const olan ye ilevin,
const olmayan bir snf nesnesi ile yaplmsa const olmayan ye ilevin arld anlalr.
Aadaki kodu derleyerek altrn:
classA{
public:
A(){}
voidfunc();
voidfunc()const;
};
#include<iostream>
usingnamespacestd;
voidA::func()
{
cout<<"A::func()"<<endl;
}
voidA::func()const
{
cout<<"A::func()const"<<endl;
}
intmain()
{
Aa;
constAca;
a.func();
ca.func();
return0;
}

C++ Kitabi (107/330)

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Kopyalayan Kurucu lev


Bir snfn kopyalayan kurucu ilevi (copy constructor), o snfa ait bir nesnenin ilkdeer
verilerek yaratlmas durumunda arlan, zel bir kurucu ilevdir. Hatrlayacanz gibi,
ilkdeer verme bir bildirim deyimidir, atama deyiminden farkl zellikler tar.
intx=10;
Yukardaki deyimde int trden x deikeni, 10 ilkdeerini alarak yaratlyor. Bir snf
nesnesi de,ayn trden bir baka snf nesnesinden ilkdeerini alarak tanmlanabilir:
classA{
public:
A();
};
intmain()
{
Aa1;
Aa2(a1);

//a1nesnesiiinvarsaylankurucuileva?rlyor.
//a2nesnesiilkde?erinia1nesnesindenalarakyaratlyor.

return0;
}
C++da bir snf nesnesinin yaratld her durumda bir kurucu ilevin otomatik olarak
arldn hatrlayalm. Bir snf nesnesi ilkdeerini baka bir snf nesnesinden alarak
yaratld zaman da bir kurucu ilev arlr. Bu ilev "kopyalayan kurucu ilev" olarak
isimlendirilir. Kopyalayan kurucu ilev, programc tarafndan tanmlanmaz ise derleyici
tarafndan otomatik olarak tanmlanr.
Derleyicinin otomatik olarak yazaca kopyalayan kurucu ilev, snfn public blmnde
bildirildii kabul edilen inline bir ilevdir ve parametrik yaps aadaki gibidir:
classA{
//
public:
A(constA&);
};

//Kopyalayankurucuilev

Derleyicinin yazd kopyalayan kurucu ilev, arlm olduu snf nesnesinin


elemanlarna yani *this nesnesinin elemanlarna, ilkdeer verme ileminde atama
ilecinin sa tarafnda bulunan snf nesnesinin ilgili elemanlarnn deerlerini kopyalar.
Byle bir kopyalama ingilizcede "memberwise copy" olarak bilinir.

Kopyalayan Kurucu lev Hangi Durumlarda arlr


Bir snf nesnesine ayr biimde ilkdeer verilebilir:
1. Ak ilkdeer verme biiminde
Aa1;
Aa2(a1);
Yukardaki kod parasnda a2 nesnesi, deerini daha nce tanmlanan a1 nesnesinden
alarak yaratlyor. Tanmlanan a2 nesnesi iin derleyicinin yazd kopyalayan kurucu ilev
arlr. a1 nesnesi bu ileve referans yoluyla geirilir.
Tek parametreli kurucu ilevlerin aadaki biimde de arlabileceini biliyorsunuz:

108/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Aa2=a1;
Bu durumda da a2 nesnesi iin kopyalayan kurucu ilev arlr. Bu ileve a1 nesnesi
referans yoluyla geirilir.
2. Argmanlardan parametre deikenlerine deerle aktarm
Bir ileve gnderilen argman, ilgili ilevin parametre deikeni olan nesneye
ilkdeerini(ilk deerini) verir. Yani ilev arldnda, parametre deikeni olan nesne,
ileve argman olarak gnderilen ifadeden ilkdeerini(ilk deerini) alarak yaratlr:
voidfunc(Ap)
{
//
}
voidfoo()
{
Aa;
func(a);
}
Yukardaki kod parasnda func ilevinin parametre deikeni A snf trndendir. foo
ilevi iinde arlan func ilevine, yerel a nesnesinin deeri argman olarak gnderiliyor.
func ilevi arldnda yaratlan A snf trnden olan parametre deikeni p, ilk
deerini a nesnesinden alarak yaratlr. Bu durumda parametre deikeni p iin
kopyalayan kurucu ilev arlr. arlan kopyalayan kurucu ileve a nesnesi referans
yoluyla geirilir.
3. levlerin geri dn deerlerini, bir geici nesne oluturarak darya aktardn
biliyorsunuz. Geri dn deeri reten bir ilevin kodunun altrlmas srasnda return
deyimi yrtldnde, ilevin geri dn deeri trnden bir geici nesne ilkdeer
verme yoluyla yaratlr. Yaratlan geici nesne ilk deerini return ifadesinden alr. Bir ilev
bir snf trne geri dnyorsa, return ifadesi de bir snf nesnesi olmaldr, deil mi? Bu
durumda geri dn deerini iinde tayacak geici nesne ilk deerini return ifadesi olan
nesneden alarak yaratlr. Yani geri dn deerinin iinde tayacak geici nesne iin
kopyalayan kurucu ilev arlr. return ifadesi olan snf nesnesi de kopyalayan kurucu
ileve referans yoluyla geirilir. Aadaki kod parasn inceleyin:
Afunc()
{
Aa;
//
returna;
}
Yukardaki ilevde return deyimi yrtldnde yaratlan geici nesne ilk deerini yerel
a nesnesinden alr. Yani
Atemp_object=a;
gibi bir ilem sz konusudur.
Bildiiniz gibi, bir snfn farkl imzaya sahip birden fazla kurucu ilevi olabilir ama snfn
sonlandrc ilevi tektir. Yukardaki durumda da kopyalayan kurucu ilevle yaratlan
snf nesneleri iin bu nesnelerin mr bittiinde snfn sonlandrc ilevi arlr.

109/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Programcnn bir kopyalama kurucu ilevi yazmamas durumunda derleyici bu ilevi
kendisi yazyorsa ve derleyicinin yazd kopya kurucu ilevi tm elemanlar karlkl
birbirine atyorsa, neden programc bir kopyalayan kurucu ilevi yazma gerei duysun?
Baz durumlarda nesnelerin elemanlarnn karlkl olarak birbirine atanmas istenen bir
durum deildir!
Baz snflarda snf nesnelerinin baz elemanlar dsal kaynaklar kontrol eder. Bu
elemanlarnn deerlerinin birbirlerine atanmas istenmeyen sonulara yol aabilir. Yazlar
tutmak iin tanmlanan ismi String olan bir snf ele alalm. Snfn basitletirilmi tasarm
aadaki gibi olsun:
//string.h
classString{
char*m_p;
intm_len;
public:
String(constchar*str);
~String();
voidmake_upper();
voidprint()const;
};
//string.cpp
//#includestring.h
#include<iostream>
#include<cstring>
#include<cctype>
usingnamespacestd;
String::String(constchar*str)
{
m_len=strlen(str);
m_p=newchar[m_len+1];
strcpy(m_p,str);
}
String::~String()
{
delete[]m_p;
}
voidString::make_upper()
{
for(intk=0;k<m_len;++k)
m_p[k]=toupper(m_p[k]);
}
voidString::print()const
{
cout<<m_p;
}
Tanmlanan String snfn kullanan aadaki main ilevini dikkatle inceleyin:
intmain()
{
Strings1("Necati");

110/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


{
Strings2=s1;
s2.print();
//...
}
s1.make_upper();
s1.print();
return0;
}
s1 nesnesi yaratldnda arlan kurucu ilevin almasyla, 7 karakter uzunluunda bir
dinamik alan yaratlyor. Yaratlan dinamik alann balang adresi s1 nesnesinin eleman
olan m_p isimli gsterici elemanda tutuluyor.
Daha sonra yer alan blok iinde bu kez s2 isimli nesne ilk deerini s1 nesnesinden alarak
yaratlyor. Derleyicinin yazd kopyalayan kurucu ilev, s1 nesnesinin elemanlarnn
deerlerini s2 nesnesinin elemanlarna atayacana gre, s2 nesnesinin de m_p isimli
eleman olan gsterici ayn dinamik alan gsterir, deil mi?
s2 nesnesinin tanmland bloun sonunda, s2 nesnesinin mr tamamlanaca iin s2
nesnesi iin snfn sonlandrc ilevi arlr. Sonlandrc ilev daha nce elde edilen
dinamik blou free storea geri vermek iin tanmlanmtr. s2 nesnesinin m_p
elemannn gsterdii dinamik alan free storea geri verilir. Ancak bu dinamik bloun
balang adresi ayn zamanda s1 nesnesinin de m_p elemannn deeridir. s2 nesnesi
mrn tamamlamasna karn s1 nesnesi halen hayatn srdrmektedir. Ancak s1
nesnesinin dinamik alan artk serbest braklmtr. Snfn make_upper ve print isimli ye
ilevleri ayrlan dinamik alan zerinde ilem yaptklar iin s1.make_upper() ve s1.print()
ilev arlar alma zamannda gsterici hatasna neden olur.
Tabii bu arada s1 nesnesi mrn tamamladnda s1 nesnesi iin de sonlandrc ilev
arlr ve bu ilev de daha nce geri verilen dinamik alan tekrar free storea geri
vermeye alr. Bu durum da bir baka alma zaman hatasdr(undefined behavior).
Tanmlanan String snf iin benzer hatalar farkl grntlerle de karmza kabilirdi:
voidfunc(Strings)
{
//
}
intmain()
{
Stringname("Necati");
func(name);
name.print(); //almazamanhatas
//
return0;
}
main ilevi iinde String snf trnden name isimli bir nesne tanmlanyor. Daha sonra
func isimli ileve name nesnesi argman olarak gnderiliyor. arlan func ilevinin
parametre deikeni String snf trndendir. Bu durumda ilevin arlmasyla birlikte,
parametre deikeni olan s nesnesi iin kopyalayan kurucu ilev arlr. func ilevinin ana
blounun sonuna gelindiinde bu kez s nesnesi iin sonlandrc ilev arlr. Nesnenin
m_p elemannn gsterdii alan free storea geri verilir. Oysa ilev arsndan sonra
name nesnesinin mr halen devam etmektedir. name nesnesinin print ye ilevi
arldnda bu ye ilev artk geri verilen bir alana eriir. Yani bir gsterici hatasna
neden olur.

Kopyalayan Kurucu levin Yazlmas


Programc bir kopyalayan kurucu ilev yazarsa derleyici artk otomatik olarak bir ilev
yazmaz. ou zaman programcnn yazd kopyalayan kurucu ilev, yaratlan nesneyi

111/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


ilkdeer(ilk deerini) veren nesnenin kayna ile dorudan ilikilendirmek yerine,
yaratlan nesne iin farkl bir kaynak yaratr. Bylece ayn kaynan birden fazla nesne
tarafndan paylalmasndan doan hatalar ortadan kaldrlr. Aada, daha nce
tanmlanm String snf iin bir kopyalayan kurucu ilev bildiriliyor ve tanmlanyor:
classString{
//...
public:
String(constString&);
//...
};
String::String(constString&r)
{
m_len=strlen(r.m_p);
m_p=newchar[m_len+1];
strcpy(m_p,r.m_p);
}
Yazlan kopyalayan kurucu ilevi inceleyelim:
levin parametre deikeni olan r referans, yaratlan String nesnesine ilk deerini veren
nesnenin yerine geiyor. nce yaratlan snf nesnesinin m_len isimli elemanna ilk deer
veren nesnenin tuttuu yaznn uzunluunun 1 fazlas atanyor. Daha sonra new[] ileciyle
m_len + 1 byte uzunluunda bir blok dinamik olarak elde ediliyor. Dinamik bloun
balang adresi yeni yaratlan nesnenin m_p isimli elemannda tutuluyor. Daha sonra
standart strcpy ileviyle yeni bloa, ilk deer veren nesnenin dinamik alanda tuttuu yaz
kopyalanyor.
Yazlan kopyalayan kurucu ilevin kodunun almasyla, yaratlan nesne artk kendi
dinamik alann kullanyor hale gelir. Bu nesne iin sonlandrc ilev arldnda da
sonlandrc ilev iinde kullanlan delete[] ileci yalnzca nesne iin ayrlm olan blou
geri verir. Kopyalayan kurucu ilev dorudan snfn elemanlarnn deerlerini birbirine
aktarmam, yaratlan nesne iin yeni bir kaynak yaratm ve ilk deer veren nesnenin
kulland kaynaa ulap, yeni elde edilen kaynaa kopyalamay salamtr. Byle
kopyalamaya "derin kopyalama" (deep copy) denir.

Kopyalayan Kurucu levin Parametresi Referans Yerine Nesne


Olabilir mi?
Yukarda tanmlanan String snfna ilikin kopyalayan kurucu ilevin aadaki biimde
bildirildiini dnelim:
classString{
//
public:
String(String);
//
};
String snf trnden bir nesnenin bir ileve deerle gnderildiini dnelim:

112/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidfoo(String);
voidfunc()
{
Stringstr("Necati");
foo(str);
//
}
Bu durumda foo ilevinin parametre deikeni olan nesnenin yaratlmas iin, kopyalayan
kurucu ilev arlr. Ancak kopyalayan kurucu ilevin de parametresi String snf
trnden bir nesne olduu iin bu kez kopyalayan kurucu ilevin de parametresi olan
String snf trnden nesne iin yine kopyalayan kurucu ilev arlr. Bu durumda
zyinelemeli (recursive) olarak arlan kopyalayan kurucu ilev belirli bir sreden sonra
yn (stack) alann tketir.

113/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Atama lecini Ykleyen lev


Bir snf nesnesine ayn trden bir snf nesnesi atand zaman da bir ilev otomatik
olarak arlr. arlan bu ilevi "atama ilevi" (assignment operator function) olarak
isimlendireceiz. Atama ilevi de zel bir ilevdir. Yani programc bu ilevi tanmlamaz ise
bu ilev de derleyici tarafndan otomatik olarak yazlr. Derleyicinin otomatik olarak
yazd atama ilevi, snfn statik olmayan bir ye ilevidir ve inline olarak bildirilir.
rnein A isimli bir snf iin derleyicinin yazd atama ilevinin bildirimi aadaki gibidir:
classA{
//...
public:
A&operator=(constA&);
//...
};
Derleyicinin yazd atama ilevi atama ilecinin sa tarafndaki snf nesnesinin
elemanlarn atama ilecinin sol tarafndaki nesnenin elemanlarna karlkl olarak atar.
lev atama ilecinin sol tarafndaki snf nesnesini referans yoluyla geri dndrr.
a1 ve a2 A snf trnden nesneler olmak zere
a1=a2;
gibi bir atama derleyici tarafndan A snfnn atama ilevine yaplan bir arya
dntrlr:
a1.operator=(a2);
arlan ye ileve this adresi olarak atama ilecinin solundaki nesnenin adresi yani a1
nesnesin adresi geirilir.
Snf nesnelerinin karlkl elemanlarnn birbirine atanmasnn uygun olmad
durumlarda derleyicinin yazd atama ilevi istenmez. Bu durumda programc atamann
istedii gibi yaplmasn salamak iin kendisi bir atama ilevi yazabilir. Programcnn bir
atama ile ilevi yazmas durumunda artk derleyici bu ilevi yazmaz. Bir snf iin
kopyalayan kurucu ilevin tanmlanmas gerekiyorsa, ounlukla ayn snf iin atama
ilevinin de yazlmas gerekir. Daha nce rnek olarak verilen String snfn dnelim:
intmain()
{
Stringname1("Deniz");
{
Stringname2("Yusuf");
name2=name1;
}
name1.print();
//...
}
Yukardaki kodu inceleyelim:
main ilevinin ana blounun banda String snf trnden name1 isimli bir nesne
tanmlanyor. arlan kurucu ilev 6 karakterlik bir blou dinamik olarak elde ederek bu
bloun balang adresini, eleman olan m_p isimli gstericide saklar. Bu bloa "Deniz"
yazsn kopyalar. main ilevi iinde yer alan i blokta bu kez name2 isimli bir nesne
yaratlyor. Bu nesne de benzer biimde "Yusuf" yazsn tutar.
name2=name1

114/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

atamas ile derleyicinin yazd atama ilevi arlyor: Bu ilev, atama ilecinin terimi olan
nesnelerin elemanlarn karlkl olarak birbirine atad iin name2 nesnesinin m_p
elemanna name1 nesnesinin m_p elemannn deeri atanr. Bu durumda her iki
nesnesinin m_p eleman da ayn dinamik blou yani "Yusuf" yazsnn bulunduu dinamik
blou gsterir. Bu durumda artk "Deniz" yazsnn bulunduu blokla iliki kaybedilmi
olur. Ama asl byk hata isel bloun sonlanmasyla oluur.
sel bloun sonunda name2 nesnesi iin sonlandrc ilev arlr. arlan sonlandrc
ilevin nesnenin m_p elemannn gsterdii blou free storea geri verdiini biliyorsunuz.
Oysa isel bloun kapanmasndan sonra name1 nesnesi halen hayattadr ama bu
nesnenin m_p gstericisi artk geri verilmi olan bir blou gsterir.
name1.print();
arsyla, geri verilen bir dinamik bloa eriilir. Bu da bir gsterici hatasdr. Bu kadar
hatann zerine son hata da name1 nesnenin mr sona erdiinde oluur. Bu kez name1
nesnesi iin arlan sonlandrc ilev, daha nce geri verilen dinamik blou ikinci kez geri
vermeye alr. Bu da tanmsz davrantr.

Atama ilevinin Yazlmas


Atama ileminde, atama ilecinin sa tarafnda yer alan nesnenin kulland kaynan,
ilecin sol tarafnda yer alan nesne tarafndan paylalmas istenmiyorsa atama ileci iin
bir ilev yazlmaldr. Yukarda daha nce bildirilen String snf iin atama ilevi aadaki
gibi tanmlanabilir:
String&String::operator=(constString&r)
{
if(this==&r)
return*this;
delete[]m_p;
m_len=r.m_len;
m_p=newchar[m_len+1];
strcpy(m_p,r.m_p);
}
Yazlan ilevi inceleyelim. levin giriinde yer alan if deyimine daha sonra deineceiz.
Atama ilevinin kopyalayan kurucu ilevden nemli bir fark vardr. Kopyalayan kurucu
ilev hangi snf nesnesi iin arlyorsa o snf nesnesi ilev arsndan nce yoktur.
Nesne kurucu ilevin arlmasyla hayata balar. Ancak atama ilevi sz konusu
olduunda durum farkldr. lev hangi nesne iin arlmsa bu nesne zaten daha nce
yaratlmtr. Daha nce yaratlm bu nesnenin kullanm iin zaten bir blok elde edilmitir.
String snf iin yazlan atama ilevi nce nesne iin ayrlan dinamik blou geri vermelidir:
delete[]m_p;
deyimiyle bu salanr:
Daha sonra atama ilecinin sol tarafndaki nesne iin yani *this nesnesi iin
m_p=newchar[m_len+1];
deyimiyle yeni bir dinamik blok elde ediliyor ve
strcpy(m_p,r.m_p);

115/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


arsyla da, atama ilecinin sa tarafndaki nesnenin dinamik blounda tutulan yaz,
yeni elde edilen dinamik bloa kopyalanyor. levin
*this
deeriyle geri dndn gryorsunuz. lev hangi snf nesnesi iin arlmsa o snf
nesnesini referans yoluyla geri dndrr. Bir baka deyile
name1=name2
atamasnn dntrld ilev ars, name1 nesnesini referans yoluyla geri
dndryor. Peki buna neden gerek duyulmu olabilir?
Doal trler sz konusu olduunda, atama ilecinin rettii deerin nesneye atanan
deer olduunu biliyorsunuz. Ayn zelliin bir snf trnden nesne iinde salanmas
atama ilecini ykleyen ilevin, *this nesnesini dndrmesi ile salanabilir. Aadaki
kodu inceleyin:
intmain()
{
Stringname1("Deniz");
Stringname2("Yusuf");
Stringname3("Huseyin");
Stringname4("?brahim");
name1=name2=name3=name4;
name1.print();
name2.print();
name3.print();
name4.print();
return0;
}
Atama ilecinin ncelik ynnn soldan saa olduunu biliyorsunuz.
name1=name2=name3=name4;
deyimi, derleyici tarafndan aadaki gibi bir ilev ars zincirine dntrlr:
name1.operator=(name2.operator=(name3.operator=(name4)));
Bir nesnenin kendisine atanmasnn bir szdizim hatas oluturmadn biliyorsunuz.
String snf trnden bir nesnenin kendisine atandn dnelim:
intmain()
{
Stringname("Necati");
name=name;
//...
}
Yazm olduumuz atama ilevi arldnda ne olur? Atama ilecinin sol terimi olan
nesne iin arlan atama ilevi, ilk nce m_p gstericisinin gsterdii dinamik blou geri
verir. Ancak atama ilecinin sa terimi olan nesne de ayn nesne olduundan,
strcpy(m_p,r.m_p);

116/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


ifadesi gsterici hatasna neden olur. nk r.m_p nesnesi artk geri verilen bir blou
gsteriyor durumundadr.
Hata nasl giderilebilir? Atama ilecinin sol terimi olan nesne ile sa tarafndaki nesnenin
ayn olmas durumunda hi bir ilem yaplmamaldr:
if(this==&r)
return*this;
Yukardaki deyimi inceleyelim: Atama ilevi iinde kullanlan this gstericisi ilecin sol
terimi olan snf nesnenin adresidir, deil mi? r referans da atama ilecinin sa terimi olan
nesnenin yerine gemitir. O zaman &r ifadesi, atama ilecinin sa terimi olan nesnenin
adresidir. Adresleri ayn olan iki nesne ayn nesnedir. Eer nesne kendine atanyorsa ilev
hi bir ilem yapmadan *this nesnesini referans yoluyla dndrr.
Atama ile ilevinin kodu iinde nesnenin kendisine atanp atanmadnn snamas
yaplmal mdr? yle dnebilirsiniz: Programc durup dururken neden bir snf
nesnesini kendine atasn?
Bu hata daha ok gstericiler, referanslar ve ilev arlarna ilikindir.
*ptr=x;
Yukardaki atama deyiminde ptr bir snf trnden gsterici x de ayn snf trnden bir
nesne olsun. Bu atama ileminden nce ptr x nesnesini gsteriyorsa, nesne kendisine
atanm olur.

117/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Dntren Kurucu lev


Snfn tek argmanla arlabilen kurucu ilevlerine dntren kurucu ilev denir. Byle
bir kurucu ilev ya tek bir parametreye sahiptir, ya da dier parametreleri varsaylan
deerler alr.
classAccount{
intacc_no;
doublebalance;
public:
Account(double);//Dntrenkurucuilev
//...
};
Yukarda tanmlanan Account snfnn
Account(double);
biiminde bildirilen kurucu ilev, dntren kurucu ilevdir. lev tek parametre
deikenine sahiptir.
classComplex{
doubler,i;
public:
Complex(doubler,doublei=0);
//...
};

//Dntrenkurucuilevi

Yine yukarda tanmlanan Complex snfnn


Complex(doubler,doublei=0);
biiminde bildirilen kurucu ilev, dntren kurucu ilevdir. lev tek bir argmanla
arlabilir.
Bir snfn dntren kurucu ilevi, baka trden bir ifadenin snf trnden geici bir
nesneye otomatik olarak dntrlmesini salar.
rnein yukarda tanmlanan Account snf iin aadaki ifadelerden hepsi geerlidir:
voidfunc(Accountp)
{
//...
}
intmain()
{
Accounta1=200;
a1=300.;
func(200.);
return0;
}
Accountfoo()
{
doublex;
//...
returnx;
}

118/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

main ilevinde yer alan birinci deyimle, Account trnden a1 nesnesi 200. deeriyle
ilkdeerini alarak yaratlyor. Bu durumda 200 deeri dntren kurucu ilev yoluyla
Account snf trnden bir geici nesneye dntrlr. Geici nesne de kopyalayan
kurucu ilevle a1 nesnesine ilkdeerini verir. Yani derleyici asndan byle bir deyim
Accounta1=Account(200.);
ya da
Accounta1=(Account)200;
deyimlerine edeer kabul edilebilir. C++ tr dntrme ilecinin ilevsel biiminin de
geerli olduunu anmsayalm.
C++ derleyicilerinin ou eniyileme (optimizasyon) amacyla, nce bir geici nesne
yaratp geici nesneyle kopyalayan kurucu ilevi armak yerine bu durumda dorudan
a1 nesnesi iin snfn kurucu ilevi arr. Bu durumu ileride yeniden inceleyeceiz.
Gelelim ikinci deyime:
a1=300.;
C'den bildiimiz gibi bir yap nesnesine ancak o yap trnden bir baka nesne atanabilir.
Yani C dilinde baka bir trden ifade hibir zaman bir yap trne otomatik olarak
dntrlmez. Ancak C++ da bir snf nesnesine baka trden bir ifade atandn gren
derleyici, atamann mmkn olup olmadn anlamak iin bir dntrme kurucu ilevinin
var olup olmadn sorgular. Byle bir kurucu ilev varsa otomatik tr dnm yaplr.
Byle bir ilevin olmamas durumunda dnm mmkn olmad iin, derleme
zamannda hata oluur. Yukardaki atama deyimi derleyici tarafndan aadaki gibi ele
alnr:
a1.operator=(Account(300.));
Yani nce 300 deeri dntrme kurucu ilevine argman olarak geilerek Account snf
trnden bir geici nesne yaratlr. Yaratlan geici nesnesin deeri a1 nesnesi iin arlan
atama ile ilevine argman olarak geilir.
func(200)
ars iin de benzer durum sz konusudur. func ilevine gnderilen argman olan 200.
ifadesi nce dntrme kurucu ileviyle Account snf trnden bir geici nesneye
dntrlr. func ilevinin parametre deikeni bu geici nesne ile kopyalayan kurucu
ilev araclyla ilkdeerini alr. Yani derleyici asndan kodun anlam
func(Account(200));
gibi bir deyime edeerdir.
imdi de foo ilevinin kodunu inceleyelim. foo ilevinin return ifadesi, ilevin geri dn
deerini iinde tayacak geici nesneye ilkdeerini verir. return ifadesi olan double trden
x, otomatik olarak Account snf trnden bir geici nesnenin yaratlmasna neden olur.
levin geri dn deerini iinde tayacak geici nesne kopyalayan kurucu ilev
araclyla ilkdeerini bu geici nesneden ilk deerini alr. Bu durumlarda yine derleyici
eniyileme amacyla daha ksa kodlar retebilir, ama imdilik bu konuya girmeyeceiz.

119/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Yukardaki tr dnmleri otomatik olarak derleyici tarafndan yaplabilecei gibi
programc tarafndan tr dntrme ileleri kullanlarak da yaplabilirdi. imdi de main
ilevini tr dntrme ilelerini kullanacak biimde deitirelim:
intmain()
{
Accounta1=Account(200);
a1=Account(300.);
func(Account(500.));

//Accounta1=(Account)200;
// a1=(Account)300.;
//(Account)500.;

return0;
}
Aklama satrlarnda tr dntrme ileleri C biimiyle kullanld.
lerdeki derslerimizde C'de olmayan C++'n yeni tr dntrme ilelerini reneceiz.
Yukardaki tr dnmleri iin C++'n yeni tr dntrme ileci olan static_cast tr
dntrme ilecinin de kullanlabileceini imdiden syleyelim.
Otomatik ya da bilinli dnmn gerekletirilebilmesi iin dntrme kurucu ilevin
parametresiyle, geici snf nesnesine dntrlecek ifadenin trnn tamamen ayn
olmas gerekmez. Dntren kurucu ilevinin arlmasndan nce doal veri trlerine
ilikin otomatik dnmler yaplabilir. Yukarda bildirilen func ilevinin aadaki gibi
arldn dnelim:
func(10);
func ilevine argman olarak int trden bir ifade gnderiliyor. func ilevinin parametresi
Account snf trndendir. Account snfnn
Account(double);
ilevinin arlabilmesi iin nce int trden 10 deeri otomatik tr dnm ile double
trne, daha sonra da dntren kurucu ilev ile Account snf trnden geici bir
nesneye dntrlr. Yani derleyici iin
func(10)
gibi bir ar
func(Account(double(10))
arsna edeerdir.
Snf trnden olmayan bir ifadenin otomatik olarak bir snf trne dntrlmesi her
zaman istenmeyebilir. Baz durumlarda byle bir dnm program yazarken oluan bir
kodlama hatasnn derleyici tarafndan bulunmasna engel olur. Aadaki koda inceleyin:
intmain()
{
inta;
Accountac(400.);
func(a);
//...
return0;
}

120/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


levi yazan programcnn func ilevine argman olarak Account snf nesnesi ac yi
gndermek yerine, yanllkla int trden olan a nesnesinin deerini gnderdiini
dnelim. Derleyici iin
func(a)
ars tamamen geerlidir. a ifadesi nce double trne, daha sonra da double trnden
yukarda akladmz biimde Account snfna dntrlerek func ilevine argman
olarak gnderilir. Yani derleyici tarafndan ilev ar ifadesi
func(Account(double(a)));
biiminde ele alnr.
Snf trnden olmayan bir ifadenin snf trne dntrme kurucu ileviyle
dntrlmesi istenmiyorsa bu durum derleyiciye explicit anahtar szcyle
bildirilebilir.

explicit Anahtar Szc


Bir snfn kurucu ilevinin bildiriminde explicit anahtar szc kullanlabilir. explicit
anahtar szc yalnzca ilevin bildiriminde yazlr, kurucu ilevinin snf dnda
tanmlanmas durumunda ilev tanmnda yer almaz. explicit anahtar szc ile bildirilen
bir kurucu ilev, otomatik tr dntrme amacyla kullanlamayan bir dntrme
kurucu ilevidir. Kurucu ilevin explicit anahtar szcyle bildirilmesi durumunda, halen
ak bir biimde yani tr dntrme ileleri kullanlarak dnm gerekletirilebilir
ancak otomatik dnme derleyicinin hata mekanizmasyla engel olunur. Yukardaki
rneimizi aadaki biimiyle yeniden derlemeye aln:
classAccount{
intacc_no;
doublebalance;
public:
explicitAccount(double); //explicitDntrenkurucuilev
//...
};
voidfunc(Accountp)
{
//...
}
intmain()
{
Accounta1=200;
a1=300.;
func(200.);

//Geersiz.otomatikdnmyaplamaz!
//Geersiz.otomatikdnmyaplamaz!
//Geersiz.otomatikdnmyaplamaz!

return0;
}
Accountfoo()
{
doublex;
//...
returnx;
}

//Geersiz.otomatikdnmyaplamaz!

121/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Arkadalik Bildirimleri
Snfn ye ilevi olmayan herhangi bir ileve, o snfn private ve protected blmlerine
eriim hakk verilebilir. Bir ilev bir snfn arkada ilevi olarak bildirilebilir. Bir ilevi bir
snfn arkada ilevi olarak bildirmek iin ilev bildiriminin nne friend anahtar szc
yazlr. Aadaki snf bildirimini inceleyin:
classAccount{
intaccount_no;
doublebalance;
public;
//...
frienddoublebalance_dif(constAccount&,constAccount&);
//...
};

Bu rnekte balance_dif global bir ilevdir. Ancak Account snf iinde friend anahtar
szcyle arkada ilev olarak bildiriliyor. Arkada ilevler yalnzca eriim bakmndan
ayrcalkl olan ilevlerdir. Bir arkada ilev iinde arkada olunan snfa ilikin bir nesne,
gsterici ya da referans tanmlanrsa, o nesne gsterici ya da referans yoluyla snfn her
blmne eriilebilir. Yukardaki rnekte balance_dif ilevi Account snfnn bir arkada
ilevi olarak bildirilmitir. Bu yzden balance_dif ilevi iinde tanmlanan Account snfna
ilikin bir snf nesnesi ile snfn her blmne eriilebilir.
classA{
intx,inty;
public:
A(int,int);
friendvoidfunc();
};
Yukardaki rnei inceleyelim. A snfnn x ve y isminde iki private eleman var. func isimli
global ilev snfn arkada ilevi olarak bildiriliyor. func global bir ilev olmasna karn
func ilevi iinde tanmlanan A snf trnden nesnelerin private elemanlar iin eriim
snrlamas ortadan kalkar:
voidfunc()
{
Aa;
a.x=10;
a.y=20;
//...
}

//privateblmeeriiliyoramageerli
//privateblmeeriiliyoramageerli

Eer func normal bir ilev olsayd, yani A snfnn arkada ilevi olmasayd a.x ve a.y
eriimleri geersiz olurdu. friend anahtar szcnn yalnzca ilevin bildiriminde
kullanlmaldr. levin tanmnda friend anahtar szcnn yazlmas bir szdizim
hatasdr.
Arkada ilevler snfn ye ilevleri deildir. Arkada ilevlerin dier global ilevlerden tek
fark eriim ayrcalna sahip olmalardr. Arkada ilevlere this gstericisi geirilmez. Bu
nedenle snfn elemanlarna arkada ilevler iinde dorudan eriilemez.
Uygulamalarda genellikle arkada ilevlerin parametre deikeni arkada olunan snfa
ilikin bir gsterici ya da referans olur. lk rnekteki Account snfna balance_dif ilevini
inceleyelim:

122/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


doublebalance_dif(constAccount&r1,constAccount&r2)
{
returnr1.balancer2.balance;
}
levlerin parametre deikenleri ilev snrlar iindedir. Yani arkada bir ilevin
parametre deikeni arkada olunan snfa ilikin bir nesne, bir gsterici ya da bir
referans ise bu nesne, gsterici ya da referans ile snfn her blmne eriilebilir.
Yukardaki balance_dif ilevinin tanmnda, ilevin parametre deikeni olan r1 ve r2
referanslar nokta ileci ile kullanlarak ismi balance olan private elemana eriiliyor.
phesiz balance_dif ilevi Account snf iinde friend ilev olarak bildirildikten sonra,
aadaki biimlerde de tanmlanabilirdi:
doublebalance_dif(constAccounta1,constAccounta2)
{
returna1.balancea2.balance;
}
ya da
doublebalance_dif(constAccount*p1,constAccount*p2)
{
returnp1>balancep2>balance;
}
Bir ilev, birden fazla snfn arkada ilevi olabilir. Arkada ilev bildiriminin snfn hangi
blmnde yapldnn hibir nemi yoktur. Yukardaki rnekte, Account snfnda
balance_dif ilevi public blmde arkada olarak bildirildi. Ancak private ya da protected
blmde bildirilseydi de bir farkllk olumazd.
Yalnzca global ilevler deil, baka snflarn ye ilevleri de arkada ilev olabilir.
rnein:
classMyclass{
//
voidmyfunc();
};
classHerclass{
//
friendvoidMyclass::myfunc();
};
Yukardaki rnekte Herclass snfn, Myclass snfnn myfunc isimli ilevini arkada olarak
bildiriyor.
Arkada ilev bildirimi ayn zamanda ilevin bildirimi yerine de geer. Bu durumda ilev
bildiriminin bilinirlik alan snf bildiriminin yapl yeriyle belirlenir. rnein:
intmain()
{
classX{
//
friendvoidf();
};
f();
//Geerli
//
}

123/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

voidfunc()
{
//
f();
}

//Geersiz!?levbildirimibubloktatannamaz!

Burada f arkada ilevinin snf iindeki arkadalk bildirimi ayn zamanda ilevin prototip
bildirimi olarak da kabul edilir. Ancak bu bildiriminin bilinirlik alan X snfnn bilinirlik alan
ile ayndr. Yani bu bildirim yalnzca main ilevi iinde bilinir. Bu yzden func ilevi iinde f
ilevi arldnda, daha nce bildirimi yaplmam bir ilev arlm olur.

Arkada levler Ne Zaman Kullanlmaldr


Arkada ilevler eriim bakmndan ayrcalkl ilevler olduundan snfn private
elemanlarnn korunmasn azaltr. Arkada ilevler snfn her blmne eriebildiine
gre, snfn private elemanlara ynelik bir deiiklik yapldnda yalnzca ye ilevleri
deil ayn zamanda arkada ilevleri de yeniden yazmak gerekir. Arkada ilevleri fazlaca
kullanmak snfn private blmnn nemini azaltmay kabul etmek anlamna gelir.
Arkada ilevler karmak durumlarda tasarm ve ilemleri kolaylatrmak iin
kullanlmaldr. Kodun daha kolay yazlmasn salamak iin baz ilevlere gereksiz bir
ekilde arkadalk vermek iyi bir fikir deildir. Arkada ilevlerin kullanlmasn gerekli
duruma getirebilecek en tipik rnek ileleri ykleyen global ilevlerinin yazmdr. Byle
ilevleri ileride ele alacaz.

Arkada Snflar
Bir baka snfn bir ye ilevine arkadalk verilebileceini belirtmitik. Bir snf bir baka
snfn tm ye ilevlerine arkadalk verebilir. Arkada snf bir snfn tm ye ilevlerinin
baka bir snfn arkada ilevi olmas durumudur. Bir snf arkada snf yapmak iin,
arkada olunan snf iinde,
friendclass<snfismi>;
bildirimini yapmak gerekir. Bu bildirimin snfn hangi blmnde yaplm olduunun bir
nemi yoktur. Bu durumda arkada olarak belirtilen snfn tm ye ilevleri ieri ilgili snf
trnden bir nesne, gsterici ya da referans yoluyla snfn her blmne eriilebilir.
Aadaki rnei inceleyin:
classNode{
intval;
Node*next;
friendclassLList;
};
classLList{
public:
voidadd(intval);
voiddelete(size_tn);
Node*get_head();
//
private:
Node*phead;
Node*pnode;
size_tsize;
};
Yukardaki rnekte LList snf Node isimli snfn arkada snfdr. LList snfnn tm ye
ilevleri iinde Node snfna ilikin nesne, gsterici ya da referans yoluyla, Node snfnn

124/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


her blmne eriilebilir. Node snfnn elemanlarnn private blmde olduuna ve
herhangi bir ilev iinde Node snf trnden nesne tanmlanabilecei halde, o nesne
yardmyla snfn private elemanlarna eriilemeyeceine dikkat edin.
Arkada snflar da arkada ilevlerde olduu gibi eriim kolayl salamak iin
kullanlabilir. Tabii arkada snflarn da, private elemanlarnn korunmasn azaltacan
sylemeliyiz.

Arkadalk Bildirimi ift Ynl Deildir


Bir snfn bir baka snfa arkadalk vermesi, arkadalk verilen snftan da bir arkadalk
alnd sonucunu dourmaz. Aadaki rnei inceleyin:
classA{
public:
friendclassB;

voidfunc();
};
classB{
intb;
//...
};
voidA::func()
{
Bobject;
object.b=1;//Geersiz!
}
Yukardaki rnekte A snf B snfna arkadalk veriyor. Bu B snfnn da A snfna
arkadalk verdii sonucunu dourmaz. A snfnn ye ilevi olan func ilevi iinde
tanmlanan B snf trnden object isimli nesnenin private elemanna ulama giriimi
geersizdir, derleme zamannda hata oluturur.

Arkadamn Arkada Benim de Arkadamdr


Bu cmle arkadalk bildirimleri sz konusu olduunda doru deildir. Arkadalk
bildirimlerinde geime zellii sz konusu deildir. Aadaki rnei inceleyin:
classA{
inta;
public:
friendclassB;
};
classB{
friendclassC;
//...
};
classC{
public:
voidfunc();
};
voidC::func()
{
Aobject;
object.a=1;//Geersiz

125/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


}

Yukardaki rnekte A snf B snfna, B snf da C snfna arkadalk veriyor. Bu durumdan


A snfnn C snfna arkadalk verdii gibi bir sonu kmaz. C snfnn func isimli ye
ilevi iinde A snfnn private ksmna erime abas derleme zamannda hata ile
sonulanr.

126/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Snfn Statik Elemanlar ve levleri


ncelikle static anahtar szcnn yerel ve global deikenlerle kullanlmas ile ilgili baz
noktalar hatrlatalm. static anahtar szc yerel deikenlerle kullanldnda
tanmlanan deikenin mr (storage duration) zerinde belirleyici olur. Yani static yerel
bir deiken tanmland bloun banda yaratlp, blok sonlandnda bellekten
boaltlmaz; global deikenlerde olduu gibi programn yklenmesiyle yaratlr; program
sonlanana kadar bellekte kalr. static yerel deikenler blok bilinirlik alanna (block scope)
uyan statik mrl deikenlerdir ve ou zaman global deikenlere seenek olarak
kullanlrlar.
static anahtar szc ile tanmlanan global deikenler, i balantya (internal linkage)
aittir. Yani static global deikenler baka bir modlde extern bildirimi yaplsa bile
kullanlamaz. Bir ilev de bu anlamyla static olarak tanmlanabilir. static ilevler baka
modllerden arlamaz.
C++ dilinde bir snfn elemanlar ve ilevleri de static anahtar szcyle bildirilebilir.
imdi static anahtar szcnn snflarla ilgili kullanmn inceleyelim:

Snfn Statik Elemanlar


Baz durumlarda bir snf trnden tanmlanan tm nesnelerin global bir nesneye erimesi
gerekir. rnek olarak, bir snf trnden ka nesnenin yaratld deerini tutan bir global
deikene gereksinim duyulmas durumunu dnebilirsiniz. Ya da yine global bir
gsterici deikenin, tm snf iin ayrlm olan dinamik bir bloun balang adresini
tuttuunu ve tm snf nesnelerinin bylelikle bu dinamik alana eritiini dnebilirsiniz.
Bu bilgilerin snfn bir eleman olarak tutulmas durumunda, hem snf nesneleri gereksiz
bir biimde byr, hem de bu deerlerin deitirilmesi durumunda deiikliin var olan
tm snf nesneler iin ayr ayr yaplmas gerekir. Bu bilgilerin global deikenlerde
tutulmas durumunda ise, dary ilgilendirmeyen yalnzca sz konusu snfa ilikin bir
kodlama detay darya szdrlm olur. Global deikenin bir baka sakncas da, bunlara
yalnzca snfn ulamasn salayp, snf dnda eriimi engellemenin mmkn
olmaydr. Yani bir global deiken bir snf iin public ya da private olamaz. Yine baka
bir saknca da, bu amala kullanlacak bir global deikenin global isim alann gereksiz
bir ekilde kirletmesidir.
Snfn bir eleman snf bildirimi iinde bana static anahtar szc getirilerek bildirilirse
bir eit snfa zg global deiken gibi ele alnr. Byle bir elemana snfn static eleman
denir. Snfn static eleman ile global deikenler arasnda ama koda yazm biimi
bakmndan hibir fark yoktur. Yalnzca, snfn static elemanlar snf isimleri ile kombine
edilerek ama kod iinde yazlr. static elemanlar snf nesnesi iinde bir yer kaplamaz.
Darda global deikenler gibi saklanr. Yalnzca mantksal adan snfla ilikilendirilirler.
Snfn static elemanlar, global deikenlerde olduu gibi darda ayrca tanmlanmak
zorundadr. Tanmlama ilemi, bildirim snfn hangi blmnde yaplm olursa olsun
gereklidir ve geerlidir. static elemanlarnn tanmlanmas aadaki gibi yaplr:
<tr><snfismi>::<de?iken_ismi>[=ilkde?er];
Genel biimden de grld gibi static elemanlar snf ismi ile birlikte belirtilerek
tanmlanr. rnein X snfnn int trden s isimli bir static eleman yle tanmlanr:
intX::s;
Snfn statik elemanlar, yaratlan snf nesnesinin iinde yer almaz. Yani statik elemanlar
snf nesnesinin sizeof deerini bytmez. Snfn statik bir elemanndan yalnzca bir tane
bulunur. Statik elemanlar aslnda global deikendir. Yalnzca mantksal bakmdan snf ile
ilikilendirilmitir.
Aadaki rnei inceleyin:

127/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classPerson{
private:
char*name;
intno;
public:
Person(constchar*,int);
~Person();
voiddisplay()const;
public:
staticintcount;
};
#include<iostream>
#include<cstring>
usingnamespacestd;
intPerson::count=0;
Person::Person(constchar*nm,intn)
{
name=newchar[strlen(nm)+1];
strcpy(name,nm);
no=n;
++count;
}
voidPerson::display()const
{
cout<<name<<""<<no;
}
Person::~Person()
{
delete[]name;
}
intmain()
{
Personperson("BurakGencer",120);
cout<<sizeof(person)<<endl;
return0;
}
Yukardaki rnekte Person snf trnden person nesnesinin sizeof ileci ile boyutu elde
ediliyor. Elde edilen boyut yalnzca sizeof(char *) + sizeof(int) kadar olur. Snfn static
eleman olan count aslnda global bir deikendir. Bir snf nesnesinin tanmlanmasna
gereksinim duyulmadan statik mrl olacak biimde yaratlr. Bu yzden snf nesnesi
iinde yer kaplamaz. Yukardaki programda eer DOS altnda ve yakn modellerde
allyorsa 4, DOS altnda ve uzak modellerde alyorsanz 6, UNIX ya da Win32
sistemlerinde alyorsanz 8 deerini elde edersiniz. rneimizde snfn static
elemannn ayrca global bir biimde snf ismi belirtilerek aadaki gibi tanmlandn da
gryorsunuz.
intPerson::count=0;

128/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Grdnz gibi statik elemanlara tanmlama srasnda ilkdeer de verilebilir. Ancak
ilkdeer verilmeyen doal trlerden statik elemanlarda, global ve static yerel
deikenlerde olduu gibi ilerinde sfr bulunur. Snfn statik bir eleman snf dnda
tanmlanmaz ise static elemann kullanlmas durumunda derleme zamannda hata
olumaz. Hata balama aamasnda oluur.
Snfn statik elemanlarna dardan ilgili snf trnden nesne, gsterici ya da referans
yoluyla eriilebilir. Tabii statik elemannn public blmde bildirilmi olmas gerekir.
Aadaki main ilevini inceleyin:
intmain()
{
Personx("AliSere",25);
cout<<x.count;
Persony("AhmetAltntart",32);
cout<<y.count;

//1
//2

return0;
}
Burada x.count ile eriilen count deikeni ile y.count ile eriilen count deikeni ayn
deikenlerdir. Snfn statik bir elemanna hangi snf nesnesi ile eriildiinin bir nemi
yoktur. Bu yzden statik elemanlara snf nesnesi olmadan da snf ismi ve znrlk
ileci ile eriilebilir. Byle bir eriimin geerli olmas iin bildirimin public blmde yaplm
olmas gerekir. Aadaki main ilevini inceleyin:
intmain()
{
Personx("AliSere");
cout<<Person::count<<endl;
Persony("AhmetAltntart");
cout<<Person::count<<endl;

//1
//2

return0;
}
rnekte eriim Person::count biiminde hi snf nesnesi kullanlmadan yaplyor. count
isimli eleman, snfn public blmnde bildirildii in eriim geerlidir. static elemanlara
ye ilevler iinde normal elemanlar gibi dorudan eriilebilir. rnein Person snfnn
kurucu ilevi iinde eriim bu biimde salanyor:
Person::Person(constchar*nm,intn)
{
name=newchar[strlen(nm)+1];
strcpy(name,nm);
no=n;
++count;
}
Snfn statik eleman bir dizi ya da gsterici olabilir. Eer dizi ise bildirim srasnda dizinin
boyutu belirtilmeyebilir. Ancak dizinin tanmlamas srasnda dizinin boyutu belirtilmelidir.
Snfa ilikin statik bir diziye tanmlama srasnda kme ayralar iinde ilkdeer de
verilebilir. Bu durumda dizi boyutu belirtilmeyebilir. rnein:

129/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classDate{
private:
intday,month,year;
staticconstchar*week_days[];
public:
//
};
constchar*Date::week_days[]={"Pazartesi","Sal","aramba",
"Perembe","Cuma","Cumartesi","Pazar"};
Snfn statik elemanlar yalnzca bir kez tanmlanmaldr. Bunun iin tanmlama ilemi
bir .cpp dosyas iinde yaplmaldr. Eer tanmlama .h dosyas iinde yaplr, bu dosya da
proje iinde birden fazla yerde eklenirse balama zamannda hata oluur. Snfn statik bir
elemann kullanmak iin o snf trnden nesne tanmlamaya gerek yoktur. Yani snf
trnden hibir nesne tanmlanmasa bile snfn statik elemanlar yine de kullanlabilir.

statik Elemanlar Ne Zaman Kullanlmal


Snfn statik elemanlar aslnda mantksal olarak snfla ilikilendirilmi global
deikenlerdir. Global deikenlere tm ilevler iinde eriilebilirken, statik elemanlara
yalnzca snfn ye ilevleri iinde dorudan eriilebilir. Snfn statik elemanlarna ayrca
snf nesnesi, gstericisi ya da referans ile ya da snf ismi ve znrlk ileci ile de
dardan eriilebilir. Bir global deiken yalnzca bir snf iin anlaml ise onun normal bir
global deiken yerine statik eleman olarak tanmlanmas, algsal bakmdan bilinirlik
alann daraltr. Bylece kodu inceleyen kii deikenin kod ile ilgisini daha iyi
anlamlandrr.
Date snf iin verilen rnekteki 01/01/1900den geen gn saysna ilikin dnmleri
yapan totaldays ve revdays isimli ye ilevleri anmsayn. Bu ilevler aylarn ka ektikleri
bilgisini mon_days isimli bir global diziden elde ediyordu. mon_days isimli dizi global
olmasna karn yalnzca aylarn ka ektiklerinin belirlenmesi amacyla kullanlmaktadr.
Yani mon_days yalnzca Date snfnn ye ilevlerinin kulland global bir dizidir. Eer bu
dizi snfn normal bir eleman yaplsa, btn Date trnden nesneler iinde gereksiz bir
biimde yer kaplard, deil mi? te hem global olarak brakmak hem de snfla
ilikilendirmek iin mon_days dizisi statik eleman olarak tanmland. Ayrca snfn
display_text isimli ilevi, yeniden dzenlenerek, ay isimlerini de yazyla yazdrabilir. Ay
isimleri ve gn isimleri char trden statik gsterici dizilerine yerletirilebilir. Date snfnn
biraz daha gelitirilmi biimini ileride vereceiz.
Snfn statik elemanlar da, snfn elemanlardr. Ancak baz zellikler asndan, snfn
statik elemanlar dier elemanlardan farkllk gsterir:
Bir snfn eleman ayn snf trnden olamaz ama bir snfn ayn snf trnden statik bir
eleman olabilir. Aadaki snf bildirimini inceleyin:
classA{
staticAsa;
A*mptr;
Aax;
};

//Geerli
//Geerli
//Geersiz

Bir snfn statik bir eleman, ayn snfn bir ye ilevinde varsaylan argman olarak
kullanlabilir. Ancak snfn statik olmayan bir eleman bu biimde kullanlmaz:

130/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classA{
intm_x;
staticintms_y;
public:
voidfunc(int=m_x);
voidfoo(int=ms_y);
};

//Geersiz
//Geerli

Snfn statik ye levleri


Snf bildirimi iinde bir ilev, bana static anahtar szc getirilerek bildirilebilir. Byle
ilevlerle snfn statik ye ilevleri denir. Snfn statik ye ilevleri global bir ilev gibidir.
Ancak mantksal bakmdan snfla ilikilendirilmitir. Bu ilevlere this gstericisi geirilmez.
Snfn statik ye ilevlerine this gstericisinin geirilmemesi, o ilevler iinde snfn
elemanlarna ve dier ye ilevlere dorudan eriilemeyecei anlamna gelir.
Snfn statik ye ilevi her ne kadar global bir ilev gibiyse de, tanmlanmas ye
ilevlerde olduu gibi snf ismi belirtilerek yaplr. Date snfnda baz deiiklikler
yapyoruz:
classDate{
private:
intday,month,year;
staticintmon_days[12];
staticchar*mon_tab[12];
staticchar*day_tab[7];
public:
enumDays{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,
Saturday};
Date();
Date(int,int,int);
voiddisplay()const;
voiddisplay_text()const;
longtotaldays()const;
voidrevdays(long);
intweekday()const;
staticboolisleap(int);
//staticyeilev
};
nceki biimde bir yln artk yl olup olmadn bulan isleap isimli ilev normal bir global
ilevdi. Ancak bu ilevin yalnzca tarih ilemleriyle anlaml bir ilevi vardr. O halde
mantksal bakmdan Date snf ile ilikilendirilip alglama kuvvetlendirilmitir. isleap ilevi
darda yle tanmlanabilir:
boolDate::isleap(intyear)
{
returnyear%4==0&&year%100!=0||year%400==0;
}
static anahtar szcnn yalnzca bildirim srasnda yazldna, tanmlama srasnda
yazlmadna dikkat edin. isleap iinde snfn day, month ve year elemanlarna dorudan
eriilemez. Snfn dier ye ilevleri snf nesnesi olmadan dorudan arlamaz.
Grdnz gibi dardaki snf ile mantksal bakmdan ilikili olan ama snfn
elemanlarn ve ye ilevlerini kullanmayan global ilevler snfn statik ilevi yaplabilir.
Snfn statik ye ilevi bir snf nesnesi, gstericisi ya da referansyla arlabilir. Ya da
eer snfn public blmndeyse ar dorudan snf ismi belirtilerek :: znrlk ileci
ile de yaplabilir:

131/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


intmain()
{
Datex;
if(x.isleap(1996))
cout<<"isaleapyear"<<endl;
else
cout<<"isnotaleapyear"<<endl;
if(Date::isleap(2000))
cout<<"isaleapyear"<<endl;
else
cout<<"isnotaleapyear"<<endl;
return0;
}
Burada x.isleap ve Date::isleap biiminde iki ar yaplyor. isleap snfn public
blmnde olduu iin her iki ar biimi de geerlidir. Ancak yine de statik ye
ilevlerin, snf nesnesi kullanmadan snf ismiyle arlmas nerilir. Ne de olsa arda
kullanlan snf nesnesinin hibir zel anlam yoktur.
Snfn statik ilevi, snfn bir ye ilevi iinde dorudan arlabilir. rnein yukardaki
programda totaldays ilevi iinde isleap ilevi dorudan arlyor.
Snfn statik bir ye ilevi iinde statik elemanlar dorudan kullanlabilir. Snfn statik
elemanlarnn snf nesnesi iinde yer kaplamadn anmsayn. Bu durumda statik
elemanlara erimek iin this gstericisi gerekmez. Aada bu biimde kullanma ilikin bir
rnek veriliyor:
classPerson{
private:
char*name_;
intno_;
staticintcount_;
public:
Person(constchar*nm,intn);
~Person();
voiddisplay()const;
staticintget_count();
};
#include<iostream>
#include<cstring>
usingnamespacestd;
intPerson::count_=0;
Person::Person(constchar*nm,intn)
{
name_=newchar[strlen(nm)+1];
strcpy(name_,nm);
no_=n;
++count_;
}
voidPerson::display()const
{
cout<<name_<<endl;
cout<<no_<<endl;
}
intPerson::get_count()

132/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


{
returncount_;
}
Person::~Person()
{
delete[]name_;
}
intmain()
{
Personx("NecatiErgin",25);
Persony("HalukYetis",34);
cout<<Person::get_count();
return0;
}
Bu rnekte daha nce vermi olduumuz Person isimli snfta baz deiiklikler yaptk.
rnein statik count_ elemann snfn private blmne yerletirdik. Bu elemann
deerinin elde edilmesi iin get_count isimli statik bir ye ilev ekledik. get_count
ilevinin yalnzca snfn statik eleman olan count_ ile ilikili olduuna dikkat edin.
Snfn statik ye ilevi ile ayn isimde ve parametre yapsna sahip global bir ilev
bulunabilir. nk snfn statik ilevleri snf ismi ile birletirilerek ama kod iine yazlr.
Snfn kurucu ve sonlandrc ilevleri statik ye ilev olamaz. Bu ilevlerin yaratlan ve
yok edilen nesne zerinde dorudan ilem yapmak zorunda olduunu dnrsek static
ye ilev olmamalar gerektii de aktr.
Statik bir ye ilev const olarak da bildirilemez. Zira bir const ye ilev, this gstericisinin
gsterdii nesne const olan bir ye ilev anlamna gelir. statik ye ilevler this
gstericisine sahip olmadklarna gre, const da olamazlar.
Snfn statik ye ilevleri sonuta snfa ilikin bir ye ilev olduu iin, statik ye ilevleri
iinde snfa ilikin bir nesne tanmlandnda o nesne yoluyla dardan snfn her
blmne eriilebilir.
classSample{
intx;
public:
staticvoidfunc();
};
voidSample::func()
{
Samplesam;
sam.x=20;
//Geerli
//...
}
Bazen de static ye ilevler zel amalar gerekletirmek iin belirli kod kalplarnda
kullanlr. rnein bir snf trnden yalnzca dinamik nesnelerin yaratlmasna izin
verilmesi istendiini dnelim. DynamicOnly bir snf olmak zere
DynamicOnlyd;
biiminde bir nesne yaratlmasna engel olunsun. DynamicOnly snfna ilikin tm
nesnelerin dinamik olarak, yani new ileciyle oluturulmas bir zorunluluk olsun. Bu nasl
salanabilir?
Snfn kurucu ilevleri snfn private blmne yerletirilirse
DynamicOnlyd;

133/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

biiminde bir tanmlama geersiz olur, deil mi? Ancak bu durumda new ileciyle de
nesne yaratlamaz. Hatrlayacanz gibi new ileciyle bir snf nesnesi yaratldnda nce
snf nesnesinin kaplayaca yer kadar dinamik bir alan ayrlyor, daha sonra bu alann
balang adresi snfn kurucu ilevine this adresi olarak geiriliyordu. Kurucu ilev snfn
private blmde olduuna gre nesne yaratlmas yine mmkn olmaz, deil mi?
Ancak snfn kurucu ilevi private blmde ise, ve snfn bir ye ilevi, iinde snfn
baka bir private bir ye ilevi arlabildiine gre, DynamicOnly snfnn bir ye ilevi
iinde dinamik bir nesne yaratlabilir. Peki ye ilevi bir snf nesnesi ile armak
gerektiine gre, byle bir snf nesnesi nasl elde edilecek? te bu noktada static bir ye
ilev kullanlabilir: Dinamik bir snf nesnesinin adresi ile geri dnen statik bir ye ilev:
classDynamicOnly{
DynamicOnly();
//balangileviprivateblmde.
public:
staticDynamicOnly*create_object();
};
DynamicOnly*DynamicOnly::create_object()
{
returnnewDynamicOnly;
//Geerlinkyeileviindebakabirprivateileva?rlabilir.
}
#include<iostream>
usingnamespacestd;
intmain()
{
//DynamicOnlyd; Geersiz!
//DynamicOnly*ptr=newDynamicOnly;
Geersiz!
DynamicOnly*ptr=DynamicOnly::create_object();
//Geerlinkcreate_objectilevipublicblmde
deleteptr;
//Yaratlandinamiknesneyokediliyor.
return0;
}
Yukardaki rneimizde DynamicOnly snfnn kurucu ilevi private blmde bildiriliyor.
Bylece global bir ilev iinde DynamicOnly snf trnden bir nesne yaratlmas
engellenmi oluyor. Ancak bir ye ilev iinde nesne yaratlabilir. Snfn public blmne
yerletirilmi olan create_object isimli statik ye ilev, DynamicOnly snf trnden bir
adresle geri dnyor.
create_object ilevi new ileci ile yaratlm bir nesnenin adresi ile geri dnyor. levimiz
ye ilev statsnde olduu iin, ilevimiz iinde DynamicOnly snfnn private kurucu
ilevinin arlmas geerlidir.
imdi de main ilevine bir gz atalm. main ilevi iinde, statik ye ilev olan
create_object ilevi
DynamicOnly::create_object()
biiminde arlabilir. Bylece ilevin geri dn deeri olan dinamik nesnenin adresi ile
yaratlan dinamik nesne istenildii biimde kullanlabilir.

Snflarn const static Elemanlar


134/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Snfn bir statik eleman const anahtar szc ile bildirilebilir. Bu durumda snfa zg
deeri deimeyecek bir eleman yaratlm olur. Snfn bir const static eleman eer bir
tamsay trnden ise bu elemana snf iinde ilkdeer verilebilir:
classMyclass{
conststaticintsize=100;
inta[size];
//...
};
Bir deimez ifadesiyle ilkdeerini alm const statik eleman bir deimez ifadesi olarak
kullanlabilir. Byle elemanlar yalnzca bir snf ilgilendiren simgesel deimezler olarak
grev yapabilir.

135/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

LE YKLEMES
C dilinde iki yap nesnesi birbiriyle aritmetik ilemlere sokulamaz, karlatrma ileleriyle
yap deikenleri arasnda karlatrma ilemi yaplamaz. Cde bir yap nesnesi yalnzca
ilecin terimi olabilir:
Nokta ileciyle bir yap nesnesinin elemanna eriilebilir.
Adres ileciyle bir yap nesnesinin adresi alnabilir. Bu durumda elde edilen adres yap
trnden bir adrestir.
Yap nesnesi sizeof ilecinin terimi olabilir. Bu durmda retilen deer sz konusu yapnn
bellekte kaplad byte saysdr.
Ayn trden iki yap deikeni birbirine atanabilir.
Eer yap deikenleri zerinde eitli ilemlerin yaplmas isteniyorsa ileme girecek yap
deikenlerini argman olarak alan zel ilevler yazmak gerekir. rnein Cde tarih
ilemlerini gerekletirmek iin, nce tarih bilgilerini bir yap olarak belirlemek ardndan
da bu yapya ilikin bir grup ilev yazmak gerekir.
C++da bir snf nesnesi bir ilecin terimi olabilir. Bu durumda derleyici, ilecin kullanld
ifadeyi bir ilev arsna dntrebilmek iin, programc tarafndan tanmlanan uygun
bir ilevin bulunup bulunmadn aratrr. Derleyici byle bir ilev bulursa, ilecin
bulunduu ifadeyi, bir ileve yaplan arya dntrr. le ifadesinin dntrlecei
uygun bir ilev yoksa, durum derleme zamannda hata olarak deerlendirilir.
Snf tasarlayan programc, tasarlad snfa ilikin nesnelerin belirli ilelerin terimi
olmasn istiyorsa, ilevler tanmlayarak bu amacn salayabilir. C++n var olan
ilelerine bylece tanmlanan snflara ilikin ek anlamlar yklenebilir. Bu araca ile
yklemesi (operator overloading) denir.
le yklemesi, kullanc kodlarn iini kolaylatrr, daha kolay ve daha iyi bir soyutlama
yapmasn salar. le yklemesi ile, var olan ilelerin verdii gl armdan snf
nesneleri iin de faydalanlr. Snf nesneleri sanki doal veri trlerinden nesnelermi gibi
ilelerle birlikte kullanlabilir.
Bir snf nesnesi bir ilecin terimi olmusa aadaki olaslklar sz konusudur.
a) fade derleyici tarafndan bir snfn ye ilevine yaplan arya dntrlr.
b) fade global bir ileve yaplan arya dntrlr.
c) fade derleme zaman hatas olarak deerlendirilir.
Bir ile snfn bir ye ilevi tarafndan yklenebilecei global ileve de yklenebilir.

leleri Ykleyen ye levler


leleri ykleyen ye ilevler snfn dier ye ilevleri gibi bildirilip tanmlanr. Bu
ilevlerin snf bildirimi iindeki bildirimi aadaki gibi olmaldr:
[geridnde?erinintr]ile<ilesimgesi>([parametreler]);
Genel biimde de grld gibi, bu ilevlerin bildirimi dier ye ilevlerde olduu gibi
yaplr. le ykleyen ilevler ile snfn dier ye ilevleri arasndaki tek fark
isimlendirmeye ilikindir. le ykleyen ilevin isimleri operator anahtar szc ile bir
ile simgesinden oluur. rnein:
classMyclass{
private:
inta;
public:
booloperator<(int);
//...
};

136/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Yukardaki rnekte ilev ismi olarak operator< kullanlyor. operator, C++n bir anahtar
szcdr. Hem bildirimde hem de tanmlama srasnda kullanlmas gerekir. operator ile
> ayr ayr atomlar olduu iin aralarna istenildii kadar boluk karakteri koyulabilecei
gibi bu iki atom bitiik de yazlabilir. le simgesi ancak C++n ilelerinden biri olabilir.
C++n ileci olmayan bir simge iin ile ykleyen ilev yazlamaz. rnein aadaki
ilevin bildirimi geerli deildir:
voidoperator$(int);//Geersiz
nk C++da $ atomuyla belirtilen bir ile yoktur.
leleri ykleyen ye ilevlerin tanmlanmas ve arlmas dier ye ilevler gibi yaplr.
rnein yukarda bildirilen operator> ilevi snfn dnda aadaki gibi tanmlanabilir.

leleri Ykleyen levlerin Parametrik Yaps


Baz ileler hari olmak zere ileleri ykleyen ilevlerin geri dn deerleri herhangi
bir trden olabilir. Ancak parametre deikeni saylar zerinde bir koul vardr. Bir snfn
yesi olan ile ykleyici ilevler ya hi parametre almaz ya da tek parametre alr. Tek
terimli (unary) ilelere ilikin ilevlerin parametresiz olmas, iki terimli (binary) ilelere
ilikin ilevlerin ise tek parametre almas zorunludur. Aadaki rnei inceleyin:
classComplex{
doublereal,imag;
public:
Complex(double,double);
Complexoperator/(double)const;
booloperator!()const;
//...
};
Complex isimli snfn operator/ ilevinin tek bir parametre deikeni var. lev Complex
trne geri dnyor. Blme ileci iki terimli olduu iin, ye ilev ile yklendiinde, ilevi
tek parametresi olmal. rnein bu ilevin snf iinde
Complexoperator/(double,double)const;
biiminde bildirilmesi geersiz olurdu.
Complex snfnn operator! ilevinin ise, parametre deikeninin olmadn bu ilevin
bool trne geri dndn gryorsunuz. Tek terimli mantksal deil ileci ye ilev ile
yklendiinde, ilevin parametre deikeni olmamaldr. rnein bu ilev
booloperator!(int)const;
biiminde bildirilseydi, bildirim geersiz olurdu.

137/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Ancak baz ileler hem tek terimli hem de iki terimli olarak kullanlr. rnein * ileci
arpma ileci olarak kullanldnda iki terimli iken, ierik ileci olarak kullanldnda tek
terimlidir. Bu ile hem binary hem de unary ile olarak yklenebilir. Benzer durum +, -,
& ileleri iin de geerlidir. Bu ileler de hem tek terimli hem de iki terimli ile olarak
yklenebilir.

leleri Ykleyen ye levlere Yaplan arlar


leleri ykleyen ilevler hem normal bir ilev gibi, hem de bir ilecin kullanlmasyla ksa
biimde arlabilir. Zaten bu ilevlerin varlk nedeni ksa arnn verdii okuma ve
yazma kolaylndan faydalanmaktr. x bir snf nesnesi, y herhangi bir trden nesne ya da
deimez olmak zere,
x.operator<ilesimgesi>(y);
gibi bir ar biimi ile,
x<ileatomu>y
ar edeerdir. rnein;
z=x+y;
ile
z.operator=(x.operator+(y));
ayn anlamdadr. Ya da rnein,
x.operator!();
yerine ksaca
!x
yazlabilir. phesiz bu ksa yaz biimi daha kolay okunabilir. Ksa ar biimi ile sanki
snf nesneleri normal ilelerle ileme sokuluyormu gibi bir alg dzeyi elde edilmi olur.
Bylece snf kullanan programclarn iini kolaylar.
object bir snf trnden bir nesne ve right_operand iki terimli bir ilecin sa terimi olsun:
object+right_operand
biimindeki bir ifade derleyici tarafndan aadaki gibi bir ye ilev arsna
dntrlebilir:
object.operator+(right_operand);
Yukardaki rnekte toplama ilecinin solundaki snf nesnesi iin, object nesnesinin ait
olduu snfn operator+ ye ilevi arlyor. Bir ye ilevin bir snf nesnesi ile arlmas
durumunda snf nesnesinin adresinin ileve gizlice this adresi olarak geirildiini
biliyorsunuz. Toplama ileci iin arlacak ilevin her iki nesne zerinde ilem
yapabilmesi iin, iki nesneye de ulamas gerekir, deil mi?
Soldaki snf nesnesinin adresi this adresi olarak ileve geirildiine gre, ilevin yalnzca
sadaki nesnenin deerini almas gerekir. te bu yzden iki terimli bir ile ye ilev
olarak yklendiinde, bu ilevin tek bir parametresi olmaldr.
!object

138/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

gibi bir ifade de ye ilev arsna dntrlebilir.


object.operator!();
Bu ilev zaten object nesnesinin adresini this adresi olarak alacana gre ve ! ilecinin
baka da bir terimi olmadna gre ilevin parametre deikeninin olmamas gerekir.
Bir ileci ykleyen ilevi yazarken ilecin ald terim says (arity) deitirilemez. rnein
! ilecinin Complex isimli bir snf iin ye ilev biiminde yklenmek istendiini
dnelim. ! ileci C++ n tek terimli ileci olduuna gre, bu ilecin grevini slenecek
ilevin parametre deikeni olmamaldr.

leleri Ykleyen Global levler


Bir snf nesnesi bir ilecin terimi olduunda global bir ilevin arlmas da salanabilir.
Bu durumda arlan ilevlere ile ykleyen gloabal ilev (global operator function)
denir. a ve b Myclass isimli bir snfa ait nesneler olmak zere a + b gibi bir ifade, uygun
bir global ilevin tanmlanmas durumunda
operator+(a,b)
gibi bir arya dntrlebilir. Bu durumda byle bir global ilevin iki parametre
deikeni olmaldr. levin bildirimi aadaki gibi olabilir:
Myclassoperator+(constMyclass&,constMyclass&);
Bir ileci ykleyen gobal ilevin ka parametre deikeni olmal? Global ilevler snf
nesnelerinin adreslerini gizlice almadklarna gre, ile ka terimli ise ilevin de o kadar
parametresi olmaldr. ki terimli bir ilecin sol teriminin bir snf nesnesi olmamas
durumunda bir ye ilevin arlamayacan biliyoruz.
Myclassm;
tanmlanmasndan sonra m + 5 gibi bir ifade iin snfn operator+ ilevi arlabilir.
Ancak,
5+m
gibi bir ifade iin snfn operator+ ilevinin arlmas mmkn deildir. Ancak toplama
ilecinin deime zellii olduuna gre Myclass snf iin de bu durumun geerli olmas
gerekir deil mi? Myclass snf iin global bir operator+ ilevinin tanmlanm olmas
durumunda yukardaki ifade aadaki gibi bir arya dntrlebilir:
operator+(5,m);
leleri ykleyen ilevlere rnek verebilmek iin aada Myint isminde yeni bir snf
tanmlyoruz. Myint snf trnden bir nesne C++n nceden tanmlanm tr olan int
trnn yerine kullanlabilecek. Snf yalnzca ile ykleyen ilevlere rnek vermek iin
tanmlyoruz. Snfn bildirimini inceleyin:
classMyint{
intm_val;
public:
Myint(int=0);
//...
};

139/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Myint snf trnden bir nesnenin iinde tamsay deeri tutmas ve nesnenin C++n
doal veri tr olan int trnn sokulabilecei her trl ileme sokulabilmesi
hedefleniyor. Tabii istenirse snfa doal veri tr olan int trnde olmayan baz zellikler
de eklenebilir. Snfn private blmnde yer alan m_val isimli eleman, snf nesnesinin
temsil ettii deeri tutmak iin bildirildi.
Snfn kurucu ilevi varsaylan deer alyor. Kurucu ileve bir argman gnderilmedii
zaman nesnenin m_val isimli eleman 0 deerini alr. Yani nesne 0 deerini tutuyor olur.
Dier taraftan kurucu ilev tek parametre deikenine sahip olduu iin dntren
kurucu ilev olarak da grev yapar. Yani int trden olan bir ifade ya da otomatik
dnmle int trne dntrlebilecek doal trlerden bir ifade, otomatik olarak Myint
snf trnden geici bir nesneye dntrlebilir. Otomatik dnmn istenmemesi
durumunda kurucu ilev explicit anahtar szcyle tanmlanabilirdi.
Snfn kurucu ilevi aada tanmlyoruz:
Myint::Myint(intval):m_val(val){}
Kurucu ilevin tamamnda MIL szdiziminin kullanldn gryorsunuz.
Snf iin kopyalayan kurucu ilevin, atama ilevinin, ve sonlandrc ilevin
tanmlanmasnmasna gerek yok, deil mi? Derleyicinin yazaca ilevler yeterli olur.
Myint snf trnden iki nesnenin elemanlarnn karlkl olarak biribirine atanmasnda bir
saknca olmaz.

Karlatrma lelerinin Yklenmesi


C++n tm karlatrma ileleri iki terimlidir. Karlatrma ilelerini snfn bir ye
ileviyle ya da global bir ilevle yklemek mmkndr. Karlatrma ilelerinin bool
trden deer rettiini biliyorsunuz. Ortak arayz korumak ve ayn armdan
faydalanmak iin, bir snfa ilikin karlatrma ilevlerinin de benzer biimde bool trne
geri dnmesi tercih edilir. ye ilevler olarak yazldklarnda tek parametre deikenine
sahip olurlar. Global ilevler olarak yazlmalar durumunda ise, iki parametre deikeninin
olmas gerekir.
Myint snf iin karlatrma ilelerini ye ilevler olarak bildiriyoruz.
classMyint{
public:
//...
booloperator==(constMyint&r)const;
booloperator!=(constMyint&r)const;
booloperator<(constMyint&r)const;
booloperator<=(constMyint&r)const;
booloperator>(constMyint&r)const;
booloperator>=(constMyint&r)const;
//...
};
Tm ye karlatrma ilevlerinin bool trne geri dndn gryorsunuz.
Karlatrma ilelerinin yan etkisi yoktur. Yani karlatrma ileminin sonucunda ilecin
sa ya da sol terimi olan nesnelerin deeri deitirilmez. lecin sol terimi olan nesnenin
deerinin deitirilmeyecei iin ilevleri const olarak bildirdik. Karlatrma ileleri sa
terimleri olan nesneleri de deitirmeyecekleri iin ilevlerin parametre deikenleri Myint
snf trnden bir const referans olarak seildi. Bu referans ilgili ilecin sa terimi olan
snf nesnesinin yerine geer. levlerin const ye ilevler olmalar ve const referans
parametreye sahip olmalar nemlidir. Bylelikle const snf nesneleri de bu ilelerin
terimi olabilir. Aada ilev tanmlar yer alyor.

140/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


boolMyint::operator==(constMyint&r)const
{
returnm_val<r.m_val;
}

boolMyint::operator!=(constMyint&r)const
{
returnr<*this;
}
boolMyint::operator<(constMyint&r)const
{
return!(*this<r);
}
boolMyint::operator<=(constMyint&r)const
{
return!(*this>r);
}
boolMyint::operator>(constMyint&r)const
{
return*this<r||r<*this;
}
boolMyint::operator>=(constMyint&r)const
{
return!(*this!=r);
}
Bir ye ilevin baka bir ye ilevi dorudan arlabileceini biliyorsunuz. leci ykleyen
ilev iinde de baka bir ye ile ykleyen ilev dorudan arlabilir. Myint snf nce <
ilevini tanmlyor. Dier karlatrma ilevleri grevlerini bu ilevi ararak
gerekletiriyor. Bylelikle ileride snfnn isel yapsnda bir deiiklik olmas durumunda,
daha az ye ilevin kodunda deiiklik yaplmas salanm olur.
Myint snfnn int trden parametresi olan bir dntren kurucu ileve sahip olduunu
gryorsunuz. leleri ykleyen ilevlerin sa terimleri doal veri trlerinden olursa
arlan ilevlere gnderilen argmanlar otomatik tr dnm ile Myint snfna
dntrlr. ye ilevlerin parametre deikenleri Myint snf trnden const referans
olduuna gre, rnein
intmain()
{
Myinti(25);

if(i==25)
cout<<"do?ru"<<endl;

return0;
}
gibi bir kod paras geerlidir. nk
i==25

141/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


ifadesi
i.operator==(25);
ifadesine edeer olduundan, derleyici bu ifadeyi de otomatik tr dnmyle
i.operator==(Myint(25));
biiminde ele alr.

Aritmetik lelerin Yklenmesi


ki terimli aritmetik ileler, yani toplama, karma, arpma ve blme ileleri, ye ilevler
ya da global ilevlere yklenebilir. Bu ileleri ykleyen ilevler ounlukla ilgili snf
trne geri dner. ye ilevler olarak yazldklarnda tek parametre deikenine sahip
olur. Global ilevlerin ise iki parametresi olur.
Myint snfnn aritmetik ilelerini snfn ye ilevleri olarak bildiriyoruz:
classMyint{
public:
//...
Myintoperator+(constMyint&r)const;
Myintoperator(constMyint&r)const;
Myintoperator*(constMyint&r)const;
Myintoperator/(constMyint&r)const;
Myintoperator%(constMyint&r)const;
};
i1 ve i2 Myint snf trnden nesneler olmak zere
i1+i2
gibi bir toplama ileminden yine Myint snf trnden bir deer elde edilmesi beklenir,
deil mi? Bu durumda toplama ilevleri Myint trnden bir deer dndrmelidir. levin
neden Myint & ya da Myint * trne geri dnemeyeceini tartn. levimizin Myint snf
trnden bir referansa geri dndn dnelim. Geri dn deeri olan referans hangi
nesnenin yerine geebilir? Yerel bir nesneyi referans yoluyla geri dndrmenin bir
programlama hatas olduunu biliyorsunuz. Dinamik bir nesneyi, ya da statik yerel bir
nesneyi geri dndrmek de ilevin kullanmn olduka snrlar.
Aritmetik ileler terimleri olan nesneleri deitirmez. Bu ileler ykleyen ye ilevlerin
const ye ilev olmas gerekir. Bu ilevlerin hem kendileri const ye parametre
deikenleri const referans olmalolan const ye ilevler olmaldr. levlerin tanmlarn
inceleyin:

142/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


MyintMyint::operator+(constMyint&r)const
{
returnMyint(m_val+r.m_val);
}
MyintMyint::operator(constMyint&r)const
{
returnMyint(m_val+r.m_val);
}
MyintMyint::operator*(constMyint&r)const
{
returnMyint(m_val*r.m_val);
}
MyintMyint::operator/(constMyint&r)const
{
returnMyint(m_val/r.m_val);
}
MyintMyint::operator%(constMyint&r)const
{
returnMyint(m_val%r.m_val);
}
levlerin return ifadelerinin Myint trden bir geici nesne olduuna dikkat edin.
operator+ ilevi aadaki gibi de yazlabilirdi:
MyintMyint::operator+(constMyint&r)const
{
Myintresult;
result.m_val=m_val+r.m_val;
returnresult;
}
Yukardaki ilev tanmnda nce yerel result nesnesi iin varsaylan kurucu ilev arlyor.
Daha sonra result nesnesine ilemin sonucu olan deer yerletiriliyor. result nesnesinin
deeri ile geri dnlyor. Oysa yazlan ilk kodda dorudan bir geici nesnenin deeri ile
geri dnlmt. Bylece hem ilem maaliyeti azaltlm olur hem de derleyiciye daha
fazla eniyileme ilemi yapma olana verilir.

lemli Atama lelerinin Yklenmesi


imdi de ilemli atama ilelerini inceleyelim. Toplama ilevinin tanmlanmas += ilevinin
derleyici tarafndan yazlaca anlamna gelmez. Bir Myint snf nesnesi += ilecinin terimi
olursa, programc tarafndan tanmlanm bir operator+= ilevi olmaldr.
lemli atama ileleri de ye ilev ya da global ilevler olarak yklenebilir. Ancak bu
ilevler de snf nesnesini deitirdikleri iin ye ilev olarak yklenmeleri ok daha doal
olur. lemli atama ilevlerinin snf iinde bildirimlerini yapalm:
classMyint{
public:
//...
Myint&operator+=(constMyint&r);
Myint&operator=(constMyint&r);
Myint&operator*=(constMyint&r);
Myint&operator/=(constMyint&r);
Myint&operator%=(constMyint&r);

143/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


};

Doal trler sz konusu olduunda, atama ilelerinin rettii deer nesneye atanan
deerdir. Ayn arayz salayabilmek iin bu ileleri ykleyen ilevlerin geri dn
deerinin Myint snf trnden referans yapldn gryorsunuz. Bylece bir ifade iinde
birden fazla atama ilecinin kullanlmas olana getiriliyor. lemli atama ilecinin sa
terimi olan nesne byle bir ilemden etkilenmeyecei iin ilevin parametre deikeni
const Myint & trnden yaplmal. levlerin tanmn aada yapyoruz:
Myint&Myint::operator+=(constMyint&r)
{
m_val+=r.m_val;
return*this;
}
Myint&Myint::operator=(constMyint&r)
{
m_val=r.m_val;
return*this;
}
Myint&Myint::operator*=(constMyint&r)
{
m_val*=r.m_val
return*this;
}
Myint&Myint::operator/=(constMyint&r)
{
m_val/=r.m_val;
return*this;
}
Myint&Myint::operator%=(constMyint&r)
{
m_val%=r.m_val;
return*this;
}

++ ve -- lelerinin Yklenmesi
++ ve - ilelerinin hem nek hem de sonek konumunda kullanldklarn biliyorsunuz.
Bu ileler global ilevler ile de yklenebilir. Ancak bu ileleri ykleyen ilevler
ounlukla snf nesnesi zerinde deiiklik yapt iin ye ilevler olarak yazlmalar
tercih edilir.
nek ve sonek konumunda bulunabilen bu ilevlerin ayr ayr yklenebilmesi iin
ilevlerin imzalarnn farkl olmas gerekir. te bu nedenle bu ileleri ykleyen ilevler
iin yle bir kural getirilmitir: Bu ileler ye ilevler ile yklendiklerinde, nek
konumunda olanlar iin ilevin parametre deikeni olmaz. Ancak sonek konumundaki
ileci ykleyen ilevin int trden bir parametre deikeni olur. Bu parametre deikeninin

144/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


amac bir deer tamak deil, yalnzca ileve farkl bir imza kazandrmaktr. Myint
snfnn tanm iinde yer alan ++ ve - ilevlerinin bildirimlerini inceleyelim.
classMyint{
public:
//...
Myint&operator++();
Myint&operator();
Myint&operator++(int);//sonek++
Myint&operator(int);//sonek
};
nek konumundaki ileleri ykleyen ilevler Myint snf trnden referansa dnerken,
sonek konumunda olanlar Myint trne geri dnyor. Acaba neden? Bildiiniz gibi, bu
ilelerin terimi doal trden nesneler olduklarnda, ileler yan etki olarak, terimi olan
nesnelerin deerlerini 1 arttrr ya da azaltr. le ister sonek ister nek konumunda olsun
terimi olan nesnenin deeri yan etki sonucu deiir. Ancak ilecin rettii deer nek ya
da sonek konumu iin farkldr. nek konumundaki ++ ileci, terimi olan nesnenin
deerinin 1 fazlasn retirken sonek konumundaki ++ ileci terimi olan nesnenin kendi
deerini retir.
Snf nesneleri iin yazlan ++ ilevlerinde de ilecin bu zelliine ounlukla uyulur. Zaten
daha nce de sylendii gibi ile yklemesinin temel amalarndan biri ilelerin doal
trler iin verdii arm ve soyutlamadan snf nesneleri iin de faydalanmaktadr.
Myint snf iin ++ ilevleri aadaki gibi yazlabilir. nce nek konumundaki ++ ileci
iin bir ilev tanmlayalm.
Myint&Myint::operator++()
{
return*this+=1;
}
levi birlikte inceleyelim. levin return deyiminde daha nce yazlan += ilevi arlyor.
*this+=1
Yukardaki ilev ars ile operator+= ilevi *this nesnesinin m_val elemannn deerini 1
arttryor. Daha nce yazlan += ilevi *this nesnesini geri dndrdne gre, ++ ilevi
de *this nesnesini geri dndrm oluyor. Bylece ++ ilecinin terimi olan snf
nesnesinin artm deerini kullanma olana getiriliyor.
Myinta,b(9);
gibi bir tanmlamadan sonra
a=++b;
atama deyimi
a.operator=(b.operator++());
gibi bir arya dntrlr deil mi?
imdi de sonek konumundaki ++ ilecini ykleyen ilevi tanmlayalm.

145/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


MyintMyint::operator++()
{
Myintret_val(*this);
++*this;

returnret_val;
}
levin int trden isimlendirilmi bir parametre deikenine sahip olduunu gryorsunuz.
C dilinde szdizimi hatas olan bu durum C++ dilinde geerlidir! C++ da bir ilevin
parametre deikenine isim verme zorunluluu yoktur. Daha nce de sylendii gibi bu
parametre deikeninin tek amac ilevin imzasn nek konumunda olan operator++
ilevinden farkl klmaktr. nek konumunda olan ++ ilevi terimi olan nesnenin kendi
deerini rettii iin, ilev de benzer biimde nesnenin kendi deerini geri dndrmelidir.
Bu yzden nesnenin deeri, daha sonra geri dn deeri olarak kullanmak zere ret_val
isimli bir nesnede saklanyor. Daha nce tanmlanan ++ ilevi ile m_val elemannn deeri
1 artrdktan sonra nesnenin arttrlmadan nceki deerini tutan ret_val nesnesinin deeri
ile geri dnlyor.
rnekler ++ ilevleri iin verildi ancak - ileler iin de tamamen benzer kodlar sz
konusudur.
Yazlan ilevleri aadaki main ileviyle snayabiliriz:
#include<iostream>
usingnamespacestd;
intmain()
{
Myintx1(10),x2(20);
Myinty1(++x1),y2(x2++);
cout<<"y1="<<y1<<endl;
cout<<"y2="<<y2<<endl;
cout<<"x1="<<x1<<endl;
cout<<"x1="<<x1<<endl;

return0;
}

leleri Ykleyen Global levlerin Yazlmas


lelerin ou global ilev biiminde de yklenebilir. Yukardaki rnekte Myint snf iin
toplama ileci ye ilev ile yklenmiti. imdi ayn ileci global ilevle ykleyelim.
Myintoperator+(constMyint&,constMyint&);
Byle bir ilevin var olmas durumunda
Myinta(10),b(20);
a+b
gibi bir ifade, daha nce sylendii gibi
operator+(a,b)

146/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


gibi bir ilev arsna dntrlr.
leleri ykleyen global ilevler snfn ye ilevler olmad iin bu ilevler iinde normal
olarak snfn private blmne eriilemez.
Myintoperator+(constMyint&r1,constMyint&r2)
{
returnMyint(r1.m_val,r2.m_val);//Geersiz!
}
Yukardaki rnekte operator+ ilevi iinde snfn private m_val elemanna eriilemez.
lev snfn yesi olmad iin, r1 ve r2 nesnelerinin private elemanlarna erimesi sz
konusu deildir? Ancak uygun bir geri dn deeri retmek iin bu private elemanlarn
deerlerine gereksinim duyuluyor.
Bu durumda ileci ykleyen global bir ilev, iini nasl yapabilir?
levin kendisinden beklenen ii yapabilmesi iin farkl yntemler kullanlabilir:
Snfn public arayznde bulunan bir get ilevi ile m_val elemannn deeri elde edilebilir.
Ancak byle bir get ilevinin bulunmas, her snf iin istenen bir durum deildir.
classMyint{
public:
intget_val()const{returnm_val;}
//...
};
Global operator+ ilevi get_val public ye ilevini ararak m_val deerini elde edebilir.
Myintoperator+(constMyint&r1,constMyint&r2)
{
returnMyint(r1.get_val(),r2.get_val());
}
Myint snf, bu ileve arkadalk bildirimi ile private elemanlarna zel eriim hakk
verebilir.
classMyint{
//...
friendMyintoperator+(constMyint&,constMyint&);
};
Global ilev iini grebilmek iin snfn bir public ilevini arabilir. Aadaki kodu
inceleyin:
Myintoperator+(constMyint&r1,constMyint&r2)
{
returnMyint(r1)+=r2;
}
levin ana blou iinde yaratlan Myint snf trnden geici nesne, ilkdeerini ilevin
parametre deikeni olan r1 nesnesinden alyor. Daha sonra geici nesne iin snfn +=
ilevi arlyor. Bu ye ileve r2 nesnesi argman olarak gnderiliyor. leci ykleyen
global ilev, ye += ilevinin geri dn deeri ileri geri dnyor.
Ayn ilecin hem ye hem de global ilev olarak yklenmesi, ou durumda algsal
karmakla neden olur. Bu nedenle programclar tarafndan pek tercih edilmez. Ayrca
baz durumlarda, ileve yaplan ar yznden ift anlamllk hatas oluabilir. Yani
derleyicinin ye ilevin mi global ilevin mi arlmak istendiini anlayamamas sonucu bir

147/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


hata durumu oluabilir. phesiz bu hata durumu rnein operator+ ilevinin ilev ar
ileciyle arlmasyla engellenebilir:
classMyclass{
public:
Myclassoperator+(Myclass,Myclass);
};
Myclassoperator+(Myclass,Myclass);
voidfunc()
{
Myclassa,b,c;
//...
c=a+b;//iftanlamllkhatasyeilevmiglobalilevmi?
c=operator+(a,b);//iftanlamllkhatasyokglobalilev
c=a.operator+(b);//iftanlamllkhatasyokyeilev
//
}

le Ykleyen levlere likin Kstlamalar


C++n baz ileleri yklenemez. Bu ileler unlardr:
znrlk ileci (::)
sizeof ileci (sizeof)
koul ileci ?:
. ileci
.* ileci (C dilinde yer almayan bu ileci ileride ele alacaz)
Yukarda listesi verilen ilelerin snfn ye ilevleriyle ya da global ilevlerle yklenmesi
geersizdir.
Aadaki ileler ise yalnzca snfn ye ilevleriyle yklenebilir:
keli ayra ileci
ilev ar ileci
atama ileci
ok ileci
Bu ilelerin global ilevler biiminde yklenmeleri geersizdir.
leleri ykleyen ilevler varsaylan argman alamaz. Bu kurala uymayan tek ilev, ilev
ar ilecini ykleyen ilevdir. Bu ilevin yklenmesini ileride ele alacaz.

le Ykleyen levlerin arlma Sras


le ykleyen ilevler C++ dilinde ilelerin belirlenmi ncelik srasna gre arlr.
Aadaki kod parasn inceleyin:
Myinta(1),b(5),c(7),d;
d=++a*bc%2;
Yukardaki ifade derleyici tarafndan yle bir koda dntrlr:
d.operator=(a.operator++().operator*(b).operator(c.operator%(2)));

148/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


lelerin dil tarafndan belilenmi ncelik seviyeleri deitirilemez.

Keli Ayra lecini Ykleyen lev


Keli ayra ileci snfn ye ileviyle yklenebilir. levin yalnzca bir parametre deikeni
olmaldr.
a bir snf nesnesi olmak zere
a[b] gibi bir ifade, keli ayra ilevinin tanmlanm olmas durumunda
a.operator[](b)
gibi bir ilev arsna dntrlr.
Keli ayra ilevi genellikle bir referans trne geri dner. Bylece, ilev ar ifadesi
dorudan bir nesne olarak kullanlabilir.
int trden dinamik bir dizinin kullanmn kolaylatrmak iin, Array isimli bir snfn
tanmlandn dnelim.
operator[] ilevinin uygun biimde tanmlanmas durumunda, Array snf trnden a gibi
bir nesne ile
a[5]=20;
gibi bir atama yaplabilir. Konumuzla dorudan ilgisi olmayan ilevleri kartarak, Array
snfn tanmlayalm.
classArray{
int*m_p;
size_tm_size;
public:
Array(intsize=0,intval=0);
~Array();
intoperator[](int)const;
int&operator[](int);
//
};
Array::Array(intsize,intval)
{
m_size=size;
if(m_size==0){
m_p=0;
return;
}
m_p=newint[m_size];
for(intk=0;k<m_size;++k)
m_p[k]=val;
}
Array::~Array()
{
delete[]m_p;
}
int&Array::operator[](intindex)
{
returnm_p[index];
}
intArray::operator[](intindex)const

149/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


{
returnm_p[index];
}
#include<iostream>
intmain()
{
Arraya(20);
constArrayca(10,1);

a[3]=5;
//ca[2]=10;//Geersiz
Std::cout<<ca[5]<<std::endl;

return0;
}
Array snfnn kurucu ilevi, istenen sayda elemann saca byklkte bir blok elde
ediyor. Sonlandrc ilev ise ayrlan dinamik blou free storea geri veriyor.
Snfn public blmnde iki ayr operator[] ilevinin bildirildiini gryorsunuz. levlerin
imzalarndaki tek farkllk, birinin const ye ilev iken dierinin const olmayan bir ye
ilev olmas. Byle ilev yklemesine const yklemesi (const overloading) dendiini
anmsayn. Acaba neden iki ayr ilev tanmland?
nce const olmayan operator[] ilevini inceleyelim. levimiz elde edilen dinamik dizinin
istenen indisli elemann, referans yoluyla dndryor. Bylece main ilevi iinde
a[3]=5;
gibi bir atama ile, dinamik dizi iindeki 3 indisli elemana atama yaplm olur. Bu atama
deyimi derleyici tarafndan aadaki biime dntrlr:
a.operator[](3)=5;
const bir dizinin elemanlarna atama ileci ile atama yaplamaz, deil mi? Benzer biimde
const bir Array nesnesinin tuttuu elemanlara da atama yaplamamas gerekir. te bu
nedenle iki ayr ilev tanmladk.
Array snf trnden const bir nesne olan a nesnesi ile operator[] ilevi arldnda,
snfn const ye ilevi arlr. const ye ilevin geri dn deeri bir referans olmad
iin
ca[4]=10;
gibi bir atama geersizdir.

Snf Nesnelerinin Deerlerinin Yazdrlmas ve Klavyeden Snf


Nesnelerine Deer Alnmas
Cden farkl olarak C++ dilinde giri k ilemlerinin ablon bazl snflar yardmyla
yapldn biliyorsunuz.
inti=10;
doubled=3.5;
cout<<i<<d;
Yukardaki kod parasnda yer alan cout, aslnda ostream isimli bir snf trnden global
bir nesnedir. ostream snfnn bir seri operator << ilevi vardr. C++ dilinin doal

150/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


trlerinden parametre deikenlerine sahip olan bu ilevler, yine ostream snf trnden
referansa geri dner.
cout<<i<<d
gibi bir ifade derleyici tarafndan
cout.operator<<(i).operator<<(d)
biimine dntrlr.
cout nesnesi iin arlan ilk ykleyici ilev i deikenini referans yoluyla alr. i
deikeninin deerini ekrana yazdrdktan sonra cout nesnesini referans yoluyla geri
dndrr. Geri dndrlen cout nesnesi iin ikinci kez arlan operator<< ilevi, bu kez
d nesnesini referans yoluyla argman olarak alr. d nesnesinin deeri ekrana
yazdrldktan sonra cout nesnesi yine referans yoluyla geri dndrlr.
Nasl doal trlerden ifadelerin deerleri ostream snfnn ye operator<< ilevleriyle
ekrana yazdrlabiliyorsa, programc tarafndan tanmlanan bir snf trnden nesnenin
deeri de, global<< ilevi yardmyla ekrana ya da bir dosyaya yazdrlabilir. Bylece k
ilemleri iin doal veri trleri ve programc tarafndan tanmlanan trler arasnda ortak
bir arayz salanm olur. Myint snf trnden nesnelerin deerlerinin, aadaki biimde
ekrana yazdrlmak istendiini dnelim.
Myinta(10),b(20);
cout<<a<<""<<b<<endl;
ostream snfnn kodlarna dorudan ekleme yaplamaz. Ama global bir operator<< ilevi
yazlabilir:
cout<<a
gibi bir ifadenin global bir ilev arsna dntrlmesi iin ilevin iki parametre
deikenine sahip olmas gerekir. Birinci parametre cout nesnesini alrken ikinci
parametre Myint snf trnden a nesnesini alr. levin geri dn deeri ostream snf
trnden bir referans yaplrsa, ilevin yine cout nesnesini geri dndrmesi salanabilir.
Aadaki ilevi inceleyin:
ostream&operator<<(ostream&os,constMyint&r)
{
returnos<<r.m_val;
}
ilevimiz
operator<<(cout,a)
biiminde arldna gre, ilevin parametre deikeni olan referans os, cout nesnesinin
yerine geer. kinci parametre olan r referans da a nesnesinin yerine geer. levin tanm
iindeki
os<<r.m_val
ifadesi, bu kez ostream snfnn ye ilevini ararak m_val isimli elemann deerini
ekrana yazdrr. levimiz
os.operator<<(r.m_val)

151/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


arsnn geri dn deeriyle geri dner. Bu da cout nesnesinin kendisidir.
Yalnz ufak bir sorunumuz var. Global ilev iinde
r.m_val
eriiminin geerli olmas iin Myint snfnn, global ileve arkadalk vermesi gerekir, deil
mi?
classMyint{
//...
friendstd::ostream&operator<<(std::ostream&os,constMyint&r);
};
C++n standart ostream snf std isimalan iinde tanmlandndan, arkadalk
bildiriminde bu snfn ismi, std::ostream olarak yazlyor.
imdi de Myint snf trnden bir nesneye standart giri biriminden (klavyeden) deer
alan bir ilev tanmlayalm:
inti=10;
doubled=3.5;
cin>>i>>d;
Yukardaki kod parasnda yer alan cin, istream isimli bir snf trnden global bir
nesnedir. istream snfnn bir seri operator>> ilevi vardr. C++ dilinin doal trlerinden
parametre deikenlerine sahip olan bu ilevler, yine istream snf trnden referansa
geri dner.
cin>>i>>d
gibi bir ifade derleyici tarafndan
cin.operator>>(i).operator>>(d)
biimine dntrlr.
arlan ilk ilev, i deikenini referans yoluyla alr. lev i deikenini klavyeden ald
deerle set ettikten sonra cin nesnesini referans yoluyla geri dndrr. Geri dndrlen
cin nesnesi iin ikinci kez arlan operator>> ilevi bu kez d nesnesini referans yoluyla
argman olarak alr. d nesnesini klavyeden alnan deerle set ettikten sonra cin nesnesi
yine referans yoluyla geri dndrlr.
Myinta(10),b(20);
cin>>a>>b;
istream snfna dorudan ekleme yaplamaz ama global bir operator>> ilevi yazlabilir.
cin>>a
gibi bir ifadenin global bir ilev arsna dntrlmesi iin ilevin iki parametre
deikenine sahip olmas gerekir. levin birinci parametresi cin nesnesini referans yoluyla
alrken ikinci parametre Myint snf trnden a nesnesini yine referans yoluyla alabilir.
levin geri dn deeri istream snf trnden bir referans yaplrsa, yeniden cin
nesnesinin geri dndrlmesi salanabilir.
Aadaki ilev tanmn inceleyin.

152/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


istream&operator<<(ostream&is,Myint&r)
{
returnis>>r.m_val;
}
ilevimiz
operator>>(cin,a)
biiminde arldna gre, ilevin parametre deikeni olan referans is, cin nesnesinin
yerine geiyor. kinci parametre olan r referans da a nesnesinin yerine geiyor. levin
tanm iindeki
is>>r.m_val
ifadesi ile bu kez istream snfnn ye ilevi arlarak m_val isimli eleman klavyeden
alnan deerle set ediliyor. levimiz
is.operator>>(r.m_val)
arsnn geri dn deeriyle geri dnyor. Yani ilev cin nesnesini geri dndryor.

Numaralandrma Trleri in lelerin Yklenmesi


Bir ile, bir numaralandrma tr iin de yklenebilir. rnein tipik bir kullanm, ++ ve
- ilelerinin yklenmesiyle numaralandrma deerlerinin dolalmasn salamaktr.
Aadaki program inceleyin:
#include<iostream>
enumMonths{January,February,March,April,May,June,July,August,
September,October,November,December};
Months&operator++(Months&m)
{
if(m==December)
returnm=January;
inttemp=m;
returnm=Months(++temp);
}
std::ostream&operator<<(std::ostream&os,constMonths&r)
{
switch(r){
caseJanuary:returnos<<"January";
caseFebruary:returnos<<"February";
caseMarch:returnos<<"March";
caseApril:returnos<<"April";
caseMay:returnos<<"May";
caseJune:returnos<<"June";
caseJuly:returnos<<"July";
caseAugust:returnos<<"August";
caseSeptember:returnos<<"September";
caseOctober:returnos<<"October";
caseNovember:returnos<<"November";
caseDecember:returnos<<"December";
}
}

153/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


intmain()
{
Monthsm=January;
for(;;){
std::cout<<m<<std::endl;
++m;
if(m==January)
break;
}
return0;
}
le ykleyen ilevlerin kullanmna rnek vermek amacyla, aada Date isimli bir
snfn kodlarn veriyoruz. Date isimli snf trnden bir nesne bir tarih bilgisi tutmaktadr.
/////////////////////date.h/////////////////////////////
#include<iosfwd>
#include<stdexcept>
classDate{
intm_d,m_m,m_y;
intm_totaldays;
staticboolis_valid(int,int,int);
staticboolis_leap(inty){
returny%4==0&&100!=0||y%400==0;
}
staticintms_daytabs[][13];
staticintms_yeartabs[2];
staticconstchar*ms_days[];
staticconstchar*ms_mons[];
conststaticintmsc_yearbase=1700;
conststaticintmsc_factor=0;
voidset_totaldays();
voidset(int,int,int);
Date&revdate(inttotaldays);
public:
Date(int,int,int);
Date();
intget_year_day()const;
intget_week_day()const;
intget_mday()const{returnm_d;}
intget_mon()const{returnm_m;}
intget_year()const{returnm_y;}
Date&operator+=(intn);
Date&operator=(intn);
Date&operator++();
Dateoperator++(intn);//postfix
Date&operator();
Dateoperator(intn);//postfix
//friendfunctions
friendstd::ostream&operator<<(std::ostream&,constDate&);
friendstd::istream&operator>>(std::istream&,Date&);
friendbooloperator<(constDate&,constDate&);
friendintoperator(constDate&,constDate&);
};
classBadDate:publicstd::out_of_range{
public:

154/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


BadDate(constchar*pmsg):std::out_of_range(pmsg){}
};
//globalfunctions
booloperator>(constDate&,constDate&);
booloperator>=(constDate&,constDate&);
booloperator<=(constDate&,constDate&);
booloperator==(constDate&,constDate&);
booloperator!=(constDate&,constDate&);
Dateoperator+(constDate&,int);
Dateoperator+(int,constDate&);
Dateoperator(constDate&,int);
///////////////////////////////////////////////////////////////////////////
//date.cppfile
#include<iostream>
#include<iomanip>
#include<ctime>
usingnamespacestd;
intDate::ms_daytabs[2][13]={
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31},
};
intDate::ms_yeartabs[]={365,366};
constchar*Date::ms_mons[]={"","Ocak","Subat","Mart","Nisan",
"Mays",
"Haziran","Temmuz","Agustos","Eylul","Ekim","Kasim","Aralik"};
constchar*Date::ms_days[]={"Pazartesi","Sali","Carsamba","Persembe",
"Cuma","Cumartesi","Pazar"};
///////////////////////////////////////////////////////////////////////////
voidDate::set(intd,intm,inty)
{
if(!is_valid(d,m,y))
throwBadDate("gecersiztarih\n");
m_d=d;
m_m=m;
m_y=y;
set_totaldays();
}
///////////////////////////////////////////////////////////////////////////
voidDate::set_totaldays()
{
m_totaldays=0;
for(intk=msc_yearbase;k<m_y;++k)
m_totaldays+=ms_yeartabs[is_leap(k)];
m_totaldays+=get_year_day();
}
///////////////////////////////////////////////////////////////////////////
Date&Date::revdate(inttotaldays)
{
m_totaldays=totaldays;
m_y=msc_yearbase;

155/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

while(totaldays>ms_yeartabs[is_leap(m_y)])
totaldays=ms_yeartabs[is_leap(m_y++)];
m_m=1;

while(totaldays>ms_daytabs[is_leap(m_y)][m_m])
totaldays=ms_daytabs[is_leap(m_y)][m_m++];
m_d=totaldays;
return*this;
}
///////////////////////////////////////////////////////////////////////////
Date::Date(intd,intm,inty)
{
set(d,m,y);
}
///////////////////////////////////////////////////////////////////////////
Date::Date()
{
time_ttimer=time(0);
tm*tp=localtime(&timer);
set(tp>tm_mday,tp>tm_mon+1,tp>tm_year+1900);
}
///////////////////////////////////////////////////////////////////////////
intDate::get_year_day()const
{
intyearday=m_d;
for(intk=1;k<m_m;++k)
yearday+=ms_daytabs[is_leap(m_y)][k];
returnyearday;
}
///////////////////////////////////////////////////////////////////////////
intDate::get_week_day()const
{
return(m_totaldays+msc_factor)%7;
}
///////////////////////////////////////////////////////////////////////////
Date&Date::operator+=(intn)
{
returnrevdate(m_totaldays+n);
}
///////////////////////////////////////////////////////////////////////////
Date&Date::operator=(intn)
{
returnrevdate(m_totaldaysn);
}
///////////////////////////////////////////////////////////////////////////
Date&Date::operator++()
{
return*this+=1;
}
///////////////////////////////////////////////////////////////////////////
DateDate::operator++(int)
{
Dateretval(*this);
++*this;

156/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


returnretval;
}
///////////////////////////////////////////////////////////////////////////
Date&Date::operator()
{
return*this=1;
}
///////////////////////////////////////////////////////////////////////////
DateDate::operator(int)
{
Dateretval(*this);
*this;
returnretval;
}
///////////////////////////////////////////////////////////////////////////
boolDate::is_valid(intd,intm,inty)
{
if(y<msc_yearbase)
returnfalse;
if(m<1||m>12)
returnfalse;
returnm>0&&d<=ms_daytabs[is_leap(y)][m];
}
///////////////////////////////////////////////////////////////////////////
ostream&operator<<(ostream&os,constDate&r)
{
returnos<<setw(2)<<r.m_d<<""<<Date::ms_mons[r.m_m]<<""<<
r.m_y
<<""<<Date::ms_days[r.get_week_day()];
}
///////////////////////////////////////////////////////////////////////////
istream&operator>>(istream&is,Date&r)
{
intd,m,y;
is>>d>>m>>y;
r.set(d,m,y);

returnis;
}
///////////////////////////////////////////////////////////////////////////
booloperator<(constDate&d1,constDate&d2)
{
returnd1.m_totaldays<d2.m_totaldays;
}
///////////////////////////////////////////////////////////////////////////
booloperator>(constDate&d1,constDate&d2)
{
returnd2<d1;
}
///////////////////////////////////////////////////////////////////////////
booloperator>=(constDate&d1,constDate&d2)
{
return!(d1<d2);
}
///////////////////////////////////////////////////////////////////////////

157/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


booloperator<=(constDate&d1,constDate&d2)
{
return!(d2<d1);
}
///////////////////////////////////////////////////////////////////////////
intoperator(constDate&d1,constDate&d2)
{
returnd1.m_totaldaysd2.m_totaldays;
}
///////////////////////////////////////////////////////////////////////////
Dateoperator+(constDate&d,intn)
{
returnDate(d)+=n;
}
///////////////////////////////////////////////////////////////////////////
Dateoperator+(intn,constDate&d)
{
returnd+n;
}
///////////////////////////////////////////////////////////////////////////
Dateoperator(constDate&d,intn)
{
returnDate(d)=n;
}
///////////////////////////////////////////////////////////////////////////
intmain()
{
Datetoday;
Datenext_year_today(today+365);

while(today<=next_year_today)
cout<<today++<<endl;
return0;
}

158/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

SM ALANLARI
Global olarak bildirilmi olan varlklar iin seilmi isimlerin birbirinden farkl olmas
gerekir.
Global blgede programc tarafndan bildirilen trler, nesneler, ilevler, ablonlar, global
varlklardr. rnein bir ilevin ismiyle, global bir nesnenin ismi ayn olamaz. stelik bu
durum yalnzca tek bir kaynak dosya iin deil, projeyi oluturan dier kaynak dosyalar
iin de geerlidir. Ayn kaynak dosyada ayn ismin global dzeyde kullanlmas derleme
zamannda hataya neden olur. Ayn ismin global dzeyde farkl dosyalarda d balantya
ait olacak biimde kullanlmas, balama (linking) zamannda hataya neden olur.
Bu durumun programc iin uygulamadaki nemi udur: Projede baka ktphaneler ya
da modller kullanlyorsa, kullanlan modllerdeki global varlklarn isimleri, programcnn
yazmakta olduu kaynak dosyadaki global isimler ile ayn olmamaldr. Yani global
dzeydeki isimler akmamaldr.
sim akmasn engellemek her zaman kolay deildir. nk kullanlan modller ya da
ktphaneler farkl kiiler ya da firmalar tarafndan retilmi olabilir. zellikle byk
programlar sz konusu olduunda global isimlerin akma riski ok fazladr. Farkl
kiilerin gelitirdii ktphanelerin birletirilmesi durumunda isimlerin akmas nasl
engellenebilir? Global isimlere ynelik bu akma problemi "global isim alannn
kirlenmesi problemi" olarak (global namespace pollution) bilinir.
C++ dilinin standartlatrlma dnemi ncesinde, programclar global isim alannn
kirlenmesini, global varlklara ok uzun isimler vererek engellemeye alyorlard. Bu
isimler de ounlukla nceden belirlenen nek szcklerle oluturuluyordu. Bir rnek
verelim: Dinamik bir diziyi soyutlayan bir snfn tanmlandn dnelim. Snfn ismi
Array olarak seilirse isim akmas olasl artar. Kullanlan modller iinde bu isim bir
baka snfa verilmi olabilir. Olas bir isim akmasn engellemek iin snfa daha uzun
bir isim verilebilir:
classC_ve_Sistem_Programcilari_Array{
//
};
voiddisplay(constC_ve_Sistem_Programcilari_Array&);
Bunun iyi bir zm olduu sylenemez. C++ dilinde yazlm bir program, btn
program iinde grlebilen ok sayda snf, ilev ya da ablon ierebilir. Srekli uzun
isimler yazmak, hem programc iin zahmetli bir itir, hem de byle isimler programn
okunabilirliini azaltr.
sim alanlar (Namespaces) global isim alan kirlenmesi problemini byk lde zen,
C++ dilinin nemli bir aracdr.
Bilgisayarmzn hard diskinin sadece bir kk dizin ierdiini dnelim. Bu dizin iinde
ayn isimli iki dosya olamaz, deil mi? Kk dizin altnda eitli alt dizinler oluturabiliriz.
Bu alt dizinler iinde isimleri ayn olan dosyalar bulunabilir. rnein ismi necati.txt olan
bir dosya, hem kk dizinde hem de kk dizinin altndaki "notlar", "mektuplar", "odevler"
isimli dizinlerde bulunabilir.
Kaynak dosyann global dzeyi, yani global isim alan, yukardaki rnekteki kk dizine
benzetilebilir. Nasl kk dizin iinde iki dosyann ismi ayn olamyorsa kaynak dosyada da
global iki varln ismi ayn olamaz. te kk dizin iinde farkl isimli dizinler yaratlmas
gibi, kaynak dosyann global alannda farkl isim blgeleri yaratlabilir. Bu durumda bu
farkl blgeler iinde ayn isimler kullanlabilir.
Bir programda belirli isimleri, global alandan gizlemek iin isim alanlar tanmlanabilir:

159/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


namespaceCDernek{
classCDString{/*...*/};
voidpush_back(CDString&);
}
CDernek programc tarafndan bildirilen bir isim alandr. Programc tarafndan bildirilen
her isim alan, ayr bir bilinirlik alan belirler. Programc tarafndan bildirilen bir isim alan,
baka isim alan bildirimlerini, ilevlerin nesnelerin ablonlarn, trlerin, bildirimlerini ya
da tanmlarn ierebilir.
Global isim alannda olduu gibi , programc tarafndan bildirilen isim alanndaki her isim
de tek bir varla ilikin olmaldr. Yani bildirilen bir isim alannda ayn isim birden fazla
kez bulunamaz. Ama farkl isim alan bildirimleri farkl bilinirlik alanlar belirledii iin,
farkl isim alanlarnda ayn isimler kullanlabilir.
sim alannda kullanlan her isme "isim alan eleman" (namespace member) denir.

sim Alan Tanm


Bir isim alan tanm namespace anahtar szc ile balar. namespace anahtar
szcn isim alannn ismi izler. sim alan ismi isimlendirme kurallarna uygun olarak
seilmelidir. sim alan ismini izleyen blok iinde isim alan elemanlarnn bildirimleri
ve/veya tanmlamalar yer alr. sim alan tanm sonunda sonlandrc atom yer almaz:
namespaceCDernek{
classCDString{
//
};
//
}
sim alan ismi global dzeyde baka bir isimle akmamaldr. sim alan ismi de, tanmn
yapld isim alannda tek olmaldr. Yani global isim alan kirlenmesi sorunu tam olarak
ortadan kaldrlm olmaz. Ancak isim alanlarnn kullanlmasyla sorun en aza indirilir. Bir
bildirimin ya da bir tanmn, bir isim alan iinde yaplmas bildirimin ya da tanmn
anlamn deitirmez. sim alan iinde yaplm bir bildirimi ya da tanm dier bildirim ya
da tanmlardan ayran tek nokta, bildirilen ya da tanmlanan isimlerin isim alan iinde
gizlenmi olmasdr. Bu isimlere dardan ancak nitelendirilmi isimler olarak yani
znrlk ileciyle eriilebilir.
Bir isim alan tanm ya global dzeyde ya da baka bir isim alan tanmnn iinde
yaplmaldr. Yerel dzeyde, yani bir ilevin tanm iinde bir isim alan tanmlanamaz.

sim Alan Bir Bilinirlik Alandr


Programc tarafndan bildirilen her isim alan, yeni bir bilinirlik alan oluturur. Bir isim
alan iinde baka isim alan bildirimleri, ilev bildirimleri ve tanmlamalar tr bildirimleri
nesne bildirim ve tanmlamalar yer alabilir. Ayn bilinirlik alannda ayn isim birden fazla
kez kullanlamaz. sim alan da yeni bir bilinirlik alan oluturduuna gre bir isim alan
iinde de ayn isim bulunamaz. Farkl isim alanlar farkl bilinirlik alan belirttiklerine gre,
farkl isim alanlar iinde ayn isim kullanlabilir. rnein yukarda bildirilen CDernek isim
alanna ek olarak Project isimli bir isim alann daha tanmlanm olsun:

160/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


namespaceCDernek{
classCDString{
//
};
//
}
namespaceProject{
classCDString{
//
};
}
Her iki isim alannda da, tanmlanan snfn ismi CDString olarak seilmitir. Bilinirlik
alanlar farkl olduuna gre iki snfn isminin ayn olmas geerlidir.
C++'da C'de olmayan iki bilinirlik alan kuralnn daha yer aldn hatrlatalm. Bu bilinirlik
alanlarndan birincisinin snf bilinirlik alan olduunu daha nceki konularda deinilmiti.
sim alan bilinirlik alan da C dilinde olmayan C++ dilinin ekledii yeni bir bilinirlik
alandr.

znrlk leci ve Nitelenmi sim


Programc tarafndan bildirilen bir isim alannn elemanlarna, isim alan dnda erimek
iin iki terimli araek konumunda znrlk ileci kullanlr. Bu biimde yazlm isme
"nitelenmi isim" (qualified name) denir. Bir isim alan iinde bildirilmi isme, isim alan
dnda ancak nitelenmi isimle eriilebilir:
namespaceCdernek{
classCDString{
//
}
};
voidfoo(CDString&r);
voidfunc(Cdernek::CDString&r)

//Geersiz
//Geerli

Yukardaki rnekte, CDernek isim alan iinde tanmlanan String snf, CDernek isim alan
dnda nitelenmi isim olarak kullanlyor. Global dzeyde bildirilen func ilevinin
parametre deikeni
CDernek::CDString&
trndendir. Bir isim alan iinde bildirilen isim, sz konusu isim alan iinde gizlenir. Bu
ismi kullanmak iin derleyiciye, sz konusu ismi hangi isim alannda aramas gerektii
bildirilmelidir. Derleyiciye bu bilgi verilmez ise, derleyici bu ismi nce bulunulan bilinirlik
alan iinde arar. Orada bulamazsa aramay bilinirlik alann kapsayan dier bilinirlik
alanlarnda srdrr. Yukardaki rnei deitirelim:
classCDString{
//
};
namespaceCDernek{
classCDString{
//
};
}

161/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidfoo(CDString&);
voidfunc(CDernek::CDString&)

Yukarda bildirilen foo ilevinin paramesi, global isim alannda bildirilen CDString snf
trnden iken, func ilevinin parametresi CDernek isim alannda bildirilen CDString
trndendir.
sim alannda bildirilen bir ismin, nitelenmeden dorudan kullanlmasn salayan aralar
da vardr. Bu aralar "using bildirimi", "using namespace komutu" ve "argumana bal
isim arama"dr. Bu aralardan birinin kullanmyla, isim alannn bir elemanna znrlk
ileci olmakszn dorudan eriilebilir.

Global sim Alan


Tm bloklarn dnda kalan blge C++da "global isim alan" (global namespace) olarak
isimlendirilir. Global isim alannda bildirilen isimler dier dorudan kullanlabilir. Aslnda
znrlk ilecinin tek terimli biimi, global isim alanndaki bir isme erimeyi salar.
Normal olarak global isim alanndaki bir isme dorudan eriilebilecei iin, bu ileci
kullanmak zorunlu deildir. Ancak baz durumlarda global isim alanndaki isim, i bilinirlik
alanlarndaki bir isim tarafndan maskelenir. Bu durumda global isim alanndaki isme
eriebilmek iin, tek terimli znrlk ilecini kullanmak zorunludur. Aadaki rnei
inceleyin:
#include<iostream>
constintmax=1000;

//globalisimalanndakimax

namespaceCDernek{
constintmax=500;
};

//Cdernekisimalanndakimax

intmain()
{
intmax=100;
//blokbilinirlikalanndakimax

std::cout<<max<<std::endl
//blokbilinirlikalanndakimax
std::cout<<::max<<std::endl;
//globalisimalanndakimax
std::cout<<Cdernek::max<<std::endl;//Cdernekisimalanndakimax
return0;
}

sim Alanlar Eklemeli Bir Yapya Sahiptir


Daha nce bildirilen bir isim alanna, ayn kaynak dosya iinde ya da baka bir kaynak
dosya iinde ekleme yaplabilir. Yani isim alan elemanlar, isim alan iinde bir defada
bildirilmek zorunda deildir. Aadaki rnei inceleyin:

162/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


namespaceCDernek{
classCDString{
//
};
}
namespaceCDernek{
classCDVector{
//
};
}
Ayn dosya iinde yaplan yukardaki tanmlamalar geerlidir. Derleyici bir isim alan tanm
grnce, nce namespace anahtar szcn izleyen ismin, daha nceden tanmlanm
olan bir alana ilikin olup olmadn aratrr. Eer bu isimli bir isim alan daha nce
tanmlanmsa, ikinci bildirimdeki isimleri otomatik olarak ilk isim alan tanmyla
birletirir. Yani daha nceden tanmlanm olan bir isim alanna, kaynak kod iinde baka
bir noktada ekleme yaplabilir. Yukardaki rnekte hem CDString snf hem de CDVector
snf CDernek isim alanndadr. Hata oluturan bir durum sz konusu deildir.
sim alanlarnn eklemeli bir yapya sahip olmas zellikle ktphane olutururken
programcnn iine yarar. Bir modle ilikin bildirimler, yani modln ara yz bir balk
dosyas iinde tanmlanan bir isim alan iinde yer alrken, modln kodlamas
(implementasyonu) baka bir kaynak dosyada, yine ayn isim alanna eklenebilir:
//cdstring.hdosyas
namespaceCDernek{
classCDString{
//
public:
Stringoperator+(constCDString&);
//
};
}
//cdstring.cppdosyas
#include<string.h>
namespaceCDernek{
CDStringCDString::operator+(constCDString&)
{
}
}
sim alanlarnn eklemeli bir yapya sahip olmas zelliinden faydalanlarak, bir isim alan
iinde sunulan bir ktphanenin arayz birden fazla balk dosyasna blnebilir. Buna
en iyi rnek std isim alandr.

std sim Alan


C++n standart ktphanesinin btn bileenlerinin bildirimleri ve tanmlamalar std ismi
verilen bir isim alan iinde yaplmtr. iostream, vector, string gibi standart balk
dosyalarnn herhangi birinde bildirilen snflar, ilevler, nesneler, ablonlar std isim alan
iinde bildirilmitir.
Standart ktphane iinde bildirilen bir ileve ya da snfa erimek iin, normal olarak
snfn ya da ilevin ismi, yer ald isim alannn ismiyle nitelenmelidir:

163/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


std::cout
std::string
std::cin
Bu isimleri nitelemeden kullanabilmek iin using bildirimi ya da using namespace komutu
kullanlaca gibi argumana bal arama da (Koenig lookup) yaplabilir. std isim alan
bildirimleri iinde deiiklik yapmak, yani bu isim alanna eklemeler yapmak ya da bu isim
alanndan baz bildirimleri silmek tanmsz davrantr.

sel sim Alanlar


Bir isim alan iinde baka bir isim alan bildirilebilir. Bylelikle isel (nested) isim alanlar
oluturulabilir. sel isim alanlar ktphanedeki kodlarn dzenlenmesini iyiletirmek iin
kullanlabilir.
namespaceCCernek{
namespaceCStringLib{
//...
}
namespaceCMathLib{
//...
}
}
sel bir isim alanndaki elemanlarn isimleri, o isim alan iinde gizlenir. sel isim
alanndaki isimlere
kapsayanisimalanismi::iselisimalanismi::isimalanelemanismi
biiminde eriilir.
sel bir isim alan, baka bir isim alannda yer alan yeni bir bilinirlik alan yaratr.
Derleyicinin isimleri zmlemesi srasnda, isel isim alanlar isel bloklar gibi ele alnr.
sel isim alannda bir isme rastlandnda, bu ismin bildirimi, nce isel isim alannda,
daha sonra srasyla iten da doru kapsayan isim alanlarnda aranr. sim kapsayan isim
alanlarnda da bildirilmemise son olarak isim global isim alannda aranr.

sim Alan Elemanlarnn Tanmlamalar


Bir isim alan elemannn tanmnn yine ayn isim alan iinde yaplabilir.
Tanm isim alan dnda da yaplabilir. Bu durumda tanmlanacak isim alan eleman,
tanmlama srasnda nitelenmi ismiyle kullanlmaldr:
namespaceCDernek{
namespaceCDStringLib{
classCDString{
intsize;
public:
intget_size()const{returnsize;}
};
CDStringoperator+(constCDString&,constCDString&);
}
}
Yukardaki rnekte CDernek isimli isim alan iinde CDStringLib isimli baka bir isel isim
alan tanmlanyor. CDStringLib isim alan iinde tanmlanan CDString isimli snfn
get_size isimli ye ilevi yine ayn isim alan iinde tanmlanyor. CDString snfnn iinde
operator+ ilevi bildiriliyor. Ancak bu ilevin tanm CDStringLib isimli isim alan iinde
yaplmyor. Bu ilevin global isim alannda aadaki biimde tanmlandn dnelim:

164/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Cdernek::CDStringLib::CDString
Cdernek::CDStringLib::operator+(constCDString&r1,constCDString&r2)
{
CDStringresult;

//...
returnresult;
}
levin geri dn deerinin trnn yazld yer, Cdernek::CDStringLib isim alan ile
belirlenen bilinirlik alan dndadr. Bu yzden ilevin geri dn deerinin tr
nitelendirilmi isim olarak yazlmaldr. Bu yzden global isim alannda bu tr
Cdernek::CDStringLib::CDString
biiminde yazlr. levin tanmnda ilevin ismi de nitelenmi isim olarak yazlr:
Cdernek::StringLib::operator+
Ancak ilevin parametre ayrac ii ile ilevin ana blou Cdernek::StringLib isim alannn
bilinirlik alanndadr. Bu yzden ilevin parametre deikenleri olan r1 ve r2 ile ilev
iindeki yerel result deikeninin tr bilgileri dorudan
CDString
olarak yazlabilir. Zira isim alan elemanlar, isim alan bilinirlik alan iinde nitelenmemi
isimleriyle dorudan kullanlabilir.
Bir isim alan elemann tanm, isim alan dnda her yerde yaplamaz. Tanm isim alannn
dnda yaplacaksa, ancak bildirimin yapld isim alann kapsayan isim alanlarndan
birinde yaplabilir. Yukardaki rnekte operator+ ilevinin tanm ya Cdernek isim alan
iinde ya da global isim alan iinde yaplmaldr. levin tanm CDernek isim alan iinde
aadaki biimde yaplabilirdi:
namespaceCdernek{
//...
namespaceCDStringLib{
classCDString{
intsize;
//...
public:
intget_size()const{returnsize;}
//...
};
CDStringoperator+(constCDString&,constCDString&);
}
CDStringLib::CDString
CDStringLib::operator+(constCDString&r1,constCDString&r2)
{
//...
}
}
Bu kez ilevin tanm CDStringLib isim alannn dnda yaplmasna karn, Cdernek isim
alan iinde yaplyor. levin geri dn deerinin trnn ve ilev isminin
String_Lib::String
String_Lib::operator+

165/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


biiminde yazldna dikkat edin.

using Bildirimi
Bir isim alan elemanna ulamak iin her defasnda bu elemann ismini nitelenmi ismi
yazmak programc asndan ok zahmetlidir. using bildirimiyle isim alan elemanna
nitelenmemi ismi ile dorudan eriilebilir.
using bir anahtar szcktr. Bu anahtar szc isim alan elemannn nitelendirilmi ismi
izler. Bildirim sonlandrc atomla sonlanr.
usingCDernek::CDString;
Yukardaki bildirimden sonra, CDernek isim alan iinde tanmlanan CDString snf
CDernek::CDString
biiminin yansra, dorudan
CDString
biiminde kullanlabilir. Yani using bildiriminden sonra CDString ismi kullanldnda
derleyici bu ismi
CDernek::CDString
olarak ele alr.
using bildirimi ile bildirilen isim, bildirimin yapld bilinirlik alanna eklenir.
using bildirimi de dier bildirimlerin ortak zelliklerini tar. Bu bildirimin de bir bilinirlik
alan vardr. using bildirimi yerel olarak yaplabilecei gibi, global isim alan iinde ya da
baka bir isim alan iinde de yaplabilir. Dier tm bildirimlerde olduu gibi using
bildirimiyle bilinirlik alanna eklenen isim
1. Eklendii bilinirlik alannda tek olmaldr.
2. Daha geni bilinirlik alanndaki ayn ismi maskeler.
3. Daha dar bilinirlik alanndaki ayn isim tarafndan maskelenir.
Aadaki rnei dikkatle inceleyin:

166/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


namespaceMynamespace{
inta=1,b=2,c=3;
//digerbildirimler
}
intb=0;
intmain()
{
usingMynamespace::a;
a=10;
usingMynamespace::b;
b=20;
intc;
//usingMynamespace::c;
}

//Geersiz!

voidfunc()
{
inty=a;
}
main ilevi iinde yaplan
usingMynamespace::b
bildiriminden sonra yaplan
b=10
atamasyla eriilen b, Mynamespace isim alan iinde tanmlanan b olur. Yani main
ilevinin blok bilinirlik alanna, using bildirimiyle eklenen b ismi, global deiken olan b
deikenini maskeler. main ilevi iinde c isimli bir yerel deikenin tanmlanmasndan
sonra yaplan
usingMynamespace::c
bildiriminin hata oluturduunu gryorsunuz. Ayn bilinirlik alannda ayn ismin
kullanlamayacan hatrlayn. using bildiriminden nce, blok bilinirlik alannda zaten c
isimli bir yerel deiken vardr. Bu durumda bilinirlik alanna ikinci bir c isminin sokulmaya
allmas geersizdir. Son olarak main ilevinden sonra tanmlanan func ilevine bir gz
atalm. lev iinde tanmlanan bir yerel deiken olan y isimli deikene a deikeninin
deeri atanm. Ancak a isimli bir nesne bu noktada grnr deil. using bildiriminin de
bir bilinirlik alan olduunu hatrlayalm.
usingMynamespace::a;
bildirimi yerel dzeyde, yani main ilevinin iinde yapldndan yalnzca main ilevi iinde
nitelenmeden kullanlabilir. func ilevinin ana blou iinde a ismi nitelenmi isim olarak
yani Mynamespace::a biiminde kullanlmaldr.
Ancak using bildirimi yerel dzeyde deil de global dzeyde yaplsayd, bu eriim de
geerli olurdu. Aadaki kodu inceleyin:

167/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


namespaceMynamespace{
inta=1,b=2,mk=c;
//di?erbildirimler
}
usingMynamespace::mi;
intmain()
{
a=10;
return0;
}
voidfunc()
{
inty=a;
}
using bildirimi ile, isim alan elemannn kullanlmas daha kolay hale gelir. using bildirimi
ile, bir defada yalnzca isim alannn bir eleman ilgili bilinirlik alanna katlabilir. using
namespace komutuyla bir defada birden fazla ismin nitelenmeden kullanlmas
salanabilir.

using namespace Komutu


Bir isim alan iinde tantlan isimlerin her birine nitelenmemi isimle eriebilmek
amacyla, her isim iin ayr bir using bildirimi yaplabilir. Ancak ok sayda isim iin using
bildiriminin teker teker yaplmas zaman alcdr. Byle bildirimler programn
okunabilirliini de bozar. Bir isim alanndaki isimlerin hepsinin tek bir komutla
nitelenmemi isim olarak kullanlabilmeleri mmkn klnmtr.
Bir using namespace komutu, using ve namespace anahtar szckleriyle balar. Bu
szckleri daha nce tanmlanm bir isim alannn ismi izler:
usingnamespaceCDernek;
usingnamespacestd;
Daha nce tanmlanm bir isim alanna ilikin olmayan bir ismin kullanlmas geersizdir.
using namespace komutuna konu isim alanndaki tm isimler, nitelenmemi isimler olarak
kullanlabilir hale gelir.
using namespace komutu, isim alan elamanlarnn, sanki bu elemanlar isim alannn
tanmnn bulunduu yerde, ancak isim alannn dnda tanmlanm gibi grlmesini
salar. Aadaki rnei inceleyin:
namespaceMynamespace{
inta=1,b=2,c=3;
//digerbildirimler
}
voidfunc();
intb=0;

intmain()
{
usingnamespaceMynamespace;
a=10;

168/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


//b=20;
//Geersiz
Mynamespace::b=100;
::b=178;
intc;
c=30;
//yerelc

return0;
}
voidfunc()
{
//inty=a;
}
main ilevinin ana blounun banda using namespace komutu yer alyor. Komutun
grlr olduu kaynak kod aralnda, Mynamespace isim alan iindeki tm isimler adeta
isim alannn dnda, yani global blgede tanmlanm gibi grlebilir duruma gelir.
a=20;
atamas geerlidir. Bu atamayla Mynamespace isim alan iinde tanmlanan a deikenine
deer atanr.
b=20;
atamas derleme zamannda ift anlamllk hatas oluturur. Zira bu noktada hem global b
deikeni hem de using namespace komutunun etkisiyle, Mynamespace isim alan
iindeki b deikeni grlr durumdadr. Hata, yalnzca b nesnesinin nitelenmemi isim
olarak kullanlmas durumunda oluur. main ilevinin ana blou iinde b nesnesi hi
kullanlmaz ise ya da b nesnesi nitelenmile kullanlrsa, ift anlamllk hatas olumaz:
//...
Mynamespace::b=100;
::b=178;
main ilevi iinde c deikeninin tanmlanmas geerlidir. Zira isim alannn iinde
tanmlanan c ile, main blou iinde tanmlanan c deikenlerinin bilinirlik alanlar farkldr.
c=30
atamas yerel c deikenine yaplm olur.
using namespace komutunun da bir bilinirlik alan vardr. Yukardaki rnekte komut main
ilevi iinde verildiinden komutun bilinirlik alan yalnzca main ilevini kapsar. main
ilevini izleyen foo ilevi iinde, a isminin nitelenmeden kullanlmas geersizdir.
using namespace komutunun kullanm son derece kolaydr. Tek bir komutun
kullanlmasyla, isim alan iindeki tm isimler dorudan kullanlabilir hale gelir. Bu kolay
bir zm gibi grnse de, gereksiz ya da ar kullanm da baka sorunlara yol aabilir.
Birden fazla ktphane kullanlyorsa ktphanelerdeki isimleri ksa biimleriyle
kullanmak iin her bir isim alan iin using namespace komutu kullanldnda, global isim
kirlenmesi sorunu yine ortaya kar.

169/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


//header1.h
namespaceHDR1{
voidfoo();
//...
}
//header2.h
namespaceHDR2{
voidfoo();
//...
}
//app.cpp
#include"header1.h"
#include"header2.h"
usingnamespaceHDR1;
usingnamespaceHDR2;
intmain()
{
foo(); //iftanlamllkhatas
//...
}

Bir Ktphanenin sim Alan ine Alnmas


sim alanlar C++ dilinin standartlatrlmas srecinde dile katlan son aralardan biridir.
Standartlar ncesi gelitirilen derleyiciler isim alanlarn desteklemedikleri iin eskiden
yazlm bir ok ktphane bir isim alan iinde bildirilmemitir. sim alan iine alnmam
ktphanelerin kullanm isim akmas riskini artrr.
Bir isim alan iinde yaplmam bildirimlerin, daha sonradan bir isim alan iine alnmak
istendiini dnelim. rnein daha nce yazlan cdate.h isimli balk dosyasndaki
bildirimlerin CDernek isim alanna katlmak istendiini dnelim:
//cdate.h
namespaceCDernek{
classCDate{
//...
};
//di?erbildirimler
}
Ancak bu durumda CDate snfn kullanan kodlarn bulunduu, rnein app1.cpp isimli bir
dosyada cdate.h isimli balk dosyas yeni biimiyle kaynak dosyaya include nilemci
komutuyla eklendiinde artk cdate.h iinde bildirilen isimler dorudan kullanlamaz.
cdate.h iinde yaplan her bildirim artk CDernek isim alan eleman durumuna geldiine
gre, bu elemanlar ancak nitelenmi isimleriyle kullanlabilir. app1.cpp dosyasnda fazlaca
bir deiiklik yapmamak iin bu dosyann bana bir using namespace komutu
yerletirilebilir:
//app.cpp
#include"cdate.h"
usingnamespaceCDernek;
//...

sim Alan Eismi


170/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


sim alan isimleri de global blgede tek olmak zorundadr. Bu yzden isim alan isimleri
genellikle uzun seilir. Nitelenmi isim kullanlrken, isim alan elemann niteleyen ismin
srekli olarak yazlmas istenmeyebilir. Daha ksa isimler kullanabilmek iin, isim alan
ismi yerine kullanlabilecek baka -daha ksa-isimler yaratlabilir. Bu isimalan eismi
bildirimi ile salanr.
sim alan eismi bildirimi (namespace alias) namespace anahtar szc ile balar.
Anahtar szc, isim alan isminin yerine geecek szck izler. Daha sonra atama ileci
yer alr. Atama ilecinin sa tarafna daha nce tanmlanan bir isim alannn ismi yazlr.
Bildirimi her zaman olduu gibi sonlandrc atom tamamlar.
namespaceCSD=C_ve_Sistem_Programcilari_Dernegi;
Bu bildirimden sonra artk C_ve_Sistem_Programcilari_Dernegi isim alan isminin
kullanlabileei yerlerde CSD ismi kullanlabilir.
Bir isim alan eismi, isel bir isim alan iin de kullanlabilir:
namespaceCSDSTR=C_ve_Sistem_Programclar_Dernegi::CDStringLib;
Biri isim alannn birden fazla eismi olabilir.
sim alan eismi, projelerde srm denetiminde de kullanlr. Baarl yazlm projelerinin
mr rn piyasaya verildikten sonra da srer. Baz rnlerin srekli yeni srmleri
retilir. Bir programn yeni ve eski srmleri sz konusu olduunda, iki srmn de ortak
olarak kulland kod bileenleri vardr. Ancak baz kod bileenleri ise her srm iin
farkldr. sim alan eisimleri farkl srmler iin dinamik isim alanlarnn yaratlmasnda
kullanlabilir:
namespaceVer_1_0{
classFile{
//
};
classUsb{
//
};
}
namespaceVer_2_0{
classFile{
//
};
classUsb{
//
};
}
intmain()
{
namespacecurrent=Ver_2_0;
usingcurrent::File;
usingcurrent::Usb;
Filef;
Usbu;
//
return0;
}

171/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Yukardaki kodu inceleyelim: Ayr srmlerde kullanlmak zere Ver_1_0 ve Ver_2_0
isimli iki ayr isim alan tanmlanyor. main ilevi iinde yaplan isim alan eismi
bildirimiyle, current isminin Ver_2_0 isim alannn yerine gemesi salanyor. Daha sonra
yaplan using bildirimleriyle current isim alannn File ve Usb snf isimlerinin nitelenmeden
kullanlmas salanyor. main ilevi iinde yer alan
namespacecurrent=Ver_1_0;
bildiriminin
namespacecurrent=Ver_2_0;
bildirimi ile deitirilmesiyle, farkl File ve Usb snflarnn kullanlmas salanabilir.

simsiz sim Alan


Her kaynak dosya iinde, isimsiz bir isim alannn bulunduu varsaylr. Bu isim alanna
programc isterse ekleme yapabilir:
namespace{
voidfunc();
intg;
classA{
//
};
//
}
Bu isim alanndaki isimlere nitelenmemi isimlerle, kendi tanmlandklar kaynak dosya
iinde dorudan eriilebilir. Yukardaki rnekte isim alan bildiriminin grlebildii bir
kaynak kod noktasnda
intmain()
{
Aa;
//..
return0;
}
Yukardaki main ilevi iinde A ismi nitelenmeden (unqualified) kullanlyor. A snf isimsiz
isim alan iinde tanmlanmtr. simsiz isim alannn her kaynak dosya iin tek olaca
gvence altna alnmtr. Yani byle bir isim alan iinde bildirilen isimler dorudan i
balantya (internal linkage) sahiptir.
simsiz isim alan ne ie yarar? C dilinde global varlklarn i balantya sahip olmas iin
static anahtar szcyle bildirilmeleri gerektiini hatrlayn. Oysa C++ da i balantya
sahip yani yalnzca kendi modlnde bilinen global varlklar iin, static anahtar
szcnn kullanlmas eskimi (deprecated) olarak kabul edilmitir. nerilen ara,
isimsiz isim alan oluturulmas ve i balantya sahip global varlklarn bu isim alan
iinde bildirilmesidir.
Global dzeyde, static anahtar szc ile ilevler ve deikenler iin kullanlabilir. Ancak
isimsiz isim alan iinde programc tarafndan yaratlan trlerin de tanm yaplabilir.

Koenig sim Aramas


Bir ilev arsyla karlaan derleyici, hangi ilevin arldn anlamak iin ilev
arsnn yapld noktada grlebilir ilevleri aratrr.

172/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


intmain()
{
func(object)
}
Yukardaki kod iinde bir using bildirimi ya da using namespace komutu kullanlmadna
gre, normal olarak func ilevinin bir isim alan iinde aranmamas gerekir. Standartlarla
dile eklenen Koenig isim aramas (Andrew Koenig isminden) bu kural deitirir. leve
gnderilen arguman olan object eer bir isim alan iinde bildirilen snfa ilikin bir nesne
ise, bu snfn bildirimini kapsayan isim alan iinde de func isimli uygun bir ilevin varl
aratrlr. Bu kurala Koenig isim aramas ya da argumana bal isim arama denir.
Aadaki kodu derleyerek altrn:
#include<iostream>
usingnamespacestd;
namespaceNMSPC{
classA{
//...
};
voidfoo(Aa)
{
cout<<"NMSPC::foo(A)"<<endl;
}
}
intmain()
{
NMSPC::Aden;
foo(den);
return0;
}
Koenig isim aramas otomatik olarak uygulanr. Yani Koenig isim aramasn etkin klmak
iin bir bildirim ya da komut kullanlmak gerekmez. Bu zellii devre d brakmak da
mmkn deildir. Koenig isim aramasnn yaplmas, baz durumlarda ift anlamllk
hatasnn olumasna da yol aabilir:
namespaceNMSPC{
classA{
//...
};
voidfoo(A);
}
voidfoo(NMSPC::A);
intmain()
{
NMSPC::Aa;
foo(a);
//iftanlamllkhatas

return0;
}

173/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Yukardaki kod parasnda main ilevi iinde arlan foo ilevi, hangi ilevdir? NMSPC
isim alan iinde bildirilen mi, global isim alan iinde bildirilen mi? Koenig isim aramas
sz konusu olmasayd, phesiz arlan ilev global isim alannda bildirilen foo ilevi
olurdu. Ancak Koenig isim aramas NMSPC isim alan iindeki foo ilevini de grlebilir
kld iin, derleme zamannda ift anlamllk hatas oluur.

sim Alanlarnda Yaplan Arkadalk Bildirimleri


Arkadalk bildirimi ayn zamanda arkadalk verilen ilev iin bir prototip bildirimidir. Bir
isim alan iinde bir ileve arkadalk verildii zaman arkadalk bildirimi isim alan iinde
yaplrsa, ilev de isim alannda bildirilmi olur. Bylece arkadalk verilen ilev de isim
alannn bir eleman olur.
namespaceCDernek{
classSample{
intx;
friendvoidfoo();
};
//...
}
voidfoo()
{
CDernek::Samplesam;
sam.x=10;//Geersiz
}
Yukarda Cdernek isim alan iinde tanmlanan Sample isimli snf iinde yaplan
friendvoidfoo();
bildirimi ayn zamanda bu ilevin bildirimi olduundan arkadalk verilen ilev
voidCdernek::foo()
ilevidir. Eer Cdernek isim alan iinde global isim alannda bildirilmi bir ileve
arkadalk verilmek istenseydi arkadalk bildirimi
friendvoid::foo();
biiminde yaplmal ve isim alan tanmndan nce global foo ilevinin bildirimi
yaplmalyd.
Global isim alannda tanmlanan foo isimli ilev iinde Sample snfnn private elemanna
eriilmeye alldn gryorsunuz. CDernek::Sample snf arkadal global func
ilevine vermemitir. Bu nedenle
sam.x
eriimi geerli deildir.

sim Alanlar Ne Zaman Kullanlmal


sim akmas olaslnn byk projeler sz konusu olduunda daha da artaca aktr.
Yzlerce kaynak dosyann olduu bir projede hem isim akmas riski hem de isim
akmasnn neden olaca ek maliyet yksektir. Byk projelerde isim alanlarnn
kullanlmas kanlmazdr. Ancak tek bir programcnn gelitirdii ok fazla dosyaya sahip
olmayan projelerde isim alanlarnn kullanlmas fazla bir getiri salamaz. Ne de olsa isim

174/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


akmas olmas durumunda programc kolayca baz isimleri deitirerek akma
durumunu ortadan kaldrabilir.

sim Alanlarnn Maliyeti


sim alan kullanm programn alma zaman sz konusu olduunda, alan programn
hz ya da kulland bellek asndan ek bir yk getirmez. sim alanlarna ilikin kontroller
programn derleme zamannda yaplr.

175/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

TRETME
Tretme (inheritance) nesne ynelimli programlama tekniinin en nemli aralarndandr.
Tretme yoluyla nceden tanmlanm olan bir snfn zerinde deiiklik yapmadan,snfn
ilevleri geniletilebilir. nceden tanmlanm olan snflar tretme ilemi ile
gereksinimlere gre biimlendirebilir. Tretme yoluyla bir snf baka bir snfn var olan
zelliklerini alarak, o snf trnden bir nesneymi gibi kullanlabilir. Tretme, nesne
ynelimli programlamann olmazsa olmaz aralarndandr.
D dnyadaki nesneler arasnda baz ilikiler kurmamz, o nesneleri soyutlayarak
alglamamz kolaylatrr. Bu ilikilerden birincisi ngilizcede "has a" ilikisi diye bilinen
ilikidir. Bir nesne baka bir nesneye sahiptir. "Bilgisayarn monitr var", "Arabann 4
tekerlei var" gibi cmlelerde, bilgisayarn ya da arabann nelere sahip olduunu grmek,
nesneleri temel bileenlerine ayrmak, bu nesneleri daha iyi soyutlamamza yardmc olur.
phesiz araba ya da bilgisayar belki yzlerce farkl paraya sahiptir. Ancak zaten
soyutlama(abstraction), baz ayrntlar grmezden gelip temel nitelikler stnde
odaklanarak, genel kavrama derecesini artrmaya dayanr.
Soyutlamada ve alglamada kullandmz ikinci teknik ise ingilizcede "is a" ilikisi diye
bilinir. "Aslan bir hayvandr." Burada verilen ana bilgi udur. "Her aslan bir hayvandr."
Her aslan hayvanlarn genel zelliklerini tar. Ancak aslan hayvanlarn genel zellikleri
dnda baz baka zelliklere de sahiptir. Aslan yrtc bir hayvandr. Aslan etobur bir
hayvandr. Aslan hayvan kavramnn daha zelletirilmi bir yesidir. phesiz bunun tersi
doru deildir. Yani her hayvan aslanlarn genel zelliklerini tamaz. Her hayvan yrtc
deildir. Her hayvan etobur deildir. Ancak znesi hayvan olan bir cmle iinde zneyi
deitirip aslan yaparsak, cmle yanl olmaz. rnein, "Hayvanlar su ier." cmlesi
doru olduu gibi "Aslanlar su ier." cmlesi de dorudur.
"is a" ilikisi bir ana tr-yan tr ilikisidir. Bu iliki alglamay glendirmek iin
kademelendirilebilir. Bylece bir tr aac oluturulabilir. Baz hayvanlar et yiyerek
beslenir. Bu hayvalara etobur hayvanlar diyelim. Her etobur hayvan bir hayvandr. Aslan
etobur bir hayvandr. Baz etobur hayvanlarn nesli tkenmektedir. Baz etobur hayvanlar
evcilletirilebilir. Kedi evcilletirilebilen bir etobur hayvandr.
Nesne ynelimli programlama, d dnyann daha iyi modellenmesine ve programn
problem dzleminde soyutlanarak gerekletirilmesine dayanr. Gerek dnyay nesnelere
ve bu nesnelerin ilikileri yoluyla soyutluyorsak, program yazarken de soyutlamay bu
biimde yapmamz iimizi kolaylatrr.
C++ dilinde "has a" ilikisi bileik nesne oluturma yoluyla (composition) salanr.
"Bileik nesneler" isimli blmde bu konuyu incelemitik. "is a" ilikisinin kurulmasna
yardmc olan ara ise tretmedir.
Bir snfn kendisini deitirmeden ilevleri geniletilmek istenirse, yani o snfa eitli ye
ilevler ve elemanlar eklenmek istenirse bu farkl biimlerde yaplabilir. rnein eski
snfn farkl bir isimde yeni bir kopyas oluturulabilir, eklemeler yeni snf zerinde
yaplabilir. rnein, A isimli bir snfn B isimli bir kopyas oluturulup btn eklemeler B
snf zerinde yaplabilir. Bylece hem A snf bozulmam olur hem de geniletilmi bir B
snf elde edilir. Ancak bu yntemin nemli bir dezavantaj vardr. Bu yntemde A snfnn
btn ye ilevlerin B snf iin yeniden yazlmas gerekir. Yani bu yntem ayn ilevlerin
farkl snf isimleriyle yeniden tanmlanmasn gerektireceinden kodun bymesine yol
aar. kinci nemli bir dezavantaj da snfn kodlarnda deiiklik yaplmas durumunda
olur. A snfnda bir deiiklik yaplmas durumunda bu deiiklik yeni oluturulan B
snfna yansmaz. Belki de en nemlisi, byle bir deiikliin yaplabilmesi iin snfn
kaynak kodlarna gereksinim duyulmasdr. Elde snfn kodlama dosyas deil de yalnzca
snfn arayz yani balk dosyas varsa byle bir deiiklik yapmak mmkn olmaz.

176/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Bir baka yntem olarak, bileik nesne oluturma yolu seilebilir. rnein nce aadaki
gibi bir A snf tanmlanr:
classA{
//Varolanilevlerveelemanlar
};
Sonra B snf iinde A snfn bir eleman olarak kullanlr:
classB{
private:
Aa;
public:
//Yenieklenenilevlerveelemanlar
};
Artk B snf trnden tanmlanm olan b nesnesi ile hem A snfnn hem de B snfnn
ye ilevleri arlabilir. nk b.a ifadesi ile A snfna eriilerek bu ifadeyle A snfnn
ye ilevleri arlabilir. Bu tasarm biimi ilev yinelemesine yol amamakla birlikte
eriim bakmndan sorunludur.
Nesne ynelimli programlama tekniinde arlkl kullanlan ara tretmedir. C++ dilinde
nceki snf bozmadan ilev geniletmek amacyla "tretme" arac kullanlmaktadr.
Tretme burada aklanan iki yntemden ok daha etkin ve geni bir aratr.

Tretme leminin Genel Biimi


Bir snf baka bir snftan tretilir. Kendisinden tretme yaplan snfa taban snf (base
class), tretilmi olan snfa da tremi snf (derived class) denir.
Tretme ileminin genel biimi yledir:
<class>
<struct>

<tremisnfismi:>

[tretmebiimi]
<public>
<protected>
<private>

<tabansnfismi>

{
snfelemanlarnnbildirimi
};
class ya da struct anahtar szcnden sonra tremi snf isminin belirtildiine, daha
sonra ":" atomu ile tretme biimi ve taban snf isminin yazldna dikkat edin. Genel
biimden de anlalaca gibi, tretme biimi hi belirtilmeyebilir. Bu durumda snflar iin
private, yaplar iin public tretmesinin yapld kabul edilir. Yani tretme biimi olarak
bir ey yazlmamsa snflar iin private, yaplar iin public yazlm gibi ilem grr.
Aada, rnek bir tretme ileminin szdizimini gryorsunuz.
classA{
//
};
classB:publicA{
//
};
Burada B tremi snf A ise taban snftr. Tretme biimi olarak public tretmesi
seilmitir. Aklamay ve anlatm kolaylatrmak amacyla snflarn tretilmesi ekilsel

177/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


olarak da gsterilebilir. Byle bir ekilde snflar daire, elips ya da dikdrtgenlerle
gsterilir. Taban snf tremi snfn daha yukarsnda gsterilir ve tremi snftan taban
snfa bir ok izilir. Okun yanna istee bal olarak tretme biimi yazlabilir. rnein B
snf A snfndan tretilmise, bu durumu ekilsel olarak aadaki gibi gsterilebilir:

EMBED Visio.Drawing.11
Yukardaki ekil yanl izilmedi. izilen okun yn pek ok kiiye olduu gibi size de ters
gelmi olabilir. Okun yn yukardaki gibi taban snf gsterecek biimde olmaldr.
Bundan sonra yalnzca tretme" dediimizde "public tretmesi" anlalmaldr. "is a"
ilikisi public tretmesiyle salanr. Dier tretme biimlerinin amac "is a" ilikisini
kurmak deildir. protected tretmesi ve private tretmesi baz zel amalar iin kullanlr.
public tretmesinde tremi snf taban snfn public blmn olduu gibi devir alarak
kendi mterilerine (clients) sunar. Yani taban snfn public blm tremi snfn public
blmnn bir parasdr.
Byle bir tretme ileminde taban snfn protected blm tremi snfn protected
blmym gibi kullanlabilir. Taban snfn private blm tam olarak korunmutur.
Taban snfn private blmne tremi snf tarafndan hibir biimde eriilemez.

Tremi Snf Nesnelerinin Bellekte Yerleimi


Bir tremi snf nesnesi kendi iinde taban snfn elemanlarn da ierir. rnein:
classA{
private:
inta,b;
public:
//
};
classB:publicA{
private:
intc,d;
public:
//
};
gibi bir tretme ileminden sonra B snf trnden bir nesne tanmlanrsa, bu nesne hem
A snfnn hem de B snfnn elemanlarn ierir. Yani, sizeof(B), drt tane sizeof(int)
toplam kadardr (DOS altnda 8, UNIX ve Win32 sistemlerinde 16). Tremi snf
elemanlar ile taban snf elemanlar blok olarak bitiik bir biimde yerletirilir. Ancak
taban snf elemanlarnn m yoksa tremi snf elemanlarnn m daha dk adrese
yerletirilecei standart olarak belirlenmemitir. Derleyiciden derleyiciye deiebilir.
Taban snf ile tremi snf elemanlarnn tremi snf iindeki yerleimi standart bir
biimde belirlenmemi olsa da, popler derleyicilerin tmnde taban snf elemanlar daha
dk saysal adreste olacak biimde yerleim kullanlr. Yerleim biiminin standart bir
biimde belirlenmemi olmas herhangi bir tanabilirlik problemine yol amaz.

178/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Tremi snf nesnesinin taban snfn elemanlarn da ierdiini grmek iin aadaki
rnei yazarak altrn:
classBase{
public:
intb1,b2;
};
classDer:publicBase{
public:
intd1,d2;
};
#include<iostream>
usingnamespacestd;
intmain()
{
Derder_object;
cout<<"sizeof(der_object)="<<sizeof(der_object)<<endl;
return0;
}
Yukardaki programda Der snf trnden der_object isimli bir nesne tanmlanyor. Bu
nesne Base taban snfnn elemanlarn da ierir. Nesnenin uzunluu DOS altnda 8 byte,
Win32 ve UNIX sistemlerinde ise 16 byte olur. Yani 2 * sizeof(int) + 2 * sizeof(int) .

Tremi Snflarda Eriim Kural


Tremi snf yalnzca kendi elemanlarna ve ilevlerine deil, ayn zamanda taban snfn
elemanlarna ve ilevlerine de eriebilir. ncelikle vereceimiz rnekler iin bir snf
tanmlamas yapalm:
#include<iostream>
classBase{
private:
intb;
protected:
voidbase_pro_func();
public:
voidset_base(int);
voiddisplay_base()const;
};
classDer:publicBase{
private:
intd;
protected:
voidder_pro_func();
public:
voidset_der(int);
voiddisplay_der()const;
};
usingnamespacestd;

179/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

voidBase::set_base(intx)
{
b=x;
}
voidBase::base_pro_func()
{
cout<<"base_pro_func()"<<endl;
}
voidBase::display_base()const
{

cout<<b<<endl;
}
voidDer::set_der(intx)
{
d=x;
}
voidDer::der_pro_func()
{

cout<<"der_pro_func()"<<endl;
}
voidDer::display_der()const
{
cout<<d<<endl;
}

public Tretmesinden kan Sonular


1. Snf bilinirlik alan dnda, tremi snf nesnesi ya da gstericisi yoluyla dardan
nokta ya da ok ilecini kullanarak taban snfn public blmne eriilebilir. Ancak taban
snfn protected ve private blmlerine eriilemez.
Aadaki rnei inceleyelim:
intmain()
{
Derd;
x.set_der(20); //Geerli.
x.set_base(10);
//Geerli.
//x.der_pro_func();
Geersiz.Tremisnfnprotectedblm.
//x.base_pro_func();Geersiz.Tabansnfnprotectedblmn.
//x.d=20;
Geersiz.Tremisnfnprivateblm.
//x.b=10;
Geersiz.Tabansnfnprivateblm.
return0;
}
2. Tremi snf bilinirlik alan iinde taban snfn public ve protected blmlerine
dorudan eriilebilir. Ancak private blmne dorudan eriilemez. Yani tremi snf ye
ilevleri, taban snfn public ve protected blmlerindeki deikenleri dorudan
kullanabilir, taban snfn ye ilevlerini de dorudan arabilir.

180/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Taban snfn private blm tam olarak korunmutur. Bu blme herhangi bir biimde
eriilemez.
rnein Der tremi snfnn der_pro_func ye ilevi iinde taban snfn protected ve
public blmlerine eriilebilir.
voidDer::der_pro_func()
{
display_base();
base_func();
d=100;
//b=200;
Geersiz!
}

Tremi Snf ye levlerinin Taban Snf ye levlerini armas


Bir tremi snf ye ilevi, taban snfn public ve protected blmmne erierek taban
snfn ye ilevlerini arabilir. Tremi snf nesnesiyle taban snf ye ilevi
arldnda, ya da tremi snf ye ilevi iinde taban snfn ye ilevi dorudan
arldnda, taban snf ye ilevine this gstericisi olarak tremi snf nesnesi iinde
yer alan taban snf alt nesnesinin adresi geirilir. Yani taban snfn ye ilevine aslnda
fiziksel olarak bir taban snf nesnesinin adresi geirilmektedir. Aadaki rnei inceleyin:
classBase{
public:
intb;
voidbase_func();
};
#include<iostream>
usingnamespacestd;
voidBase::base_func()
{
cout<<"base_func()icindethisadresi="<<this<<endl;
}
classDer:publicBase{
public:
intd;
voidder_func();
};
voidDer::der_func()
{
cout<<"der_func()icindethisadresi="<<this<<endl;
}
intmain()
{
Derder_object;
cout<<"&der_object="<<&der_object<<endl;
cout<<"&der_object.d="<<&der_object.d<<endl;
cout<<"&der_object.b="<<&der_object.b<<endl;
der_object.der_func();
der_object.base_func();
return0;
}

181/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


rnek bir ekran kts:
&der_object=0012FF78
&der_object.d=0012FF7C
&der_object.b=0012FF78
der_func()icindethisadresi=0012FF78
base_func()icindethisadresi=0012FF78

Taban Snf Kurucu ve Sonlandrc levlerinin arlmas


Tremi snf nesnesi kendi iinde taban snfa ilikin bir alt nesneyi de ierir. Taban snf
elemanlarnn taban snfn private blmnde olduunu dnelim. Bu durumda tremi
snfn ye ilevleri oradaki veri elemanlara eriip onlara ilkdeer verebilir mi? Tremi
snfn kurucu ilevi iinde yalnzca tremi snf elemanlarna ilkdeer verilebilir. Peki
tremi snfn private blmde yer alan taban snf elemanlarna nasl ilkdeer verilebilir?
Tremi snf nesnesine ait taban snf elemanlarna ilkdeer verilmesi, tremi snfn
kurucu ilevinin ana blounun banda taban snfn varsaylan kurucu ilevine yaplan gizli
aryla olur. Yani tremi snf kurucu ilevi kendi iinde taban snf varsaylan kurucu
ilevini arr. Aadaki program derleyerek altrn:

182/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classBase{
intb;
public:
Base();
Base(int);
voiddisplay_base()const;
};
#include<iostream>
usingnamespacestd;
Base::Base()
{
cout<<"Base::Base()"<<endl;
b=0;
}
Base::Base(intval)
{
cout<<"Base::Base(int)"<<endl;
b=val;
}
voidBase::display_base()const
{
cout<<"b="<<b<<endl;
}
classDer:publicBase{
intd;
public:
Der();
};
Der::Der()
{
cout<<"Der::Der()"<<endl;
d=0;
}
intmain()
{
Derder_object;
der_object.display_base();
return0;
}
main ilevi iinde tremi snf olan Der snf trnden der_object simli bir nesne
tanmlanyor:
Derder_object;
Bu nesne iin Der snfnn varsaylan kurucu ilevinin arlacan biliyorsunuz. Der
snfnn varsaylan kurucu ilevinin ana blounun hemen banda da, derleyici tarafndan

183/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


yerletirilen gizli bir ar kodu ile taban snf olan Base snfnn varsaylan kurucu ilevi
arlr.
Der::Der()
{
//DerleyicitarafndanburayaBase::Base()a?rkoduekleniyor!
cout<<"Der::Der()"<<endl;
d=0;
}
Tremi snfn btn kurucu ilevlerinde bu gizli ar ilemi yaplr.
Taban snfn varsaylan kurucu ilevi yerine, taban snfn parametreli baka bir kurucu
ilevin arlmas istenebilir. Bu durumda tremi snfn kurucu ilevi MIL (Member
Initialization List) szdizimi ile tanmlanmaldr. MIL szdiziminde taban snfn hangi
kurucu ilevinin arlaca aadaki gibi belirlenir.
B::B(parametrede?ikenleri):tabansnfismi(parametrede?ikenleri)
{
//...
}
Grld gibi tanmlama, bir snfn baka bir snf trnden elemanlara sahip olmas
durumunda olduu gibi MIL szdizimi kullanlarak yaplr. Ancak bu kez ':' atomunu
elemannn ismi deil taban snf ismi izler. Taban snf isminden sonra ayra iinde bir
parametre deikeni listesi yazlabilir. Bu durumda derleyici parametre listesini
inceleyerek parametre listesine uygun olan taban snf kurucu ilevini arr. rnein
yukardaki tretme ileminde Der snfnn kurucu ilevi yle yazlm olabilirdi:
Der::Der():Base(1)
{
cout<<Der::Der()<<endl;
}
Bu durumda Base taban snfnn int trden parametre deikeni olan kurucu ilevi
arlr.
Tremi snf kurucu ilevine geilen argmanlar taban snf kurucu ilevine aktarlabilir.
rnein tretilen snf olan Der snfnn
Der(int,int);
biiminde bir kurucu ilevi olsun.
Der::Der(intx,inty):Base(x),d(y){}
Burada Der snfnn kurucu ilevinin x parametre deikeni, taban snfn kurucu ilevi iin
kullanlyor. Bylece rnein :
Derder_object(10,20);
biiminde bir nesne tanmlamas ile 10 deeri taban snfn kurucu ilevi iin 20 deeri ise
tremi snfn kurucu ilevi iin kullanlr.
Tremi snfn kurucu ilevinin tanmlamasnda eer MIL szdizimi kullanlmamsa,
taban snf iin varsaylan kurucu ilevi arlr. rnein Y snf X snfndan tretilmi
olsun.

184/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Y::Y()
{
//...
}
Bu durumda kurucu ilevin ana blounun banda X snf iin varsaylan kurucu ilev
arlr. Yani bu biimde bir tanmlama aadaki gibi tanmlamayla edeer kabul
edilebilir:
Y::Y():X()
{
//...
}
Eer taban snf olan X snfnn herhangi bir kurucu ilevi varsa, ama varsaylan kurucu
ilevi yoksa bu durum derleme aamasnda hata oluturur.

Kurucu levin Snfn private Blmnde Olmas


Taban snf kurucu ilevlerinin tremi snfn kurucu ilevi iinden bu biimde otomatik
olarak arlabilmesi iin, taban snf kurucu ilevinin kendi snfnn protected ya da
public blmnde bildirilmi olmas gerekir. Bir snfn kurucu ilevi snfn protected
blmne koyulursa global bir ilev iinde o snf trnden nesne tanmlanamaz. nk
snfn protected kurucu ilevine eriilemez. Ancak o snftan tretme yapldnda tremi
snf kurucu ilevi taban snfn protected kurucu ilevini arabilir.
classBase{
protected:
Base();
public:
//...
};
classDer:publicBase{
//...
public:
Der();
};
intmain()
{
Derder_object;
Basebase_object;

//Geerli
//Geersiz!

return0;
}

Taban Snfn Sonlandrc levinin arlmas


Bir snf nesnesinin mr sona erdiinde o snf nesnesi iin sonlandrc ilevin arldn
hatrlyorsunuz. Tremi snf trnden bir nesne kendi iinde taban snf alt nesnesini
ierdiine gre, tremi snf nesnesinin mr tamamlandnda, ierilen taban snf
nesnesinin de mr tamamlanm olur. Peki bu durumda, ierilen taban snf nesnesinin
sonlandrc ilevi nasl arlr?
erilen taban snf nesnesi iin sonlandrc ilevin arlmas derleyicinin ekledii bir kod
ile olur. Derleyici tremi snf sonlandrc ilevinin sonuna taban snfn sonlandrc
ilevine yaplan ar kodunu ekler. Aadaki rnei derleyerek altrn.

185/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include<iostream>
classBase{
public:
Base(){std::cout<<"Base::Base()"<<std::endl;}
~Base(){std::cout<<"Base::~Base()"<<std::endl;}
};
classDer:publicBase{
public:
Der(){std::cout<<"Der::Der()"<<std::endl;}
~Der();
};
Der::~Der()
{
std::cout<<"Der::~Der()"<<std::endl;
}
voidfunc()
{
Derder_object;
}
intmain()
{
func();
return0;
}
Programn ekran kts
Base::Base()
Der::Der()
Der::~Der()
Base::~Base()
eklinde olur.
Der::~Der()
{
cout<<"Der::~Der()"<<endl;
//DerleyiciburayaBase::~Basea?rsnekliyor!
}
Bu durumun anlam udur. Bir tremi snf nesnesi yok edilirken nce tremi snfn
ekledii ksm yok edilir. Daha sonra taban snf ksm yok edilir. Kurucu ve sonlandrc
ilevlere ilikin daha nce aklanan kural anmsayalm. Kurucu ilevler ile sonlandrc
ilevler ters srada arlr. Yani kurucu ilevi en nce arlan nesnenin sonlandrc ilevi
en sonra arlr. Taban snfn kurucu ve sonlandrc ilevlerinin arlmas durumunda da
bu kural geerlidir.

Tretme le Bileik Nesne Oluturmann Karlatrlmas


Mantksal ve ilevsel karlklar farkl olsa da, tretme ile bileik nesne oluturmann
ortak noktalar vardr. Her iki arata da bir snf nesnesi bir baka snf nesnesini fiziksel
olarak ierir.

186/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

classMember{
//...
};
classOwner{
Memberm;
//...
};
Yukardaki rnekte Owner snf Member snf trnden bir elemana sahiptir. Owner snf
trnden bir nesne yaratldnda bu nesnenin iinde Member snf trnden bir isel
nesne (embedded object) de yer alr. Member snf trnden isel nesne mnin varsaylan
kurucu ilevi, Owner snfnn kurucu ilevlerinin bana derleyici tarafndan eklenen edilen
bir kodla arlr. Yine Member snf trnden isel nesne mnin sonlandrc ilevi, Owner
snfnn sonlandrc ilevinin eklenen edilen kodla arlr. erilen nesne mnin varsaylan
kurucu ilevinin deil de, parametreli kurucu ilevlerinden birisinin arlmas MIL
szdizimiyle mmkn klnmtr. imdi de tretmeye bakalm:
classBase{
//...
};
classDer:publicBase{
//...
};
Der snf trnden bir nesne yaratldnda bu nesnenin iinde Base trnden bir alt
nesne (subobject) yer alr. Bu alt nesne tremi snf olan Der snfnn taban snf olan
Base snfndan devir ald ksmdr. Derleyici rettii kodda Der snfnn kurucu
ilevlerinin bana taban snfn varsaylan kurucu ilevine yaplan bir ar kodunu ekler.
Taban snf nesnesinin sonlandrc ilevinin arlmas da yine, tremi snfn sonlandrc
ilevinin koduna derleyici tarafndan otomatik olarak eklenen, taban snfn sonlandrc
ileve yaplan ar koduyla salanr. Tremi snf nesnesinin yaratlmas srasnda taban
snf nesnesi iin parametreli bir kurucu ilevinin arlmas yine MIL szdizimiyle
mmkn klnmtr.
Fiziksel karlklar birbirine bu kadar yaknda olsa iki aracn mantksal karlklar farkl
olduu gibi modelledikleri durumlar da tamamen farkldr. Bileik nesneler "has a" ilikisini
modellerken tretme "is a" ilikisini modeller. Baz durumlarda iki snf arasnda bir
sahiplik ilikisi mi yoksa bir genellik - zellik ilikisi mi olduu kolayca anlalamayabilir.
Yani bir bileik nesne mi oluturulmaldr yoksa bir snf m tretilmelidir? Bir proje iinde
tanmlanacak snflarn neler olacan saptamak, bu snflar arasndaki ilikilerin trn
belirlemek iin baz teknikler kullanlr. Bu tekniklere ileride deineceiz.

Snfn protected Blm


Snfn protected blm yalnzca tretme yapldnda anlam kazanan bir blmdr. Bu
blm tpk private blm gibi darya kapaldr. Ancak bir tretme yapldnda tremi
snfn ye ilevleri tarafndan taban snfn protected blmne eriilebilir. Yani private
blm ile protected blm arasndaki fark udur. Tremi snfn ilevleri taban snfn
private blmne eriemezken taban snfn protected blmne eriebilir.
Bu durumda bir snfn
- public blm tm kodlarn her zaman eriebilecei bir blmdr.
- private blm yalnzca snfn kendi ye ilevlerinin ve arkada ilevlerin eriebilecei
bir blmdr.

187/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


- protected blm snfn kendi ye ilevlerinin ve arkada ilevlerinin yan sra tremi
snf ye ilevlerinin de eriebilecei bir blmdr. Tremi snf ye ilevlerinin
eriebilmesi onu private blmden ayrr.
Peki hangi elemanlar ve ye ilevler snfn protected blmne yerletirilmelidir? te
buna karar verebilmek iin nce sorulmas gereken soru udur: "Tasarlanan snftan
tretme yaplacan dnlyor mu?". Eer dnlyorsa treten kod paras hangi
elemanlarndan ve ilevlerinden faydalanabilir? te tretmeyi yapan kod parasnn
dorudan kullanabilecei, onun ilerini kolaylatraca dnlen ye ilevler ve veri
elemanlar snfn protected blmne yerletirilmelidir. Bylelikle bu elemanlar ve ye
ilevler darnn algsndan uzaklatrlarak yalnzca tretme ilemini yapacak kodlarn
kullanmna sunulur. rnein tarih ilemlerini yapan Date snfna bakalm. Bu snftan bir
snf tretip bu snfa yeni ilevler eklemek istenirse day, month, year elemanlar
dorudan kullanllmas iin bu elemanlar snfn protected blmne yerletirilebilir. Bir
snfn protected arayz kendisinden tretme yapan snflar ilgilendiren bir arayzdr.
classDate{
public:
Date();
Date(intday,intmonth,intyear);
//
protected:
intday,monthyear;
};
classSpecialDate:publicDate{
//Yeniyeilevlerveelemanlar
};

protected

Bir snfn protected blm koruma bakmndan private blmden gevek public
blmden sk olduuna dikkat edin. imdi yerleim bakmndan bir zet yapalm.
Blm

Neler Yerletirilmeli?

public

Dardan tm kodlarn arabilecei ye ilevler, tm kodlarn


kullanabilecei elemanlar ve bildirimler
Dardan eriilmesi istenmeyen, yalnzca snftan tretme yapacak kodlarn
erimesi istenilen ye ilevler, elemanlar ve bildirimler
Yalnzca snfn kendi kodlarnn erimesi istenilen ye ilevler, elemanlar ve
bildirimler.

protected
private

Snf Hiyerarisi
Tretme ilemi birden fazla kademeyi ierebilir.
Bir taban snftan farkl tretme ilemleriyle dorudan yeni snflar tretilebilir. rnein
"Ara" isimli bir snftan, "hava arac", "kara arac", "deniz arac" snflar tretilebilir.
Bir taban snftan tretilmi bir snfn kendisi bu kez taban snf olarak kullanlarak da yeni
bir tretme yaplabilir. rnein "Kara Arac" snfndan "otomobil" snf tretilip bu kez
"otomobil" snfndan da, "Yar Otomobilir" snf tretilebilir.
Bir tretme zinciri iinde mantksal olarak ilikisi kurulan snflarn tmne "snf
hiyerarisi" denir. Tretmeden elde edilmek istenen ana faydalardan biri, tretme
hiyerari iinde yer alan snflarn tm zerinde belirli ilemleri yapacak ortak kodlarn,
hiyerarinin tepesinde yer alan snfa dayal olarak yazlmasdr. Bu konuyu ileride ayrntl
olarak ele alacaz.

Tretme ve Bileik Nesnelerin Birlikte Kullanlmas

188/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Baka bir snftan tretilen bir snf, yine bir baka snf trnden elemana sahip olabilir.
Bu durumda kurucu ilevler hangi sraya gre arlr?
Tremi bir snfn baka snf trnden bir nesneye sahip olmas durumunda, nce taban
snfn kurucu ilevi arlr. Taban snfn (ya da snflarn) kurucu ilevleri arldktan
sonra bu kez eleman olarak ierilen snf nesneleri iin kurucu ilevleri arlr. Aadaki
program derleyerek altrn:
#include<iostream>
classMember{
public:
Member(){std::cout<<"Member::Member()"<<std::endl;}
~Member(){std::cout<<"Member::~Member()"<<std::endl;}
};
classBase{
public:
Base(){std::cout<<"Base::Base()"<<std::endl;}
~Base(){std::cout<<"Base::~Base()"<<std::endl;}
};
classDerComp:publicBase{
Membermem;
public:
DerComp(){std::cout<<"DerComp::DerComp()"<<std::endl;}
~DerComp(){std::cout<<"DerComp::~DerComp()"<<std::endl;}
};
voidfunc()
{
DerCompd;
}
intmain()
{
func();
return0;
}
Programn ekran kts :
Base::Base()
Member::Member()
DerComp::DerComp()
DerComp::~DerComp()
Member::~Member()
Base::~Base()

Tremi Snflarda Bilinirlik Alan


Bilinirlik alan (scope) bir ismin derleyici tarafndan tannabildii program araldr. C ve
C++ da bir blok iinde ayn isimli birden fazla deiken biliniyorsa o blok iinde ayn isimli
deiken kullanldnda dar bilinirlik alanna sahip olana eriilir. Yani dar bilinirlik
alanndaki isim kendisini kapsayan daha geni bilinirlik alannda bulunan ismi maskeler.
Onun grlmesini engeller. Ayn kural C++ da tretme ilemlerini kapsayacak biimde
geerlidir. nce u soruyu soralm: Tretme durumunda taban snf tremi snf
tarafndan eriilebildiine gre taban snftaki bir isim mi daha dar bilinirlik alanna

189/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


sahiptir, tremi snftaki bir isim mi? Tremi snftaki isim deil mi? nk taban
snftaki isimler hem kendi snf iinde hem de tremi snf iinde kullanldna gre
daha geni bir bilinirlik alanna sahiptir. Bu durumda hem taban snf iinde hem de
tremi snf iinde ayn isimli bir deiken varsa tremi snf ye ilevleri iinde o
deiken kullanldnda, dar bilinirlik alanna sahip olan yani tremi snfta tanmlanm
olan anlalr. Aadaki kodu inceleyelim:
classBase{
protected:
intb;
public:
Base():b(0){}
voiddisplay()const;
};
#include<iostream>
voidBase::display()const
{
std::cout<<"b="<<b<<std::endl;
}
classDer:publicBase{
intb;
public:
Der():b(1){}
voidset(int);
voiddisplay()const;
voidfunc()const;
};
voidDer::set(intval)
{
b=val;
//Der::b=val;
}
voidDer::display()const
{
std::cout<<"b="<<b<<std::endl;
}
voidDer::func()const
{
display();
}
Burada Der snfnn set ye ilevi iinde kullanlan b ismi, daha dar bilinirlik alanna sahip
olan Der snfnn b isimli elemanna ilikindir. Der snfnn b isimli eleman Base snfnn
b isimli elemann maskeler yani grnmesini engeller. Tabii eer Der snfnn b isimli bir
eleman olmasayd burada kullanlan b, Base snfna ilikin olurdu.
Ayrca Base snfnn display ye ilevi iinde kullanlan b eleman Base snfna ilikin
olandr. Zaten taban snf tremi snfa eriemediine gre hibir biimde bunun Base
snfna ilikin olmas sz konusu deildir.
Tremi snf iinde ayn isimli taban snf elemanlarna ve ilevlerine znrlk ileci ile
eriilebilir. rnein bu kez Der snfnn iki parametreli set isimli bir ye ilevi daha
olduunu dnelim:

190/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidDer::set(intx,inty)
{
b=x;
Base::b=y;
}
levde dorudan kullanlan b, bilinirlik alan kurallarna gre Der snfna ilikin olandr.
Ancak znrlk ileci ile, yani Base::b ifadesi ile kullanlan b, Base snfna ilikin
olandr. ki terimli znrlk ilecini taban ve tremi snflarda ayn isimli elemanlar ya
da ilevler varken taban snfn elemanlarna erimek amacyla bu biimde kullanlabilir.
Bilinirlik alan kurallar ilev isimleri iin de geerlidir. Tremi ve taban snfta ayn isimli
ilevler varsa dar bilinirlik alan kuralna gre tremi snftaki anlalr. rnein Der
snfnn func ilevi iinde arlan display ilevi Der snfna ilkin olandr.
znrlk ileci, ayn amala ye ilevler iin de kullanlabilir. rnein tremi snf olan
Der snfnn func isimli ye ilevi iinde bu kez taban snfn display isimli ilevi arlmak
istenseydi bu aadaki gibi yaplabilirdi:
voidDer::func()
{
Base::display();
}
Dar bilinirlik alan kural dardan snf elemanlarna eriirken de geerlidir. Yukarda
verdiimiz tretme ilemi iin aadaki kod yazlm olsun:
intmain()
{
Derder_object,*der_ptr;
der_object.display();
der_object.Base::display();
der_ptr=&der_object;
der_ptr>display();
der_ptr>Base::display();
Basebase_object;
base_object.display();
return0;

//1
//2
//3
//4
//5

}
Yukardaki main ilevinde yorum satrlaryla iaretlenen ilev arlarna bakalm:
//1
//2
//3
//4
//5

Der snfnn display ilevi arlr.


Base snfnn display ilevi arlr.
Der snfnn display ilevi arlr.
Base snfnn display ilevi arlr.
Base snfnn display ilevi arlr. Taban snf tremi snfa eriemez!

Bilinirlik alan ile eriilebilirlik ayn eyler deildir. C++da her zaman nce isim aramas
daha sonra eriim denetimi yaplr. Bu kuraln etkisini aadaki gibi bir tretme ileminde
deerlendirelim:

191/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classBase{
public:
intx;
};
classDer:publicBase{
intx;
};
voidfunc()
{
Derder_object;
der_object.x=0;
//Geersiz!
}
C++'a yeni balayanlar func ilevi iindeki
der_object.x=0;
atamasnn geerli olmas gerektiini dnrler. Hem tremi snfta hem de taban
snfta x isimli bir eleman olduuna gre, nce tremi snfta bulunan x isimli elemana
eriilmeye allr. Tremi snfta bulunan x snfn private blmnde bulunduu iin bu
eriim gereklemez. Ancak taban snfn public blmnde bulunan xe eriilir.
Ancak durum byle deildir. nce isim aramas yaplr. Tremi snf olan Der snfnn
bilinirlik alannda x ismi bulunduunda isim arama sona erdirilir. Aranan isim bulunmu ve
x isminin tremi snf bilinirlik alanndaki x olduu anlalmtr. Artk ne nedenle olursa
olsun yeniden bir isim aramas yaplmaz. imdi bu x'e eriimin geerli olup olmad
sorgulanr. Tremi snfn x isimli eleman tremi snfn private blmnde olduu iin
eriim geersizdir.
lev yklemesi (function overloading) ayn bilinirlik alanndaki ayn isimli ilevler iin
geerli bir aratr. Farkl bilinirlik alanndaki ayn isimli ilevler yklenemez. Yine, dar
bilinirlik alanndaki ismin daha geni bilinirlik alanndaki ismi gizlemesi sz konusudur. Bu
kez aadaki kod parasn inceleyin:
classBase{
public:
voidfoo();
voidfoo(int,int);
};
classDer:publicBase{
public:
voidfoo(int);
voidfoo(int,int);
};
intmain()
{
Derder_object;
//der_object.foo();
der_object.foo(10);
der_object.foo(5,8);
der_object.Base::foo();
der_object.Base::foo(5,8);

//Geersiz
//voidDer::foo(int)
//voidDer::foo(int,int)
//voidBase::foo()
//voidBase::foo(int,int)

return0;
}

192/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

main ilevi iinde yaplan ilev arlarn teker teker inceleyelim:


der_object.foo();
ars geersizdir. nk tremi snf bilinirlik alannda foo ismi bulunduunda isim
arama sona erer. Yalnzca Der snf iinde bildirilmi olan foo ilevleri, arlan ilev iin
aday olur. Der snf bilinirlik alan iinde parametresi olmayan foo isimli bir ye ilev
bildirilmediine gre, ar derleme zamannda hata olarak deerlendirilir. phesiz
tremi snf iinde foo isimli hi bir ilev tanmlanmam olsayd bu kez taban snfn
parametre deikeni olmayan foo isimli ilevi arlrd:
der_object.foo(10);
ars ile tremi snfn int parametreli foo ilevi arlr. Der snfnn bu ar iin iki
aday ilevi vardr. Ancak seilecek ilev int parametreli olandr:
der_object.Base::foo();
//voidBase::foo()
der_object.Base::foo(5,8); //voidBase::foo(int,int)
arlarnda ilev ismi snf ismi ile nitelendirildiinden isim aramas tremi snfn
bilinirlik alanndan balamaz. Arama dorudan Base snfnn bilinirlik alanndan balar. Bu
durumda Base snfnn ayn ismli iki ilev iinden ilev ykleme kurallarna gre uygun
olan ilevler arlr.
der_object.foo(5,8);
ile bu kez arlan Der snfnn iki parametreli foo ilevi iken
der_object.foo(10);
ile Der snfnn tek parametreli foo ilevi arlr.
Benzer durum tremi snfn ye ilevi iinde taban snfn bir elemanna eriirken ya da
taban snfn ye ilevi arlrken de geerlidir. Aadaki program inceleyin:
classBase{
intb;
public:
voidfoo();
voidfunc(int);
};
classDer:publicBase{
intb;
public:
voidfoo();
voidfunc();
};
voidDer::foo()
{
b=10;
//Der::b=10;
//Base::b=50;Tabansnfnprivateblmneeriilemez.Geersiz
foo();
//?levkendikendinia?rr.
Base::foo();
//Base::foo()a?rlr
//func(10);
//Geersiz!
func();
//Der::func()a?rlr.

193/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Base::func(10);//Base::func(int)a?rlr.
}

Tremi Snf inde Yaplan using Bildirimi


Tremi ve taban snflarn farkl bilinirlik alan oluturduklarn biliyorsunuz. Tremi snf
bilinirlik alan iinde bildirilen bir isim, taban snf iinde de kullanlmsa, taban snftaki
isim maskelenir. Maskelenme istenmiyorsa tremi snf iinde using bildirimi yaplabilir.
Snf ii using bildirimiyle taban snflara ilikin maskelenen isimler grnr klnr. Bylece
taban snf ve tremi snf ilevleri farkl bilinirlik alannda olsalar bile yklenebilir.
Aadaki kodu inceleyin:
#include<iostream>
classBase{
public:
voidfoo(){std::cout<<"Base::foo()"<<std::endl;}
};
classDer:publicBase{
public:
usingBase::foo;
voidfoo(int){std::cout<<"Der::foo(int)"<<std::endl;}
};
intmain()
{
Derder_object;
der_object.foo();
der_object.foo(25);
return0;
}
Der snfnn tanm iinde yaplan using bildirimiyle Base snfnn foo isimli ilevi Der snf
iinde grlebilir hale getiriliyor. Bylece

194/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

der_object.foo();
ars sz konusu olduunda
voidBase::foo();
ilevi de arya aday ilev olarak belirlenir. using bildirimiyle taban ve tremi snfn foo
ilevleri ayr bilinirlik alanlarna ait olmasalar da yklenebilir.
imdi de aadaki koda bakalm:
#include<iostream>
classBase{
public:
voidfoo(){std::cout<<"Base::foo()"<<std::endl;}
};
classDer:publicBase{
public:
usingBase::foo;
voidfoo(){std::cout<<"Der::foo()"<<std::endl;}
};
intmain()
{
Derder_object;
der_object.foo();
return0;
}
main ilevi iinde arlan, Der snfnn foo ilevidir. Der snfnn foo ilevinin gizli
parametre deikeni Der & trnden iken, Base snfnn foo ilevinin gizli parametre
deikeni Base & trndendir.

Snflarda sim Arama


sim arama (name lookup) bilinirlik alannn derleyici bak asyla ele alnma biimidir.
Bir deiken kullanldnda derleyici o deikeni srasyla dardan genie doru eitli
bilinirlik alanlarnda arar. Eer ismi bir bilinirlik alannda bulursa aramay keser.
Deikeninin o bilinirlik alanndaki isim olduuna karar verir. Derleyici eer arad ismi
hibir bilinirlik alannda bulamazsa bu durum hata olarak deerlendirilir. rnein Cde
derleyici bir blok iinde bir deiken ile karlatnda srasyla onu u bloklarda arar.
1. Deikenin kullanld blok iinde
2. lev iinde onu kapsayan bloklarda
3. Global isim alannda
imdi ayn isimli hem bir yerel hem de global deiken tanmlanm olduunu dnelim.
Derleyici onu yerel blokta bulduu iin arama ilemini srdrmez. sim arama srasnda
aranan isim bulunduu zaman, isim ister eriilir olsun isterse olmasn ilem sonlandrlr.
Eriim geerlilii yukarda da belirtildii gibi isim aramas bitirildikten sonra yaplr.
Grdnz gibi aslnda isim arama ilemi dar bilinirlik alan kuralnn derleyici bak
asyla yorumlanm biimidir. C++da snflar sz konusu olduunda bilinirlik alanna
ilkin karmak durumlar sz konusu olabildii iin anlatmda isim arama kavramndan da
faydalanlr. Bir isim ya nitelenmemi olarak (unqualified) ya da znrlk ileci ile
nitelenmi olarak (qualified) kullanlr. Snflarda isimlerin aranmasn nitelenmemi isimler

195/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


asndan inceleyeceiz.

Snf Bildirimi indeki simlerin Aranmas


Bir snf bildirimi iinde bir eleman, ye ilev ismi, typedef ismi, enum deimezleri gibi
isimlerin aranma srasn belirler. rnein:
classA{
public:
//
voidputstr(PCSTR);
//
};
Burada putstr ye ilevin parametre deikeninin tr olarak kullanlan PCSTR ismi snf
bildirimi iindedir. Bu isim nerede aranr?
Snf bildirimi iinde kullanlan bir isim srasyla u bilinirlik alanlarnda aranr:
1. sim kendi snf bildiriminin bandan kullanm yerine kadar olan blgede aranr.
Aadaki rnei inceleyin:
classA{
public:
Daysget_day(Str);
private:
typedefchar*Str;
enumDays{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,
Saturday};
public:
Strfunc(Days);
//...
};
Yukardaki snf tanmnda get_day ye ilevinin bildiriminde Days ve Str isimlerinin
kullanlmas geersizdir. nk derleyici bu noktaya geldiinde bu isimlerle henz
karlamamtr.
Ancak func isimli ye ilevin geri dn deerinin tr olarak Str ismi kullanlabilir. nk
bu trn bildirimi snf iinde daha nce yaplmtr.
2. sim snfn taban snf bildirimlerinin her yerinde aranr. Bir dizi tretme sz konusu
olabilir. Bu durumda ayn zellik tm taban snflar iin geerli olur.
rnein aada tremi snf iindeki SIZE isminin kullanlmas geerlidir.
classA
{
protected:
enum{SIZE=50};
};
classB:publicA{
private:
inta[SIZE];
};
Tabii burada SIZE taban snfn public ya da protected blmnde bildirilmi olmasayd,
kullanm bilinirlik alan bakmndan geerli fakat eriim bakmndan geersiz olurdu.

196/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

3. Snf baka bir snfn iinde bildirilmise, isim kapsayan snf bildiriminden ismin
bulunduu snfn bildirimine kadar olan blgede aranr.
rnein aada B snf iindeki Str isminin kullanlmas geerlidir. Ayrca bu durumda
eriim geerlilii iin ismin kapsayan snfn public blmnde bildirilmi olmas gerekir.
classA{
public:
typedefchar*Str;
classB{
private:
StrpStr;
};
};
4. Snf baka bir snf iinde bildirilmise, isim kapsayan snf bildiriminin taban snflarnn
her yerinde aranr. Bu durumda eriim geerlilii iin kapsayan snfn public tretme
biimiyle tretilmi olmas ve kullanlan isimlerin de snfn public blmnde bildirilmi
olmas gerekir. Aadaki rnei inceleyelim:
classA{
public:
enum{SIZE=50};
};
classB:publicA{
classC{
private:
intx[SIZE];//geerlieriim
//...
};
};
Burada C snf iinde SIZE isminin kullanlmas geerlidir.
5. sim, snfn iinde bulunduu isim alannn bandan kapsayan snf bildirimine kadar
olan blgede aranr. Aadaki rnekte SIZE ismine eriim geerlidir.

namespaceX{
enum{SIZE=50};
classB{
classC{
private:
intx[SIZE];
//...
};
};
}

//geerlieriim

6. sim dosya bandan snfn iinde bulunduu isim aralna kadar olan global isim
aralnda aranr. Snf bildirimi iinde bir isim znrlk ileci ile snf ismi ya da isim
aral ismi belirtilerek kullanlm olabilir. Bu durumu ileride ele alacaz.

197/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Snfn ye levi inde Kullanlan simlerin Aranmas


Snfn ye ilevi iindeki isimlerin aranma sras tanmlamann snf iinde (yani inline
olarak) yaplp yaplmadna gre deiiklik gstermez. ye ilev ister snfn iinde
tanmlanm olsun isterse darda tanmlanm olsun arama ilemi aada aklanan
srada yaplr:
1. sim, ye ilev kendi yerel bloklar ve parametre bildirim ayralar iinde aranr.
2. sim ye ilevin ilikin olduu snf bildiriminin her yerinde aranr. rnein:
classA{
public:
voidset(intx)
{
a=x;
}
intget()const
{
returna;
}
private:
inta;
};
Burada set ve get ye ilevlerinin iinde a ismi daha sonra bildirildii halde kullanlyor.
Snfn her yeri arand iin kullanm geerlidir. Grld gibi arama ileminde ye
ilevin snf iinde tanmlanp tanmlanmadnn bir nemi yoktur.
3. sim ye ilevin ilikin olduu snfn taban snf bildirimlerinin her yerinde aranr.
Arama ilemi ilk taban snftan balanarak yukarya doru srasyla yaplr. Ayrca, eriim
geerlilii iin ismin taban snfn public ya da protected blmlerinde bulunmas gerekir.
rnein:
classA{
public:
intx;
};
classB:publicA{
public:
intx;
};

classC:publicB{
public:
voidfunc();
};
voidC::func()
{
x=100;
}
Burada x ismi srasyla B ve A taban snflarnda aranr. sim bulunduu anda arama
ilemine son verilir. Dolaysyla buradaki rnekte bulunan x, B snfna ilikin olan x
ismidir.

198/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

4. ye ilevin ilikin olduu snf kapsayan bir snf varsa, isim kapsayan snf bildiriminin
her yerinde aranr. Eriim geerlilii iin ismin snfn public blmnde bulunmas gerekir.
rnein:
classA{
public:
classB{
public:
voidfunc()
{
inta[SIZE];
for(inti=0;i<SIZE;++i)
a[i]=0;
//
}
};
enum{SIZE=100};
};
Burada B snf iindeki func ilevinde SIZE ismi kullanlabilir. Tabii byle durumlarda
kapsayan snfa ilikin bir eleman kullanlamaz. nk kapsama ilemi tretme ilemi
deildir. Bu yzden kullanlacak ismin de bir enum ismi, typedef ismi gibi bildirimlerden
olumas gerekir.
5. Snf kapsayan snf varsa, isim kapsayan snfn taban snf bildirimlerinin her yerinde
aranr. Bu durumda eriim geerlilii iin ismin kendi snfnn public blmnde bildirilmi
olmas gerekir. Tretme biiminin bir nemi yoktur. rnein:
classA{
public:
typedefchar*Str;
};
classB:publicA{
public:
classC{
public:
voidfunc() {StrpStr="Deneme";
//...
}
};
};
Burada Str ismi C snf iinden kullanlabilir.
6. sim snfn ya da kapsayan snfn iinde bulunduu isim alannn (namespace)
bandan kapsayan snf bildirimine kadar olan blgede aranr. rnein:

199/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


namespaceX{
typedefchar*Str;
classA{
public:
classC{
public:
voidfunc()
{
StrpStr="Deneme";
//...
}
};
};
}
Burada Str isminin kullanm geerlidir.
7. sim, snfn ya da kapsayan snfn iinde bulunduu isim alann kapsayan isim
alannda ve sonra da global isim alannda (global namespace) aranr. rnein aadaki
isimlerin hepsi doru kullanlmtr:
enum{SIZE=10};
namespaceX{
typedefint*Pint;
namespaceY{
typedefchar*Str;
classA{
voidfunc()
{
StrpStr="Deneme";
PintpInt=0;
inta[SIZE];
//...
}
};
}
}

Tretme likisinde Arkadalk Bildirimleri


Arkadalk tretme yoluyla devir alnmaz. Taban snfn arkada tremi snfn da
arkada deildir. Aadaki rnei inceleyin:
classBase{
intb;
friendvoidfunc();
public:
Base(intval):b(val){}
};
classDer:publicBase{
intd;
public:
Der(intval1,intval2):Base(val1),d(val2){}
};
voidfunc()

200/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


{
Derder_object(10,20);
//der_object.d=34;
der_object.Base::b=13;

//Geersiz!

}
Base snf iinde global func ilevine arkadalk veriliyor. Global func ilevi iinde
tanmlanan Der snf trnden der_object nesnesinin private eleman olan d elemanna
eriim derleme zamannda hataya neden olur. Ancak func ilevi iinde der_object
nesnesinin taban snftan devir ald b isimli private elemana eriebilir.

Tremi Snf Nesne Adresinin Taban Snf Gstericisine


Atanabilmesi
C++ dilinde kat bir tr denetiminin esas alndn biliyorsunuz. Bir gstericiye ancak ayn
trden bir adres atanabilir. Bir referans da ancak ayn trden bir nesne ile ilkdeerini
alabilir. public tretmesi bu kuraln bir istisnasdr. public tretmesiyle amalanan "is a"
ilikisini modellemektir. Tretilmi bir snf trnden nesne ayn zamanda taban snf
trnden bir nesne olduuna gre, taban snf trnden nesne gereken her yerde tremi
snf trnden bir nesne kullanlabilir.
1. Tremi snf nesnesi taban snf nesnesine dorudan atanabilir.
2. Tremi snf trnden bir nesnenin adresi taban snf trnden bir gsterici deikene
atanabilir.
3. Taban snf trnden bir referans tremi snf trnden bir nesne ile ilkdeerini alabilir.
Aadaki kod parasn inceleyelim:
classBase{
public:
//...
};
classDer:publicBase{
public:
//...
};
intmain()
{
Basebase_object;
Derder_object;
Base&base_ref=der_object;
Base*base_ptr=&base_object;
base_object=der_object;
return0;
}
"is a" ilikisinin anlam dilin kurallar ve aralar tarafndan da desteklenir. Tremi snf
nesnesinin taban snf nesnesi gereken yerde kullanlabilmesinin anlam udur. Bir snf
hiyerarisi iinde bir ilevin parametresi en tepedeki taban snf trnden bir gsterici ya
da bir referans ise, bu ilev hiyerari iinde herhangi bir snf trnden nesnenin adresi ile
(ya da kendisi ile) arlabilir. Bylece ortak zellikleri olan snflarn hepsi zerinde genel
ilem yapan ilevler yazlabilir.
voidprocess(Base&);

201/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Yukarda bildirimi verilen ilevin parametre deikeni Base trnden bir referanstr. Bu
ilev Base trnden bir nesne ile arlabildii gibi Base snfndan treyen herhangi bir
snf trnden nesne ile de arlabilir.
Tremi snf nesnesinin taban snf nesnesiymi gibi kullanlabilir. Ama bunun tersi doru
deildir. Bir tremi snf nesnesine taban snf nesnesinin atanmas ya da tremi snf
gsterici deikene taban snf trnden bir adresin dorudan atanmas geersizdir.

Tretmede Kopyalayan Kurucu levin Durumu


Tremi snf nesnesi kendi iinde bir taban alt nesnesini de ierir. Bir tremi snf
nesnesi ilkdeerini bir baka tremi snf nesnesinden alarak yaratlrsa, tremi snf
nesnesi iindeki taban snf nesnesinin durumu ne olur?
Eer tremi snf nesnesi iin bir kopyalayan kurucu ilev yazlmamsa, derleyici
yazaca kopyalayan kurucu ilevin bana, taban snfn kopyalayan kurucu ilevin ars
kodunu ekler. Yani ilkdeer alan tremi snf nesnesinin taban snf ksm iin de taban
snfn kopyalayan kurucu ilevi arlr.
Burada dikkat edilmesi gereken durum udur: Eer tremi snfn kurucu ilevi programc
tarafndan yazlrsa, taban snf nesnesine ilkdeer verilmesinden de programc sorumlu
olur. Eer taban snf ksmna ilkdeer verilmez ise, tremi snf nesnesinin taban snf
ksm iin varsaylan kurucu ilev arlr. Aadaki rnei inceleyin:
#include<iostream>
classBase{
public:
Base(constBase&r){std::cout<<"Base(constBase&)"<<std::endl;}
Base(){std::cout<<"Base()"<<std::endl;}
};
classDer:publicBase{
public:
Der(){std::cout<<"Der()"<<std::endl;}
Der(constDer&){std::cout<<"Der(constDer&)"<<std::endl;}
};
intmain()
{
Derder1;
Derder2(der1);

return0;
}
Derder2(der1);
tanmlama deyimiyle der2 nesnesi ilkdeerini der1 nesnesinden alarak yaratlyor. Bu
durumda yaratlan der2 nesnesi iin kopyalayan kurucu ilev arlr. der2 nesnesi iin
arlan kurucu ilevin bana derleyici, taban snfn varsaylan kurucu ilevine yaplan
ar kodunu ekler. Yani taban snf iin kopyalayan kurucu ilev deil varsaylan kurucu
ilev arlr. imdi Der snfnn kopyalayan kurucu ilevin tanmn programdan kartarak
program derleyin ve yeniden altrn. Bu kez der2 snf nesnesinin taban snf ksm iin
kopyalayan kurucu ilevin arldn greceksiniz. Tremi snfn kopyalayan kurucu
ilevini yazan programc, taban snf nesnesinin kopyalayan kurucu ilevin arlmasn
MIL szdizmiyle salayabilir:
Der::Der(constDer&r):Base(r){cout<<"Der(constDer&)"<<endl;}

202/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Tremi snf nesnesinin taban snf ksm iin hangi kurucu ilev arlr? Taban snfn
kopyalayan kurucu ilevin parametre deikeni Base trnden referans olduuna gre, bu
referans ilkdeerini tremi snfn kopyalayan kurucu ilevin parametre deikeni olan r
referansndan alabilir deil mi? Sonuca taban snf trnden bir referansa tremi snf
trnden bir nesne ile ilkdeer veriliyor.

Tretmede Atama levinin Durumu


Benzer durum atama ilevini ykleyen ilev iin de geerlidir. C++ da ayn snf trnden
iki nesnenin birbirine atanmas durumunda, atama ilecinin sol tarafndaki snf nesnesi
iin atama ilecini ykleyen ilevin arldn biliyorsunuz. Snf iin atama ilevi
yklenmemise, atama ilecini ykleyen ilevi derleyici yazar. Derleyicinin yazd atama
ilevi snfn statik olmayan public inline ye ilevidir. Bu ilev snf elemanlarn karlkl
olarak birbirine atayarak referans yoluyla atamann yapld nesneye geri dner. rnein
Myclass isimli bir snf iin, derleyici tarafndan otomatik olarak yazlan atama ilevinin
bildirimi aadaki gibi olur:
classMyclass{
public:
Myclass&operator=(constMyclass&);
};
Tremi snf iin bir atama ilevi yazlmazsa tremi snf iin ilevi derleyici yazar.
Derleyicinin yazd atama ilevi snf nesnesinin elemanlarn karlkl olarak birbirine
atamakla kalmaz, nesnelerin taban snf alt nesnelerini de birbirine atar. Bu atama iin
yine taban snfn atama ilevi arlr. Burada yine dikkat edilmesi gereken nokta udur:
Tremi snf iin atama ilecini ykleyen bir ilev yazlrsa, artk derleyici bu ileve
herhangi bir kod eklemez. Yani taban snf nesnelerinin birbirine atanmas da, tremi
snfn atama ile ilevinin sorumluluundadr. Aadaki kodu inceleyin:
classDer:publicBase{
public:
Der&operator=(constDer&);
};
Der&Der::operator=(constDer&r)
{
*(Base*)this=r; //tabansnfksmiinyaplanatama
return*this;
}
Der snf iin yazlan atama ilevi iindeki
*(Base*)this=r;
atamasn inceleyelim. lev iinde kullanlan this adresi atama ilecinin sol tarafna gelen
tremi snf nesnesinin adresidir. Bu adres, tr dntrme ileci ile nce taban snf
trnden bir adrese dntrlyor. Byle bir dnmle elde edilen adresin tremi snf
nesnesinin iindeki taban snf nesnesinin adresi olduunu biliyorsunuz. Bu adresin ierik
ilecinin terimi olmasyla elde edilen nesne, tremi snf nesnesinin taban snf alt
nesnesidir. Bu durumda taban snfnn atama ilevi arlr. Bu ileve argman olarak
tremi snf nesnesi gnderilmi olur. Taban snf nesnesinin atama ilevinin parametresi
taban snf trnden refarans olduundan bu ileve tremi snf nesnesinin
gnderilebileceini biliyorsunuz. Derleyicinin bu deyim iin aadaki gibi bir kod rettiini
dnebilirsiniz:
((Base*)this)>operator=(r);

203/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Ayn ii gerekletirmek iin aadaki gibi bir ar da yaplabilirdi:
Base::operator=(r);

SANAL LEVLER ve OKBMLLK


Sanal ilevler nesne ynelimli programlarn gelitirilemesini ve bytlmesini byk
lde kolaylatran, C++ dilinin ok nemli bir aracdr. Sanal ilevler, "nesne ynelimli
programlama tekniinin olmazsa olmaz zelliklerinden biri olan, alma zamanna
ilikin ok biimlilii salayan temel aratr.
Bu ara ile bir taban snftan dorudan ya da dolayl biimde tretilmi tm alt snflara
ilikin nesneler, yani bir snf hiyerarisi iinde kullanlabilecek tm nesneler, taban snf
nesneleriymi gibi dnlerek genel programlar yazlabilir. Programn gelitirilmesi
srasnda henz var olmayan snflar bu ara ile daha sonra programn genel yapsna
eklenebilir.
Bir snf hiyerarisi iinde bir snf nesnesi iin bir ilev yardmyla bir iin yaptrlmas
durumunu inceleyelim. rnein bir snf nesnesinin elemanlarnn deerlerinin ekrana
yazdrlmas gerektiini dnelim. Bu i snflarn display isimli ye ilevler tarafndan
yaplsn:
classA{
//
public:
voiddisplay()const;
};
classB:publicA{
//
public:
voiddisplay()const;
};
classC:publicA{
//
public:
voiddisplay()const;
};

//Asnfnnelemanlarnyazdracak.

//Bsnfnnelemanlarnyazdracak.

//Csnfnnelemanlarnyazdracak.

Yukardaki rnekte A snfndan tretilmi B ve C snflarnda A snfnda bulunan display()


ilevi yeniden tanmlanyor. imdi tremi bir snf nesnesi yoluyla yani nokta ileci
kullanlarak display ilevi arlrsa, dar bilinirlik alanndaki isim geni bilinirlik alanndaki
ayn ismi maskeleyecei iin, tremi snfn display ilevi arlr.
intmain()
{
Aa;
Bb;
Cc;
a.display();
b.display():
c.display();

//Asnfnndisplayilevia?rlr.
//Bsnfnndisplayilevia?rlr.
//Csnfnndisplayilevia?rlr;

return0;
}

204/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


ar snf nesnesi yoluyla deil de snf trnden gsterici ile yaplm olsayd da sonu
ayn olurdu:
intmain()
{
Aa,*pa=&a;
Cc,*cp=&c;
Bb;*bp=&b;
pa>display();
pb>display();
pc>display():

//Asnfnndisplayilevia?rlr;
//Bsnfnndisplayilevia?rlr;
//Csnfnndisplayilevia?rlr;

return0;
}
Taban snf ve tremi snflarda ayn isimli ilevler varsa, ar znrlk ileci ile
yaplmamsa, eer taban snf nesnesi ya da gstericisine ilikin bir ar sz konusu ise
doal olarak taban snfn ilevi arlr.
yle bir ilev olsun ki, bu ilev snf hiyerarisi iinde yer alabilecek bir nesnenin, hangi
snf trnden olursa olsun elemanlarnn deerlerini yazdrsn. Byle bir ilev nasl
tasarlanabilir? Taban snf trnden bir gstericiye, bu snftan tretilmi herhangi bir snf
nesnesinin adresi atanabileceine gre byle bir ilevin parametre deikeni taban snf
trnden bir gsterici olabilir. Global olarak tanmlanan display isimli ilevin bildirimi yle
olabilir:
voiddisplay(constA*ptr);
imdi display ilevi ister taban snf olan A snf trnden bir nesnenin adresiyle ister bu
snfta tremi snflar olan B ve C snfndan nesnelerin adresleri ile arlabilir.
Ancak byle bir ilev arld zaman iini doru yapabilmesi iin hangi snf trnden bir
nesnenin adresiyle arldn phesiz bilmek zorundadr. lev bu durumu nasl bilebilir?
Bunu salamann bir yolu u olabilir:
Taban snf bildiriminde, taban snfa bir eleman daha eklenenerek ve bu elemannn snf
trnden nesnenin tr bilgisini saklamas salanabilir.
enum{CLASSA,CLASSB,CLASSC};
classA{
//...
inttype;
public:
//
};
A snf ve bu snflardan tretilecek snflarn kodu, bir snf nesnesi yaratldnda snf
nesnesinin type isimli elemanna CLASSA, CLASSB, CLASSC vs. deerleri atanacak
biimde yazlabilir. Bu durumda global display ilevi, aadaki gibi bir switch deyimini
kullanarak iini grebilir.

205/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voiddisplay(constA*ptr)
{
switch(ptr>type){
caseCLASSA:((A*)ptr)>display();break;
caseCLASSB:((B*)ptr)>display();break;
caseCLASSC:((C*)ptr)>display();
}
//..
}
Ancak yukardaki kod parasnn ok nemli bir dezavantaj programn gelitirilmesi
srasnda ortaya kar. Taban snf olan A snfndan ya da tretilmi snflar olan B ve C
snflarndan yeni bir snf tretildiinde yukardaki display ilevinin bu yeni snf trnden
bir nesnenin de deerlerini yazdrmas istendiinde, display ilevinin kaynak kodunu
deitirmek gerekir. Bu da phesiz switch deyiminin iine yeni bir case daha eklemekle
mmkn olur. Ayrca yukardaki gibi bir kodu okumak zorlar. te sanal ilevler ve
alma zamanna ynelik ok biimlilik bu konuda yeni ufuklar aacak bir aratr.

Sanal levler
Snfn bir ye ilevi sanal (virtual function) yaplabilir. Bir ye ilevi sanal yapabilmek iin
ilev bildiriminin nne virtual anahtar szc getirilir. virtual anahtar szc yalnzca
ilevin bildiriminde kullanlr. lev tanmlanrken kullanlmaz. Bir global ilev ya da bir
snfn statik ilevi virtual anahtar szc ile bildirilemez. Bir ye ilev sanal yaplrsa, o
snfn tremi snflarnda bulunan ayn isimli, ayn bildirime sahip tm ilevler da sanal
olur. Yani virtual anahtar szc yazlmasa da yazlm gibi ilem grr. Ayn bildirime
sahip olmas demek geri dn deerlerinin parametre yaplarnn ve ilev isimlerinin ayn
olmas demektir. Tremi snfn taban snfn sanal ileviyle tamamen ayn parametrik
yapya sahip ve ayn isimli bir ilev tanmlamasna, tremi snfn taban snfn sanal ilevi
ezmesi (override) denir.
classBase{
//
public:
virtualintvfunc(int,int);
//
};
classDer:publicBase{
//
public:
public:
virtualintvfunc(int,int);
//
};
Yukardaki rnekte, Base snfndan tretilmi Der snf, Base snfnn sanal vfunc ilevini
eziyor. Der snf iinde bildirimi yaplan vfunc ilevinin bildiriminde virtual anahtar
szcnn kullanlmas zorunlu deildir.
Tremi snf nesnesinin adresi taban snf gstericisine atanr bu gsterici yoluyla da
sanal bir ilev arlrsa, adresi alnan nesne hangi snfa aitse o snfn sanal ilev arlr.
Hangi ilevin arlaca derleme zamannda deil ancak programn alma zamannda
belli olur. Bu yzden bu duruma "ge balama" (late binding) ya da dinamik balama
(dynamic binding) denir. Taban snfn tremi snfa erimesi ancak bu sanal ilev
kullanmyla mmkn olur. Bir dizi tretme yapldnda tremi snflardan birine ilikin
nesnenin adresi taban snflardan birine ilikin bir gstericiye ya da referansa atanabilir.
Bu gsterici ya da referans yoluyla sanal ilev arlabilir.
Bir sanal ilev snf ismi belirtilerek znrlk ileci ile arlrsa sanallk zellii kalmaz.

206/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Sanal levlerin arlma Biimleri


Sanal ilevler eitli biimlerde arlabilir. Bu biimleri gsterebilmek iin nce aadaki
snflar tanmlayalm:
classBase{
//...
public:
virtualvoidvfunc();
};
classDer:publicBase{
public:
virtualvoidvfunc();
};
1. Tremi snf nesnesinin adresinin ak bir biimde taban snf gstericisine atanmas
yoluyla:
intmain()
{
Derder_object;
Base*base_ptr;
base_ptr=&der_object;
base_ptr>vfunc();
(*base_ptr).vfunc();
return0;
}
Yukardaki rnekte
base_ptr>vfunc();
(*base_ptr).vfunc();
arlaryla Der snfnn vfunc ilevi arlr.
2. Bir ilevin parametre deikeni taban snf trnden bir gstericidir. lev de bir
tremi snf nesnesinin adresiyle arlr. Parametre deikeni olan gsterici yoluyla sanal
ilev arlabilir.
voidfunc(Base*ptr)
{
ptr>vfunc();
}
intmain()
{
Derder_object;
func(&der_object);
return0;
}
Yukardaki rnekte
func(&der_object);
deyimiyle arlan func ilevi iinde arlan vfunc ilevi Der snfnn vfunc ilevidir.

207/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

3. Taban snf trnden bir referans tremi snf trnden bir nesneyle ilkdeer verilerek
tanmlanr. Bu referans yoluyla sanal ilev arlabilir. Bu durumda tremi snfa ilikin
sanal ilev arlr.
intmain()
{
Derder_object(10,20);
Base&base_ref=der_object;
base_ref.vfunc();
return0;
}
Yukardaki rnekte
base_ref.vfunc();
deyimiyle arlan vfunc ilevi Der snfnn vfunc ilevidir.
4. levin parametre deikeni taban snf trnden bir referans olur. lev de tremi
snf nesnesinin kendisiyle arlr. lev iinde bu referans yoluyla tremi snfa ilikin
sanal ilev arlr.
voidfoo(Base&r)
{
r.vfunc();
}
intmain()
{
derder_object(10,20);
foo(der_object);
return0;
}
Yukardaki rnekte
foo(der_object);
deyimiyle arlan foo ilevi iinde arlan vfunc ilevi Der snfnn vfunc ilevidir.
5. Tremi snf trnden bir nesne ya da gsterici ile taban snfa ilikin sanal olmayan
bir ye ilev arlm olsun. arlan bu ye ilev iinde snfn sanal bir ilevine ar
yapldnda, ye ilev hangi snfa ilikin bir nesne iin arlmsa o snfa ilikin sanal
ilev arlr. Aadaki rnei inceleyin:

208/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include<iostream>
usingnamespacestd;
classBase{
//...
public:
virtualvoidvfunc(){cout<<"Base::vfunc()"<<endl;}
voidnfunc();
};
classDer:publicBase{
public:
voidvfunc(){cout<<"Der::vfunc()"<<endl;}
};
voidBase::nfunc()
{
cout<<"Base::nfunc()"<<endl;
vfunc();
}
intmain()
{
Derder_object;
der_object.nfunc();
return0;
}
Base snfndan Der isimli bir snf tretiliyor. Der snf Base snfnn vfunc isimli sanal
ilevini eziyor. Taban snfn sanal olmayan nfunc isimli bir ilevi olduunu gryorsunuz.
nfunc ilevi iinde sanal vfunc ilevi arlyor.
main ilevi iinde Der snf trnden der_object isimli bir nesnenin yaratldn
gryorsunuz. Bu nesne ile taban snfn nfunc ilevi arlyor. Bu durumda nfunc ilevi
iinde arlan Der snfnn vfunc ilevi olur.
Taban snf sanal ileve sahip olduu halde tremi snf sanal ileve sahip olmayabilir.
Yani tremi snfn taban snf olarak ald snftaki sanal ilevi ezmesi (override) zorunlu
deildir. Bu durumda taban snf gstericisine bir tremi snf nesnesinin adresi atanarak
sanal ilevi arlrsa, taban snfn ye ilevi arlr.
Sanal ileve sahip olmayan tremi snfa ilikin bir snf nesnesinin adresi taban
gstericisine atanr, bu gsterici yoluyla sanal ilev arlrsa tremi snfn sanal ileve
sahip ilk taban snfnn sanal ilevi arlr.

209/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include<iostream>
usingnamespacestd;
classA{
public:
virtualvoidfoo(){cout<<"A::foo"<<endl;}
};
classB:publicA{
public:
voidfoo(){cout<<"B::foo"<<endl;}
};
classC:publicB{
//...
};
classD:publicC{
//...
};
intmain()
{
Dd;
A*aptr=&d;
aptr>foo();
return0;
}
Yukardaki rnekte D snf trnden d nesnesinin adresi A snf trnden aptr gsterici
deikenine atanyor. aptr gstericisi ile sanal foo ilevi arldnda, B snfnn foo ilevi
arlr. nk D snf ve D snfnn dorudan taban snf olan C snf sanal ilev olan foo
ilevini ezmitir. Hiyerari iinde ilevi ilk ezen snf B snf olduu iin arlan ilev de B
snfnn ilevidir.

private Sanal levler


Sanal ilev arlabilmesi iin tretme biiminin public olmas gerekir. Bir sanal ilev
arldnda gerekte arlacak olan tremi snfn sanal ilevi tremi snfn herhangi
bir blmnde olabilir. Ancak ar rnein taban snf trnden bir referans ya da
gsterici ile yaplyorsa, arlan ilev taban snfn sanal public blmde olmak
zorundadr. rnein:
Base*base_ptr
Derder_object;
baseptr=&derObject;
baseptr>vfunc();
Burada vfunc sanal bir ilev olsun, gerekte arlacak olan ilevin hangi snfn vfunc
ilevi olduu programn alma zamannda belirlenir. Ancak vfunc ilevinin taban snfn
hangi blmnde bildirildii derleme zamannda aratrlr. Der snfnn vfunc sanal ilevi
Der snfnn herhangi bir blmnde bildirilmi olabilir, ancak arnn geerli olabilmesi
iin Base snfnn vfunc sanal ilevinin Base snfnn public blmnde bildirilmi olmas
gerekir.

Sanal lev armann Nedenleri


Sanal ilev armann balca iki faydal nedeni vardr:

210/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

1. Bir snfn ilevini deitirmek


2. Trden bamsz ilemler yaplmasna olanak salamak
rnein A gibi bir snf varsa, bu snf belirli ilemleri yapyorsa, bu snfa hi dokunmadan
snfn yapt ilemler zerinde deiiklik yaplmas salanabilir.
Snf hiyerarisi iinde snfa ilikin bir i yapan ilevin, nesnesinin hangi snftan olduunu
saptayarak i yapmasna dayanan tasarmlar kt tekniktir. Bu tr kodlar yerine sanal
ilev mekanizmasn kullanmak daha iyi tekniktir.
Snf hiyerarisine zaman iinde yeni snflar katlabilir. Snf hiyerarisine yeni bir snf
eklendiinde yalnzca eklenen snfn kodlar yazlr, genel ilem yapan ilevlerin kodlarnda
bir deiiklik yaplmas gerekmez. Sanallk mekanizmasnn yeni snf da kapsamas iin
daha nce yazlm kaynak kodlarda da bir deiiklik yaplmas gerekmez. Byle bir
kolaylk olmasayd bakasnn tasarlad ve yazd snf hiyerarilerine yeni tretmelerle
ekleme yapld zaman, faydalanlan snflarn yalnzca balk dosyalarna deil kaynak
kodlarna da sahip olmak gerekirdi.
Sanal ilevler kullanlarak bir snf hiyerarisi iinde yer alan snflarn ortak zelliklerine
dayanarak kod yazlabilir.

Sanallk Devreden kartlmas


Sanal bir ilevin arlmas hakkndaki kararn programn alma zamannda deil de
(late binding) derleme zamannnda verilmesi (early binding) isteniyorsa, sanal ilev snf
ismi ve znrlk ileci yardmyla arlabilir:
#include<iostream>
classBase{
intb;
public:
Base(intval=0):b(val){}
virtualvoiddisplay()const{std::cout<<b<<std::endl;}
};
classDer:publicBase{
intd;
public:
Der(intval1=0,intval2=0):Base(val1),d(val2){}
voiddisplay()const{std::cout<<d<<std::endl;}
};
intmain()
{
Base*base_ptr;
DerderObject(10,20);
base_ptr=&derObject;
base_ptr>Base::display(); //Basesnfnndisplayilevia?rlr!
return0;
}

Sanal lev Kullanlmasna likin rnekler


1. ngilizce yazlar zerinde ilem yapan bir Cstring snf olsun. Bu snfn yazlar
karlatran, byk harf ya da kk harfe dntren ye ilevleri olsun. Yazlarn
karlatrlmas ve harf dnmnn yaplmas dile bal bir durumdur. Cstring snfnn
compare isimli karlatrma ilevi karlatrma ilemini yaparken iki karakteri
karlatran sanal cmpchr ilevini aryor olsun. Cstring snfndan bir snf tretilir.

211/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


cmpchr sanal ilevi tretilmi snf iin yeniden yazlrsa, artk compare ilevi tremi
snfn cmpchr ilevini arr. Bylece ilemler baka bir dilde de doru bir biimde
yaplabilir.
2. Bir dizinin Array isimli bir snf ile temsil edildiini dnelim. Bu snfn sraya dizme
ilemini yapan sort isimli sanal bir ilevi olsun. Baz ye ilevler de bu ilevi ararak
sralama ilemini gerekletiriyor olsunlar. Sralama algoritmalar ok eitli olabilir. Array
snfndan bir tretme yaplarak, tretilen snfn sanal ilevi baka bir sralama
algoritmasn kullanacak biimde yeniden yazlabilir. Bu durumda sralama ilemi istenilen
algoritmayla yaplabilir.
3. MFC snf sisteminde her trl pencere ilemleri CWnd snf tarafndan yaplmaktadr.
Diyalog penceresi de zel bir tr penceredir. Diyalog penceresi ilemleri CWnd snfndan
tretilen CDialog snf ile yaplmaktadr. Her diyalog penceresi dierinden farkl zelliklere
sahip olabilir. O ilemler de CDialog snfndan tretilen snfla temsil edilir.
Diyalog penceresini grnr hale getirmek iin CDialog snfnn DoModal ilevi arlr.
CDialog snfnn OnOk ve OnCancel sanal ilevleri de vardr. CWnd snfndan tretilen bir
snfa ilikin bir nesne tanmlandnda CWnd snfnn kurucu ilev ile yaratlan nesnenin
adresi MFC sistemi tarafndan global bir biimde saklanr. Ne zaman bir diyalog
penceresinde OK ya da Cancel tularna baslrsa MFC saklam olduu adresle OnOk ya
da OnCancel ilevlerini arr. Eer bu ilevler yeniden yazlrsa yeniden yazlan arlr.
Tabii orjinal OnOk ve OnCancel ilevleri kritik baz ilemleri de yapmaktadr. Bu durumda
bu ilevlerin dorudan arlmalar da gerekebilir.
voidMyDialog::onOk()
{
CDialog::OnOk();
//...
}

Sanal lev Mekanizmasnn Oluturulmas


Bir tremi snf nesnesinin adresi taban snf gstericisiyle ilevden ileve dolatrlm
olabilir. En sonunda sanal ilev arlm olsa bile nesnenin ait olduu snfa ilikin sanal
ilev arlr. Peki derleyici bu olay derleme srasnda belirleyebilir mi? Bu olayn derleme
srasnda saptanmas mmkn deildir. levlerin kodunun yrtlmesi programn alma
zamannda gerekleir. Gerekte hangi sanal ilevin arlacan belirlemek ancak
programn alma zaman srasnda kurulacak bir mekanizmayla mmkn olabilir. Bu
mekanizmann alma zamannda kurulmasna ingilizce "late binding" ya da "dynamic
binding" denir. Hangi ilevin arlacana programn alma zamannda deil de derleme
zamannda karar verilmesine ise ingilizcede "early binding" ya da "static binding" denir.
Aadaki kodu inceleyin:

212/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include<iostream>
#include<cstdlib>
#include<ctime>
classCalisan{
public:
virtualvoidkendini_tanit(){std::cout<<"Bencalisanim"<<
std::endl;}
};
classMudur:publicCalisan{
public:
virtualvoidkendini_tanit(){std::cout<<"Benmudurum"<<std::endl;}
};
classGenelMudur:publicMudur{
public:
virtualvoidkendini_tanit(){std::cout<<"Bengenelmudurum"<<
std::endl;}
};
classSekreter:publicCalisan{
public:
virtualvoidkendini_tanit(){std::cout<<"Bensekreterim"<<
std::endl;}
};
classSofor:publicCalisan{
public:
virtualvoidkendini_tanit(){std::cout<<"Bensoforum"<<std::endl;}
};
classIsci:publicCalisan{
public:
virtualvoidkendini_tanit(){std::cout<<"Benisciyim"<<std::endl;}
};
Calisan*calisan_yarat()
{
Calisan*pd;
switch(rand()%5){
case0:pd=newMudur;break;
case1:pd=newGenelMudur;break;
case2:pd=newSekreter;break;
case3:pd=newSofor;break;
case4:pd=newIsci;
}
returnpd;
}
intmain()
{
srand(time(0));
for(intk=0;k<20;++k){
Calisan*pd=calisan_yarat();
pd>kendini_tanit();
deletepd;
}

213/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Yukardaki rnekte Calisan snfndan Mudur snf, Mudur snfndan GenelMudur snf
tretiliyor. Calisan snfndan ayrca Sekreter, Sofor ve Isci snflar tretiliyor. Tretilen
tm snflar Calisan snfnn sanal kendini_tanit isimli ilevini eziyor. Global calisan_yarat
ilevi iinde, tretme hiyerarisi iinde yer alan snflardan birine ait rastgele bir dinamik
nesnenin yaratldn gryorsunuz. rand ilevinin rettii rastgele deere gre yaratlan
dinamik nesnenin tr Mudur, GenelMudur, Sekreter, Sofor, Isci olabilir. Dinamik
nesnenin hangi trden olaca programn alma zamannda belli olur. calisan_yarat
ilevi yaratilan dinamik snf nesnesinin adresini dndryor.
main ilevi iinde bir dng iinde nce calisan_yarat ilevi arlarak elde edilen adres
Calisan snf trnden bir gsterici deikende tutuluyor. Sonra bu gsterici deikenle
sanal ilev kendini_tanit arlyor. arlan kendini_tanit ilevi hangi snfn sanal
ilevidir?
Peki hangi ilevin arlacann alma zamannda belirlenmesi nasl mmkn oluyor?
Sanal ilev ar mekanizmasnn derleyiciler tarafndan ne ekilde salanaca standart
olarak belirlenmemitir. Yani derleyiciler bu mekanizmay istedikleri gibi oluturabilir.
Ancak derleyicilerin ou bu mekanizmay kurabilmek iin her snfa ilikin bir sanal ilev
tablosu yaratr. Bu tablolar ksaca vtable (virtual table) olarak isimlendirilir. Bu sanal ilev
tablolarnda ilgili snfn sanal ilevlerin adresleri bulunur. Sanal ileve sahip bir snfa
ilikin bir nesne tanmlandnda o nesne iin bir gizli ilev gstericisi kadar daha ek yer
ayrlr. Bu gizli gstericide snfn sanal ilev tablosunun adresi tutulur. Bu gizli
gstericinin nesnenin neresinde tutulduu standart olarak belirlenmemitir. Ancak
popler derleyicilerin hemen hemen hepsinde nesnenin en dk anlaml adresinde
tutulur.
Base Snfnn Sanal lev Tablosu
Sra No Adres
1
&Base::func1()
2
&Base::func2()
Der1 Snfnn Sanal lev Tablosu
Sra No Adres
1
&Der1::func1()
2
&Der2::func2()
Der2 Snfnn Sanal lev Tablosu
Sra No Adres
1
&Der2::func1()
2
&Der2::func2()
Bu durumda bir sanal ilev arldnda aa seviyeli u ilemler yaplr:
1. Sanal ilev gstericisi (vpointer) alnr. Sanal ilev tablosunun yeri (vtable) bulunur.
2. Sanal ilev tablosunda ilgili sanal ilevin adresi bulunur.
3. Adresi bulunan sanal ilev arlr.

Sanal levlerin Maliyeti


Sanal ilev mekanizmas phesiz ek bir bellek kullanmna ve daha fazla ilemci
zamanna neden olur. Ek bir bellek kullanm sz konusudur. nk her okbiimli snf
iin bir sanal ilev tablosu ve her okbiimli snf nesnesi iin sanal ilev tablo gstericisi
bellekte fazladan bir yer kaplar. Sanal ilevin arlabilmesi iin nce sanal ilev
tablosunun adresinin alnarak tabloya eriilmesi ve tablodan da arlacak ilevin
adresinin alnmas gerekir. Yani fazladan iki "ierik alma" (indirection) ilemi yaplr. Ancak
ortalama bir uygulama programnda sanal ilevlerin getirdii ek bellek ve zamansal
maliyet yok saylabilir. Sanal ilevlerin kazandrd faydann yannda getirdii ek
maliyetler gerekten nemsenmeyecek boyuttadr.

214/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Sanal Sonlandrc levler


Bir snf hiyerarisi iinde dinamik olarak yaratlan snf nesneleri iin alma zamanna
ilikin okbiimliliin uygulanmasnda baz istenmeyen durumlar ortaya kabilir.
Daha nceki blmlerden hatrlayacanz gibi new ileciyle snf trnden bir nesne
yaratld zaman ilgili snfn kurucu ilevi arlr. delete ileciyle dinamik olarak yaratlan
nesneye ilikin blok free storea geri verildiinde ilgili snf nesnesi iin sonlandrc ilevi
arlr. Aadaki kodu inceleyin:
classBase{
char*base_ptr;
public:
Base();
~Base();
};
#include<iostream>
usingnamespacestd;
Base::Base()
{
cout<<"Base::Base()"<<endl;
base_ptr=newchar[1000];
cout<<"Base::Base()icinde1000byte'lkblokeldeedildi!"<<endl;
}
Base::~Base()
{
cout<<"Base::~Base()"<<endl;
delete[]base_ptr;
cout<<"Base::~Baseicinde1000byte'likblokgeriverildi!"<<endl;
}
classDer:publicBase{
char*der_ptr;
public:

Der();

~Der();
};
Der::Der()
{
cout<<"Der::Der()"<<endl;
der_ptr=newchar[2000];
cout<<"Der::Der()icinde2000byte'lkblokeldeedildi!"<<endl;
}
Der::~Der()
{
cout<<"Der::~Der()"<<endl;
delete[]der_ptr;
cout<<"Der::~Dericinde2000byte'likblokgeriverildi!"<<endl;
}
intmain()
{
Base*ptr=newDer;
deleteptr;

215/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


return0;
}

altrlan programn ekran kts:


Base::Base()
Base::Base()icinde1000byte'lkdinamikblokeldeedildi!
Der::Der()
Der::Der()icinde1000byte'lkdinamikblokeldeedildi!
Base::~Base()
Base::~Baseicinde1000byte'likblokgeriverildi!

216/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Snfn sonlandrc ilev (virtual destructor) da snfn bir ye ilevi olduuna gre, delete
ilecinin terimi olan adres hangi snf trnden ise o snfn sonlandrc ilevi arlr.
Yukardaki programda dinamik olarak yaratlan tremi snf (Der) trnden adres, taban
snf trnden ptr gstericisine atanyor. Ancak delete ilecinin terimi ptr olduundan
doal olarak taban snfa (Base) ilikin sonlandrc ilev arlr. Baz durumlarda dinamik
yaratlan snf nesnesi iin, tremi snfn deil taban snfn sonlandrc ilevinin
arlmas programn tamamen yanl ya da zararl bir ekilde almasna neden olabilir.
rnein tremi snf nesnesi taban snf alt nesnesinin dnda ayr bir kaynak kullanyor
olabilir. Tremi snf nesnesine bu kaynak, tremi snfn kurucu ilevinin arlmasyla
balanr. Tremi snf nesnesine ilikin sonlandrc ilevi, nesneye balanan kayna geri
veriyor ya da serbest brakyor olabilir. Tremi snfn sonlandrc ilevi arlmad
zaman balanan kaynan geri verilme ilemi de yaplamaz.
Sonlandrc ilevler de virtual anahtar szc ile bildirilebilir. Bu durumda sonlandrc
ilev, tpk dier sanal ilevler gibi ok biimli davran gsterir.
Yukardaki kod parasnda taban snfn sonlandrc ilevinin bildirimine virtual anahtar
szcn ekleyelim:
classBase{
public:
virtual~base();
//
};

Artk Base snf trnden bir gsterici delete ilecinin terimi yapldnda, gsterici
deikene hangi snf trnden bir adres atanmsa o snfa ilikin sonlandrc ilev
arlr. Yani yukardaki deiiklikten sonra, altrlan programda arlan Base snfnn
deil Der snfnn sonlandrc ilevi olur.
Tremi snf sonlandrc ilevinin kodunun yrtlmesinin sonunda tremi snf
nesnesinin taban snf ksm iin taban snfn sonlandrc ilevinin de arlacan
unutmayalm. Yoksa bu kez de taban snf nesnesine balanm kaynaklar serbest
braklamazd. Yukardaki deiiklikten sonra program altrldnda ekrana
Dersnfnnsonlandrcilevia?rld!..
Basesnfnnsonlandrcilevia?rld!..
yazar.
Genel olarak u kural verilebilir: Bir snfn eer en az bir sanal ilevi varsa, snfn
sonlandrc ilevi de sanal yaplmaldr. ou zaman sanal sonlandrc ilev bir koda sahip
olmaz ve bo olarak tanmlanr. Bu durumda ilev snfn inline ilevi olarak yazlr.
classMyclass{
public:
virtualvoidfunc();
virtual~Myclass(){}
};

Saf Sanal levler


Bir snf hiyerarisi oluturulmasnn ou zaman amac, mantksal olarak iliki halindeki
snflarn ortak olarak paylalabilecek kodlarn bir taban snf iinde toplamaktr. Bylece
genel ilem yapan kodlar en tepedeki taban snfa gre yazlabilir. Daha nce yazlan
kodlar, daha sonra yazlacak kodlar yani tretilmi snflara ilikin kodlar arabilir.
Ancak bazen taban snflar, kendilerinden tretilecek snflara yalnzca bir arayz
salamak amacyla oluturulur. Ama taban snfn salad arayze ilikin tremi

217/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


snflara sunaca bir kodun (implementasyon) varl sz konusu olmayabilir. Baka bir
deyile taban snf, kendisinden tretilecek snflara kendi arayzn vermekte ancak bu
arayze ilikin kodlar tremi snfn kendisinin tanmlamasn istemektedir.
rnek olarak Shape isimli bir snf tanmlandn ve bu snftan Triangle, Square, Circle
snflarnn tretildiini dnelim. Shape snfnn draw isimli bir sanal ye ilevi olsun:
classShape{
public:
//...
virtualvoiddraw()const;
//...
};
Bir ilevin sanal olmas ne anlama gelir? Sanal bir ilev tremi snf tarafndan ezilebilir
(override edilebilir). Ancak bu bir zorunluluk deildir. Tremi snf taban snfn
tanmlad sanal ilevi ezmez ise tremi snfa ilikin bir nesne ile sanal ilev
arldnda, taban snfn ye ilevi arlr. Tasarm asndan bakldnda bu durumun
anlam udur: Sanal bir ilev, hem arayz hem de default kodu (default implementation)
devir alnan bir ilevidir. Sanal bir ilevin tremi bir snfa verdii ileti udur: "Beni
istediin gibi tanmlayabilirsin. Tanmlarsan, senin tanmladn arlr, ancak
tanmlamaz isen arlan ben olacam!"
Yine Shape snfna dnelim. Shape snfndan treyecek snflar draw ilevini ezmezlerse
taban snfn tanmlad draw ilevi arlr. Peki Shape snfnn draw ilevi ne yapabilir?
Bir karenin ya da bir genin izilmesi mantksal olarak bir anlam tar. Ama bir "ekil" in
izilmesi ne demektir? Shape snfnn draw ilevi iin salayabilecei bir kod paras
yoktur. Shape snf draw ilevini yalnzca tremi snflar iin bir arayz oluturmas
amacyla bildirmitir.
Evet baz durumlarda bir taban snf sanal ilevinin bildirilmesinin tek nedeni kendisinden
tretilecek snflara uygun bir arayz sunmaktr. Bu nedenle taban snf sanal ilevinin
tanmnn yaplmas mantkl deildir.
C++'da bu durum saf sanal (pure virtual) ilevlerle gerekletirilir.
Bir ilevin saf sanal olarak bildirilmesi ilevin bildiriminde ileve atama ilecinin
kullanlarak 0 deerinin atanmasyla gsterilir. Bu gerek bir atama ilemi deildir.
Yalnzca bildirilen ilevin saf sanal olduunu gsteren bir szdizim kuraldr.
classShape{
public:
virtualvoiddraw()=0;
//...
};

//safsanalilev

Yukarda tanmlanan Shape snfnn draw isimli ilevi saf sanal yaplm. Saf sanal bir
ilev, kendisinden tretilecek snflara arayz salayan, kendi kodu olmayabilen bir
ilevdir.
Saf sanal ilevin tanmlanmamas durumunda balama zamannda bir hata olumaz. Peki
saf sanal ilevin tanmlanmas geerli bir durum ise, bir taban snf nesnesi ile taban
snfn saf sanal ilev arldnda ne olur?
En az bir saf sanal ilev ieren snfa soyut snf (abstract class) denir. Bir soyut snf
trnden nesne yaratlamaz. Bir soyut snf trnden nesne yaratlmas durumunda
derleme zamannda hata oluur. Aadaki kodu inceleyin:

218/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classShape{
public:
virtualvoiddraw()=0;
};

//safsanalilev

intmain()
{
Shapemyshape;
//Geersiz!
Shape*shape_ptr=newShape; //Geersiz!
return0;
}

Yukardaki main ilevi iinde yazlan her iki deyim de geersizdir. Her iki deyimde de soyut
Shape snf trnden bir nesne yaratlmak istenmitir.
Tremi snf taban snfn saf sanal ilevini ezmelidir. Ezmezse, arlacak bir taban snf
ilevi yoktur. Tremi snf bir soyut snfn herhangi bir saf sanal ilevini ezmezse, bu
durumda tremi snf da soyut olur. Yani tremi snf trnden de bir nesne
tanmlanamaz. Saf sanal bir ilevin kendisinden tretilecek snflara verdii ileti udur:
"Beni tanmlaman gerekiyor. nk ben yalnzca bir arayzm. Beni tanmlamaz isen sen
de benim gibi bir soyut snf olursun. Senin trnden de nesne yaratma olana olmaz."
Soyut bir snf trnden nesne yaratlmaz, ancak phesiz soyut bir snf trnden bir
gsterici deiken ya da referans tanmlanabilir. Bylece snf hiyerarisi zerinde ortak ve
genel ilem yapacak kodlar, yine soyut taban snf trnden referanslar ya da gsterici
deikenler kullanlarak yazlabilir.
Aadaki Shape snfnn bildiriminde yer alan draw ve write_shape_name isimli saf sanal
ilevler, tretilmi snflar tarafndan yeniden tanmlanyor:
classShape{
public:
virtualvoiddraw()const=0;
virtualvoidwrite_shape_name()const=0;
};
Shape snfndan dorudan ya da dolayl olarak tretilmi snflardan herhangi birine ait
bir nesne zerinde ilemler yapmak zere tanmlanan process isimli global bir ilevin
yazldn dnelim:
voidprocess(Shape&r)
{
r.write_shape_name();
r.draw();
}
process ilevine hangi snf trnden nesne gnderilirse o nesnenin write_shape_name ve
draw ilevleri arlr. Shape snfnn ve process ilevinin yazlmasndan yllarca sonra
bile, Shape snfndan yeni bir snf tretilip o tremi snf trnden bir nesne tanmlansa,
o nesne ile process ilevi arldnda mantksal olarak istenen i yaplr. Yani process
ilevi iinde yeni tretilmi snfa ilikin write_shape_name ve draw ilevleri arlr.
Shape snfnn ara yz saf sanal ilevleriyle, tretilecek snflarn tanmlamasnn zorunlu
olduu ye ilevlerini gsterir.
Bir snf soyut deil ise, yani bir snf trnden nesne tanmlanabiliyor ise bu snfa somut
snf (concrete class) denir.
Bir saf sanal ilevin tanmlanmamas, derleme ya da balama aamasnda bir hata
oluturmaz. Ancak saf sanal ilevler istenirse tanmlanabilir. Programc tretme hiyerarisi

219/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


iin ortak olan bir kod parasn isterse taban snfn saf sanal ilevi iinde toplayabilir. Bu
durum az da olsa baz kod kalplarnda karmza kar.

Saf Sanal Sonlandrc levler


Sonlandrc ilevler de saf sanal olarak bildirilebilir. Ancak saf sanal sonlandrc ilevlerin
dier saf sanal ilevlere gre nemli bir fark vardr. Bu ilevler tanmlanmak zorundadr.
Eer tanmlanmazlar ise bu snftan tremi bir somut snf trnden bir nesne
yaratldnda balama zamannda hata oluur. Tremi snf nesnesinin sonlandrc
ilevinin kodu sonunda taban snfn sonlandrc ilevinin arldn hatrlayalm. Taban
snfn sonlandrc ilevi saf sanal da olsa, ilevin tanm yoksa, ilev ars balayc
tarafndan hata olarak iaretlenir. Aadaki kod parasnda saf sanal sonlandrc ilevin
de normal sonlandrc ilevler gibi arld gsteriliyor:
#include<iostream>
classShape{
public:
virtual~Shape()=0;
};
Shape::~Shape()
{
std::cout<<"Shape::~Shape()"<<std::endl;
}
classSquare:publicShape{
public:
~Square(){std::cout<<"Square::~Square()"<<std::endl;}
};
intmain()
{
{
Squares;
}
Shape*ptr=newSquare;
deleteptr;
return0;
}
Programn ekran kts:
Square::~Square()
Shape::~Shape()
Square::~Square()
Shape::~Shape()
Taban snfn saf sanal bir ilevinin tremi snf tarafndan ezilmemesi durumunda
tremi snfn da soyut snf olur. Ancak bu kural saf sanal sonlandrc ilev iin geerli
deildir. Yani taban snfn saf sanal sonlandrc ilevini tremi snf ezmese de soyut snf
olarak ele alnmaz. Halen tremi snf trnden bir nesne tanmlanabilir. Soyut bir snfn
tek saf sanal ilevinin saf sanal sonlandrc ilev olmas durumu zel bir durumdur. Zira
bu durumda tremi snf bu ilevi yeniden tanmlamasa da soyut bir snf olarak ele
alnmaz. Yani taban snftan tretilen btn snflar somut snflar olarak ele alnr.

Kurucu levler inde Yaplan Sanal lev arlar


220/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Bir snfn kurucu ilevi iinde sanal bir ilev arlrsa sanallk mekanizmas devreye
girmez. Aadaki kodu inceleyin:
#include<iostream>
classBase{
//...
public:
Base();
virtualvoidvfunc();
};
usingnamespacestd;
Base::Base()
{
cout<<"Base::Base()"<<endl;
vfunc();
}
voidBase::vfunc()
{
cout<<"Base::vfunc()"<<endl;
}
classDer:publicBase{
public:
Der();
voidvfunc();
};
Der::Der()
{
cout<<"Der::Der()"<<endl;
}
voidDer::vfunc()
{
cout<<"Der::vfunc()"<<endl;
}
intmain()
{
Derder_object;
return0;
}
Yukardaki rnekte Base snfndan tretilen Der snf Base snfnn vfunc ilevini eziyor.
main ilevi iinde Der snf trnden bir nesne tanmlandn gryorsunuz. Der snfnn
kurucu ilevinin banda taban snf olan Base snfnn kurucu ilevi arlr. Base snfnn
kurucu ilevi iinde sanal vfunc ilevi arlyor.
vfunc();
ars aslnda

221/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


this>vfunc();
arsdr.
Normal olarak this gstericisi iinde Der snf trnden bir adres olduuna gre arlan
vfunc ilevini tremi snfn vfunc ilevi olmas gerekir. Ancak arlan Der snfnn deil
Base snfnn vfunc ilevidir. Bu C++ dilinin bir kuraldr. Peki kurucu ilev iinde neden
sanallk mekanizmas devreye girmiyor? Tremi snf nesnesi yaratldnda nce taban
snf ksm oluturulur. Bu da taban snfn kurucu ilev tarafndan yaplr. Taban snfn
kurucu ilevi iinde arlan sanal ilev tremi snfn sanal ilevi olsayd, bu durumda bu
ilev ilkdeerini almam elemanlar zerinde ilem yapmak durumunda kalabilirdi.
Tremi snf nesnesinin baz kaynaklar kullandn dnelim. Bu kaynaklar tremi snf
nesnesine tremi snf nesnesinin kurucu ilevi tarafndan balanr. vfunc ilevi iinde bu
kaynaklarn kullanldn dnelim. Eer sanallk mekanizmas devreye girseydi, tremi
snfn vfunc ilevi bu kaynaklar henz nesneye balanmadan bu kaynaklar kullanmaya
alrd. Bu da alma zaman hatalarna neden olurdu.

Sonlandrc levler inde Yaplan Sanal lev arlar


Benzer durum sonlandrc ilevler iin de geerlidir. Bir sonlandrc ilev iinde sanal bir
ilev arldnda sanallk mekanizmas devreye girmez. Aadaki rnei inceleyin:

222/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classBase{
public:
~Base();
virtualvoidvfunc();
//...
};
#include<iostream>
usingnamespacestd;
Base::~Base()
{
std::cout<<"Base::~Base()"<<std::endl;
vfunc();
}
voidBase::vfunc()
{
std::cout<<"Base::vfunc()"<<std::endl;
}
classDer:publicBase{
public:
~Der();
voidvfunc();
//...
};
Der::~Der()
{
std::cout<<"Der::~Der()"<<std::endl;
}
voidDer::vfunc()
{
std::cout<<"Der::vfunc()"<<std::endl;
}
intmain()
{
Derder_object;
return0;
}
main ilevi iinde yaratlan der_object nesnesinin mr sona erdiinde bu nesne iin
sonlandrc ilev arlr. Der snfnn sonlandrc ilevinin kodunun sonunda derleyici
tarafndan eklenen kod ile taban snf olan Base snfnn sonlandrc ilevi arlr. Base
snfnn sonlandrc ilevi iinde yaplan vfunc arsnda sanallk mekanizmas devreye
girmez. Taban snfn sonlandrc ilevi arldnda artk tremi snf nesnesi ksm yok
edilmitir. Eer sanallk mekanizmas devreye girseydi, yani tremi snfn vfunc ilevi
arlsayd, bu ilev artk var olmayan kaynaklar zerinde ilem yapmaya alabilirdi. Bu
da alma zaman hatalarnn olumasna neden olurdu.

Taban Snf Nesnesiyle Yaplan Sanal lev ars


Sanal ilev mekanizmasnn devreye girmesi iin sanal ilev arsnn bir gsterici ya da
bir referans yoluyla yaplmas gerekir. Bir tremi snf nesnesi bir taban snf nesnesine

223/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


atandktan sonra taban snf nesnesiyle bir sanal ilev arlrsa sanallk mekanizmas
devreye girmez. Aadaki rnei inceleyin:
#include<iostream>
classBase{
public:
virtualvoidvfunc()const{std::cout<<"Base::vfunc()"<<std::endl;}
};
classDer:publicBase{
public:
voidvfunc()const{std::cout<<"Der::vfunc()"<<std::endl;}
};
voidfunc1(Baseb)
{
b.vfunc();
}
voidfunc2(Base*ptr)
{
ptr>vfunc();
}
intmain()
{
Derder;
func1(der);
func2(&der);
return0;
}
main ilevi iinde yaplan
func1(der);
arsnda sanallk mekanizmas devreye girmez. func1 ilevi deerle arlyor. Argman
olan der nesnesi ilevin parametre deikeni olan Base trnden b nesnesine atanrken
nesne dilimlenir (object slicing). levin parametre deikeni olan b nesnesi ile yalnzca
Base snfnn vfunc ilevi arlabilir. Oysa
func2(&der);
arsnda sanallk mekanizmas devreye girer, nk func1 ilevi adresle arlmtr.
Programn alma zamannda *ptr nesnesi hangi trden ise, o snfn vfunc ilevi arlr.

Kurucu levler Sanal Olabilir mi


Bir snfn kurucu ilevi sanal olamaz. virtual anahtar szcnn bir kurucu ilevin
bildiriminde kullanlmas bir szdizim hatasdr. Ancak baz uygulamalarda "sanal bir
kurucu ileve" gereksinim duyulur. Aadaki gibi bir ilevin varln dnelim:

224/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidfunc(Base*base_ptr)
{
Base*d_object=//new(base_ptr'niniindehangisnftrnden//adres
varsaosnftrndenbirdinamiknesneyaratlacak)
//..
}
Yukardaki func ilevinin taban snf trnden bir gstericiye ya da referansa sahip
olduunu dnelim. Taban snf trnden bir gstericiye herhangi bir tremi snf
trnden nesnenin adresinin atanabileceini biliyorsunuz. func ilevi snf hiyerarisi
iinde hangi snf trnden bir nesnenin adresi ile arlrsa ilev iinde o snf trnden
dinamik bir nesne yaratlmak istendiini dnelim. Bu nasl yaplabilir? Adeta sanal bir
kurucu ileve gereksinim duyuluyor. Bu durumu salamak iin kullanlan idiyoma "sanal
kurucu ilev idiyomu" (virtual constructor idiom) denir. Aadaki kod parasn inceleyin:
#include<iostream>
classBase{
public:
virtualBase*create_similar()const=0;
virtualBase*clone()const=0;
virtual~Base(){}
//...
};
classDer1:publicBase{
public:
Der1(){std::cout<<"Der1::Der1()"<<std::endl;}
Base*create_similar()const{returnnewDer1;}
Base*clone()const{returnnewDer1(*this);}
//...
};
classDer2:publicBase{
public:
Der2(){std::cout<<"Der2::Der2()"<<std::endl;}
Base*create_similar()const{returnnewDer2;}
Base*clone()const{returnnewDer2(*this);}
//...
};
classDer3:publicBase{
public:
Der3(){std::cout<<"Der3::Der3()"<<std::endl;}
Base*create_similar()const{returnnewDer3;}
Base*clone()const{returnnewDer3(*this);}
};
voidfunc(Base*ptr)
{
Base*ptr1=ptr>create_similar();
Base*ptr2=ptr>clone();
deleteptr1;
deleteptr2;
}
usingnamespacestd;
intmain()

225/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


{
cout<<"Der1,Der2veDer3nesneleriyaratiliyor."<<endl;
Der1der1;
Der2der2;
Der3der3;
cout<<"Herbirnesnesirasiylafuncilevinegonderiliyor"<<endl;
func(&der1);
func(&der2);
func(&der3);
return0;
}
Taban snf olan Base snf iinde isimleri create_similar ve clone olan iki saf sanal ilev
bildiriliyor. Base snfndan treyen her snf create_similar ve clone sanal ilevlerini ezer.
Base snfndan treyen her snf -rneimizde Der1, Der2 ve Der3 snflar- ezdikleri
create_similar ilevlerini kendi snflar trnden dinamik bir nesnenin adresiyle geri
dndrr. clone ilevinin tek fark ise adresi dndrlen dinamik nesnenin varsaylan
kurucu ilev ile deil kopyalayan kurucu ilevle ilkdeerini almasdr. Yani clone ilevi
hangi snf nesnesi iin arlma o nesnenin deerine eit deerde dinamik bir nesnenin
adresini dndrr. Bylece taban snf trnden bir gsterici ya da referans ile sanal
create_similar ya da clone ilevleri arldnda, sanal ilev mekanizmas devreye girer.
Taban snf gstericisi iinde hangi nesnenin adresi varsa o snfn sanal ilevinin
arlmasyla o snf trnden bir dinamik nesne yaratlm olur.

Sanal levler ve Varsaylan Argmanlar


Sanal ilevler de varsaylan argman alabilir. Taban snfn sanal ilevini ezen tremi snf
ilevi farkl bir varsaylan argmanla bildirilebilir:
#include<iostream>
classBase{
public:
virtualvoidfunc(intval=20){std::cout<<"val="<<val<<
std::endl;}
};
classDer:publicBase{
public:
virtualvoidfunc(intval=100){std::cout<<"val="<<val<<
std::endl;}
};
intmain()
{
Derder;
Base*bptr=&der;
bptr>func();
return0;
}
Yukardaki rnekte bptr gstericisine Der snf trnden der isimli nesnenin adresi
atanyor. Daha sonra bptr gstericisi ile sanal func ilevi argman gnderilmeden
arlyor. leve varsaylan argman olarak hangi deer geilir? 20 mi 100 m? Sanal
ilevin balanmas programn alma zamannda olsa da, varsaylan argman

226/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


degerlendirilmesi programn derleme zamannda yaplr. Yukardaki program
altrldnda ekrana 20 deeri yazdrlr.

Ezilen Bir Sanal levin Parametrik Yaps


Taban snfn bir sanal ilevinin tremi snf tarafndan ezilmesi iin tremi snfn
tamamen ayn parametrik yapya sahip bir ilev bildirmesi gerekir. Tremi snfn
bildirdii ilevin imzasnda bir farkllk olursa, tremi snf taban snfn sanal ilevini
ezmi olmaz. Yeni bir ilev bildirmi olur. Tremi snfn bildirdii ilevin imzas taban
snfn sanal ilevi ile ayn fakat geri dn deeri tr farkl ise bu durum derleme
zamannda hata olarak deerlendirilir:
classBase{
public:
virtualintfunc1(int);
virtualintfunc2(int);
virtualintfunc3(int);
};
classDer:publicBase{
public:
intfunc1(int);
intfunc2(double);
doublefunc3(int);
};

//Geersiz

Yukardaki bildirimleri inceleyelim:


Base snfndan tretilen Der snf sanal func1 ilevini eziyor. Ancak sanal func2 ilevini
ezmiyor. nk bildirilen func2 ilevinin imzas taban snfn bildirdii sanal func2 ilevinin
imzasndan farkldr. Tremi snf iinde yaplan func3 ilevi bildirimi ise derleme
zamannda hataya neden olur.
Tremi snfn taban snfn sanal ilevini ezebilmesi iin, tamamen ayn parametrik
yapya sahip bir ilev bildirmesi gerekir.
Ancak bu durumun bir istisnas vardr (variant return type): Taban snfn sanal ilevi bir
snf trnden adrese ya da referansa geri dnyorsa, tremi snfn ilevinin geri dn
deeri, taban snfn geri dndrd snftan treyen bir snfa ilikin bir trden olabilir.
Aadaki rnei inceleyin:
classB{
//...
};
classD:publicB{
//...
};
classBase{
public:
virtualB*vfunc1();
virtualB&vfunc2();
};
classDer:publicBase{
public:
D*vfunc1();
D&vfunc2();
};

227/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Yukardaki rnekte Base snf iinde iki ayr sanal ilev bildiriliyor. Sanal vfunc1 ilevinin
geri dn deeri B* trndendir. Oysa Base snfndan tretilmi Der snf bu ilevi
ezerken ilevin geri dn deerinin trn D* olarak bildiriyor. D snf B snfndan
tretildii iin bu geerli bir durumdur.
Benzer durum referans ile geri dnen sanal ilevler iin de geerlidir. Base snfnn sanal
vfunc2 ilevi B& trne geri dnerken bunu ezen Der snfnn vfunc2 ilevi D& trne geri
dnyor.
Bu kural neden getirilmi olabilir?
Der snf trnden bir nesne ile vfunc1 ya da vfunc2 ilevinin arldn dnelim:
Derder_object;
D*ptr=der_object.vfunc1();
D&r=der_object.vfunc2();
Eer tremi snfn vfunc1 ve vfunc2 ilevleri A* ve A& trlerine geri dnselerdi
yukardaki ilev arlar geerli olmazd.

okbiimlilik
Nesne ynelimli programlama tekniinde sanal ilevlerin kullanlarak ilev arlarnn
balanmasnn programn alma zamanna kaydrlmas genel olarak okbiimlilik
(polymorphism) ya da alma zaman ok biimlilii (runtime polymorphism) olarak
bilinir. Nesne ynelimli programlama teknii gerek gcn alma zaman
okbiimliliinden alr.
Bu teknikle genelletirilmi ve soyutlanm baz ilemler farkl snf nesneleri iin farkl
biimlerde yaplr. Hangi ilevin arldnn programn alma zamannda belirlenmesi
program yazmnda daha byk esneklik salad gibi ok daha iyi soyutlama olana
verir.
okbiimlilik farkl trden snf nesnelerinin gerek trleri bilinmeden, bu nesnelerin ortak
zelliklerine dayanlarak ilenmesidir.

228/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

LEV ABLONLARI
C ve C++ dillerinde ilevler trlere gre yazlr. Oysa bir ok ilev belirli bir algoritmay
kodlamak iin yazlr. lev belirli bir tre gre yazlmasna karn algoritma trden
bamszdr. rnein "iki deerden byk olann bulma" algoritmas deerlerin hangi
trden olacana gre deimez. ki nesnenin deerini takas etmek iin yaplmas
gerekenler bu nesnelerin trlerine bal deildir. Ya da bir diziyi sralamak iin yaplmas
gerekenler dizinin trne gre deimez. Ancak bu ileri yapacak ilevler ilem
yapacaklar trlere gre yazlr.
Bir ok programda, ayn algoritma sz konusu olmasna karn, farkl trler iin ilevler
programc tarafndan birden fazla kez yazlr. Programcnn ayn algoritmay farkl trler
iin yeniden kodlamasnn baz sakncalar olabilir:
1. Olas yazm hatalar sonucunda ilevlerden bazlar yanl tanmlanm olabilir.
2. Genel algoritmada bir deiiklik yapld zaman tre bal her bir ilev iin bu
deiiklikler ayr ayr yaplmaldr. Yani deiiklii tek bir yerde yaparak gerekletirmek
mmkn deildir.
Bir dizinin en byk elemannn deeri ile geri dnecek bir ilev tanmlamak isteyelim.
lev int trden bir dizi iin aadaki biimde tanmlanabilir:
intget_max(constint*ptr,size_tsize)
{
intmax=*ptr;
for(size_tk=1;k<size;++k)
if(ptr[k]>max)
max=ptr[k];
returnmax;
}
lev double trden bir dizi iin yazlmak istendiinde
doubleget_max(constdouble*ptr,size_tsize)
{
doublemax=*ptr;
for(size_tk=1;k<size;++k)
if(ptr[k]>max)
max=ptr[k];
returnmax;
}
Bu i nasl daha kolay bir hale getirilebilir? levlerin yazm nilemci programa
yaptrlabilir. Makrolar konusunu hatrlayalm:
#include<string>
#definegenerate_get_max(T)Tget_max(constT*ptr,intsize){\
Tmax=*ptr;for(intk=1;k<size;++k)\
if(ptr[k]>max)max=ptr[k]; returnmax;}
generate_get_max(int)
generate_get_max(double)
generate_get_max(std::string)

229/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Yukardaki kod parasnda ismi generate_get_max olan bir makro tanmlanyor. Argman
olarak farkl tr isimlerinin kullanlmasyla alan makrolarla, farkl trlere gre i gren
ilevler tanmlanm olur.
Ancak bu ama iin makrolar tanmlanmasnn baz sakncalar da vardr. Makrolar birden
fazla satra yayldnda satr sonlarnda '\' karakteri kullanmak gerekir. Ayrca baz
durumlarda gvenlik nedeniyle fazladan ayralar kullanlr. Makro ilevler gerek ilevlere
gre farkl bir szdizime sahiptir.
Makrolar nilemci program tarafndan alr. Makro-lev kullanlmas durumunda
program yazan, hangi makronun alp almamas gerektiini dnmek zorundadr. Ayn
tr iin bir makro-ilevin iki kez almamasn gvence altna almak programcnn
sorumluluundadr.
Makro-ilevlerde hata olumas durumunda kaynak kodda hatann olutuu yerin derleyici
tarafndan belirlenmesi daha zor olur. Derleyiciler gerek ilevler iin bu konuda ok daha
iyi destek verebilir.
Baka bir zm, her tr iin doru ekilde alacak, trden bamsz bir ilevin yazm
olabilir. C dilinin standart ilevlerden qsort ilevinin herhangi trden bir diziyi
sralayabildiini anmsayn. Trden bamsz ilevler void trden gsterici parametreleri
ile yazlabilir. Ancak bu yntem, kat bir tr denetiminin hedeflendii C++ dili iin pek
uygun deildir. Ayrca trden bamsz yazlan ilevler, tre bal olarak yazlan ilevlere
gre daha kark olma eilimindedir. Trden bamsz ilevlerin snf nesneleri iin
arlmasnda baz sorunlar oluabilir.
Bir baka zm de btn trlerin tek bir taban snftan tretilmesi olabilir. stenen
algoritma en tepedeki taban snfa gre yazlrsa, bu ileve argman olarak btn trler
gnderebilir. Bu durumda yine kat tr denetimi yaplmas engellenmi olur. Ayrca ilgili
ilevden faydalanabilmek iin mutlaka bir tretme ilemi yapmak gerekir.
ablonlar C++ a grece olarak ge eklenmi bir aratr. ablonlar dier programlama
dillerinde ya yoktur ya da kstl lde destek verecek ekilde vardr. C++ diline son
dnemde yaplan eklemelerin byk bir blm ablonlar konusunda yaplmtr.
Programc ayn algoritmaya gre farkl trler iin i gren ok sayda ilev tanmlamak
yerine yalnzca tanmlayaca ilevlere ilikin bir ablonu derleyiciye bildirir. Derleyici bu
ablondan faydalanarak gerektii zaman istenilen trden bir ilevin tanmn kendi yapar.
Yani derleyici ilevin kodunu yazar.
lev ablonu tanmlanma szdiziminin genel biimi aadaki gibidir:
template<classT>
<geridnde?eritr><ilevismi>([parametrede?ikenleri])
{
}
rnek:
template<classT>
voidfunc(T&a)
{
//...
}
template bir anahtar szcktr. template anahtar szcnden sonra asal ayra < >
gelmelidir. Asal ayra iinde yer alan class anahtar szcnn normal snf ilemleriyle
bir ilgisi yoktur. class anahtar szc yerine typename anahtar szc de kullanlabilir.
class ya da typename anahtar szcnden sonra isimlendirme kurallarna uygun
herhangi bir isim (identifier) seilebilir. Seilen bu isim, yani yukardaki rnekteki T ismi
bir tr belirtir. Byle ilevler birer ablondur. Yani kendi balarna alan kodda yer
kaplamaz. Bir ilev ablonuna ilikin bir ilev arldnda derleyici nce ar ifadesi
olarak kullanlan ifadenin trn saptar. Bu tre uygun olarak ablonda belirtilen ilevin
kodunu programc iin yazar:

230/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

#include<iostream>
template<classT>
voidprint(Ta)
{
std::cout<<a<<std::endl;
}
intmain()
{
print(3.5);
print(30L);
print('a');
print("Ahmet");
return0;
}
Yukardaki print ilev ablonunun tanmnda typename anahtar szc de kullanlabilirdi:
template<typenameT>
voidprint(Ta)
{
std::cout<<a<<std::endl;
}
main ilevi iinde print isimli ilev ablonunun drt ayr trden argman ile arldn
gryorsunuz. Derleyici bu durumda ilgili her ilev arsn grdnde ablondan ayr
ayr ilevler retir. Yukardaki kaynak kodun derlenmesi srasnda derleyici aadaki
ilevleri tanmlar. Bu duruma ablondan ilev retilmesi ("function generation ", "function
instantiation") denir.
print(3.5);
ar ifadesi iin derleyicinin yazd ilev:
voidprint(doublea)
{
std::cout<<a<<std::endl;
}
print(30L);
ar ifadesi iin derleyicinin yazd ilev:
voidprint(longa)
{
std::cout<<a<<std::endl;
}
print('a');
ar ifadesi iin derleyicinin yazd ilev:

231/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidprint(chara)
{
std::cout<<a<<std::endl;
}
print("Ahmet");

ar ifadesi iin derleyicinin yazd ilev:


voidprint(constchar*a)
{
std::cout<<a<<std::endl;
}
lev ablonlarnda tr belirten isme ablon parametresi (template parameter) denir.
lev ablonunda kullanlan parametre deikenlerine ilev ar parametreleri (call
parameters) denir.
Ayn ablon parametresinin asal ayra iinde birden fazla yer almas geersizdir:
template<classType,classType>
Typemax(Typea,Typeb)
{
//...
}

//Geersiz!

Bir ablon parametresi, ilev ablonunun her yerinde tr belirten szck olarak
kullanlabilir:
#include<iostream>
template<classT>
Tmax_of_three(Ta,Tb,Tc)
{
Tmax=a;
if(b>max)
max=b;
if(c>max)
max=c;
returnmax;
}
intmain()
{
std::cout<<max_of_three(12,51,67)<<std::endl;
std::cout<<max_of_three(17.2,15.3,6.7)<<std::endl;
return0;
}
ablon parametresi olarak kullanlan isim ilev ablonu dnda grnr deildir, ilev
ablonu dnda bilinmez. Ayn isim baka ilev ablonlarnda, ya da normal ilevlerde bir
akmaya neden olmadan kullanlabilir.

Birden Fazla ablon Parametresi Olabilir


Bir ilev ablonu birden fazla ablon parametresine sahip olabilir.
Bu durumda ilev ablonuna ilikin ileve yaplan arda kullanlan argmanlarn trlerine
gre, derleyici tarafndan farkl parametrik yapya sahip ilevler retilebilir:

232/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

#include<iostream>
template<classA,classB>
voiddisplay(Aa,Bb)
{
std::cout<<a<<""<<b<<std::endl;
}
#include<string>
usingnamespacestd;
intmain()
{
strings("Necati");
intx=10;
doubled=3.25;
display(x,d);
display(d,s);
display('A',s);

//voiddisplay(int,double);
//voiddisplay(double,string);
//voiddisplay(char,string);

return0;
}

lev ablonu Bildirimleri


Bir ilev ablonuna ilikin bildirim de yaplabilir:
template<classT>
Tmin(T,T);
lev bildirimlerinde parametre deikeni isimlerinin yazlmasnn zorunlu olmadn
hatrlayalm. Ayn bildirimi aadaki gibi de yapabilirdik:
template<classType>
Typemin(Typea,Typeb);
Normal ilevlerin bildiriminde olduu gibi, ilev ablonu bildirimlerinde de parametre
ayrac iinde kullanlan isimlerin bilinirlik alan bu ayracn iiyle snrldr. Yani bu isimlerin
ilevlerin tanmlamasnda kullanlan isimlerle ayn olmas gerekmez. Yukarda bildirimi
yaplan ilev ablonunun tanm aadaki gibi yaplabilir:
template<classType>
Typemin(Typet1,Typet2)
{
returnt1>t2?t1:t2;
}

Derleyicinin ablon Parametresinin Trn karmas


Bir ilev ablonuna ilikin ileve ar yapldnda, derleyici ileve gnderilen
argmanlarn trlerine bakarak, ablon parametresi olan tr yerine hangi gerek trn
koyulmas gerektiini anlar. Bu ileme ingilizcede "template argument deduction" denir.
Bu aamada derleyici tarafndan aadaki ilemler srayla yaplr:
1. lev arsnda kullanlan her bir argmana karlk, bir ar parametresinin karlk
gelip gelmedii kontrol edilir.

233/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


2. Eer uygun bir argman bulunmu ise, buna karlk gelen ablon parametresinin tr
bilgisi belirlenmi olur.
3. Eer ayn ablon parametresi ilev ablonu tanm iinde birden fazla kullanlm ise, bu
durumda, ilev ar ifadesindeki argmanlarn tr de benzer ekilde ayn olmaldr.
Bu aklamadan sonra aadaki ilevleri inceleyelim :
template<classT>
voidfunc(Ta,Tb)
{
//
}
intmain()
{
charch='K';
func(ch,'A');
//
return0;
}
Bu rnekte derleyici
func(ch,'A)
gibi bir ar iin birinci aamada ilev ar ifadesine bakarak ch ifadesinin trnn char
tr olduu anlar. lev ablonu tanmnda ablon parametresi olarak kullanlan T'nin char
tr olduuna karar verir. func ilevine yaplan ar ifadesindeki ikinci argman olan 'A'
da char trden bir deimez olduguna gre, ikinci ablon ar parametresinin de char
trden olmas gerekir.
Gerekten ikinci ar parametresi de T trnden olduguna gre aadaki ilevin
retilmesi doal sonutur:
voidfunc(chara,charb)
{
//
}
Ancak yukardaki func ilev ablonunun aadaki biimde arldn varsayalm:
voidfoo()
{
doubled=3.15;
floatf=10.7F;
func(d,f);
//Geersiz!
}
func(d,f)
ars geersizdir. Derleyici ilev ar ifadesinde yer alan birinci argmann trne
bakarak T trnn double tr olduu sonucunu karr. Bu durumda ikinci ablon
argman da T trnden olduuna gre, ilev ar ifadesindeki ikinci argman da double
trnden olmaldr. Oysa ileve gnderilen ikinci argman float trnden olduundan,
ileve yaplan ar geersizdir.
Baka bir rnek verelim:
template<classT>
Tget_max(constT*ptr,size_tsize)
{

234/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Tmax_elem=ptr[0];
for(size_tk=1;k<size;++k)
if(ptr[k]>max_elem)
max_elem=ptr[k];
returnmax_elem;
}
intmain()
{
inta[10]={1,2,3,7,8,4,5,6,9,1};
doubleb[3]={1.0,2.0,3.0};
cout<<"maxint="<<get_max(a,10)<<endl;
cout<<"maxdouble="<<get_max(b,10u)<<endl;
return0;
}
Yukardaki ilev arlar geerlidir, derleme zamannda hata oluturmaz. Derleyici baarl
bir ekilde yani ift anlamllk hatas olmadan ilev ablon parametresi olan tr, ilev
ar ifadesine bakarak saptayabilir.
lev ablonlarna ilikin ilevler arldnda, ileve gnderilen arguman says ile, ilev
ablonunda belirtilmi parametre saysnn da uyumlu olmas gerekir. Uygun parametre
yaps bulunmaz ise derleme zamannda hata oluur. Aadaki kodu inceleyin:
template<classT>
Tsum_square(Ta,Tb)
{
returna*a+b*b;
}
#include<iostream>
usingnamespacestd;
intmain()
{
cout<<sum_square(5,8)<<endl;
cout<<sum_square(2.7,3.5)<<endl;
cout<<sum_square(10)<<endl;
cout<<sum_square(4,7.9)<<endl;

//Geerli
//Geerli
//Geersiz
//Geersiz!

return0;
}
sum_square(10)
ars geersizdir. nk ilev ablonunun iki ar parametresi varken ileve tek bir
argman gnderiliyor.
sum_square(4,7.9)
ars da geersizdir. leve iki farkl trden argmanlar gnderiliyor. Oysa ilev ar
parametrelerinin tr ayndr.

235/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Aada rnek olarak ayn trden iki nesnenin deerini takas eden swap isimli bir ilev
ablonu yazlyor:
template<classT>
voidswap(T&r,T&b)
{
Ttemp=a;
a=b;
b=temp;
}
#include<iostream>
intmain()
{
intx=10;
inty=20;
swap(x,y);
std::cout<<"x="<<x<<"\ny="<<y<<std::endl;
doubled=3.75;
doublee=4.50;
swap(d,e);
std::cout<<"d="<<d<<"\ne="<<e<<std::endl;
return0;
}
swap ilevi ablonunda referans yerine gsterici deikenler de kullanlabilirdi:
template<classT>
voidswap(T*p1,T*p2)
{
Ttemp=*p1;
*p1=*p2;
*p2=temp;
}
#include<iostream>
usingstd::cout;
intmain()
{
intx=10;
inty=20;
swap(&x,&y);
cout<<"x="<<x<<"\ny="<<y<<std::endl;
doubled=3.75,e=4.50;
swap(&d,&e);
cout<<"d="<<d<<"\ne="<<e<<std::endl;
return0;
}
lev ablonundan retilecek ilevlerin parametre deikeni ya da deikenlerinin tr ya
da trleri derleyici tarafndan akllca saptanr. rnein:

236/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


template<typenameT>
voidfunc(Tp)
{
T*ptr=&p;
//
}
intmain()
{
inta[10];
func(a);
return0;
}
main ilevi iinde func ilev ablonuna ilikin ilev, int trden a dizisinin balang adresi
ile arlyor. lev ablonuna gnderilen argmann tr (int *) olduuna gre, derleyici
T trn (int *) tr olarak belirleyerek ilevin kodunu yazar. Bu durumda ilev
ablonunun iinde tanmlanan ptr isimli nesnenin tr de (int **) olur. imdi de aadaki
ilev ablonunu inceleyelim:
template<typenameT>
voidfunc(Tf)
{
f();
}
#include<iostream>
voiddisplay_message()
{
Std::cout<<"merhaba!"<<std::endl;
}
intmain()
{
func(display_message);
return0;
}
main ilevi iinde func ilevi display_message ilevinin ismi ile arlyor. func ilevi bir
ablona ilikindir. Bir ilev isminin, ileme sokulduunda ilevin adresine
dntrldn biliyorsunuz. Bu durumda derleyici ablon parametresi olan T trn
void(*)(void)
tr olarak belirler. levi bu tre gre yazar. Derleyici tarafndan aadaki gibi bir ilev
yazlr:
voidfunc(void(*f)())
{
f();
}

237/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Derleyicinin yazd func ilevinin arlmas ile, ilevin ana blou iinde f deikeninin
gsterdii ilev, yani display_message ilevi arlr.

ablon Argmanlar Bir Snf Trne Balanabilir


lev ablonuna ilikin bir ilev yaplan ar ifadesinde kullanlan argman ya da
argmanlar bir snf trnden de olabilir.
classComplex{
doublem_r,m_i;
public:
Complex(doubler=0,doublei=0.):m_r(r),m_i(i){}
friendComplexoperator+(constComplex&r1,constComplex&r2);
friendComplexoperator*(constComplex&r1,constComplex&r2);
//
};

template<classT>
Tsum_square(Ta,Tb)
{
returna*a+b*b;
}

intmain()
{
Complexc1(4.,7);
Complexc2(3,8);
Complexc3=sum_square(c1,c2);
return0;
}
Yukardaki kod parasnda eer Complex snf iin operator+ ve operator* ilevleri
bildirilmemi olsa derleme zamannda hata oluurdu. Derleyici yazlm olan ablonda T
template parametresi yerine Complex trn yerletirdiinde,
a*a+b*b
ilemini yapabilmek iin ilgili ile ilevlerini arar ama bulamazd.

Tr ve Referans ar Parametreleri
lev ablonu ar parametresinin bir gsterici ya da referans olmas, baz dnmlerin
yaplp yaplmayacan belirler. Aadaki ilev ablonlar bildirilmi olsun:
template<typenameT>
voidf(T);
template<typenameT>
voidg(T&);
doublea[20];
constintci=10;
imdi bu ablonlara ilikin yaplacak baz arlar ele alalm:
f(a);

238/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

lev ablonu ar parametresi referans olmad iin, bu durumda dizi ismi otomatik
olarak dizinin ilk elemann adresine dntrlr. Yukardaki ilev ars sonucunda
derleyici f ilev ablonu iin T trn double* tr olarak belirler.
g(a);
ilev ablonu ar parametresi referans olduundan bu durumda T tr, 20 elemanl
double trden bir dizi trdr.
f(ci);
ilev ablonu ar parametresi referans olmadndan T tr int tr olarak belirlenir.
g(ci);
ilev ablonu ar parametresi referans olduundan T tr const int tr olarak belirlenir.
f(5);
Bu ar sonucunda T tr int tr olarak belirlenir. ar geerlidir.
g(7);
T tr int tr olarak belirlenir. ar derleme zamannda hata oluturur. Ancak bir const
referansa, bir deimez ile ilkdeer verilebileceini anmsayn.
Aadaki rnei derleyerek altrn:
#include<iostream>
template<classT>
voiddisplay(T&a)
{
for(intk=0;k<sizeof(a)/sizeof(a[0]);++k)
std::cout<<a[k]<<"";
std::cout<<std::endl;
}
intmain()
{
inta1[5]={1,2,3,4,5};

display(a1);

inta2[3]={10,20,30};
display(a2);

inta3[10]={2,4,6,8,10,12,14,16,18,20};
display(a3);
return0;
}
Nasl oluyor da bir dizinin elemanlarn yazan ilev dizinin eleman saysn almadan bu ii
baaryor? display ilevinin ar parametresinin tr T& olarak seildiinden,
display(a1)

239/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


arsyla, derleyici ilev ablonu ar parametresinin 5 elemanl int trden bir dizinin
yerine geen referans olduu bilgisini kartr. Derleyici aslnda
display(a1)
display(a2)
display(a3)
arlar iin ayr ilev yazmtr.

Dizgelerin Argman Olarak Kullanlmas


Bir dizge bir ilev ablonuna ilikin ileve argman olarak gnderilirse, ablon
parametresinin tr ne olarak belirlenir? ar parametresi bir referans deilse ablon
parametresi const char * tr olarak belirlenir. Ancak ilev ar parametresi bir referans
ise argman tr belirli bir uzunlukta char trden dizi tr olarak ele alnr. Dizinin
uzunluu dizgeyle belirlenen yaznn uzunluundan bir fazla olarak alnr:
Aadaki rnei inceleyin:
template<classT>
voidfunc(Ta,Tb);
template<classT>
voidfoo(T&a,T&b);
intmain()
{
func("veli","murat");
foo("ali","can");
foo("veli","murat");

//Geerli
//Geerli
//Geersiz

return0;
}
func("veli","murat");
arsnda func ilev ablon parametresi T trn char * tr olarak alr.
foo("ali","can"); //Geerli
arsnda ise ablon parametresi char [4] trdr. Her iki argmann tr de ayn olduu
iin ar derleyici tarafndan geerli olarak deerlendirilir.
foo("veli","murat");
Derleyicinin yapt karmda ise her iki argmann tr ayn deildir. leve gnderilen
birinci argmana gre T tr char[5] tr olarak belirlenirken, ikinci argmana ilikin tr
char[6] trdr. Oysa ilev ablonu ar parametreleri ayn trdendir. lev ars
geersizdir.

Bir lev ablonu inde Baka Bir lev ablonu arlabilir


phesiz bir ilev ablonu iinde baka bir ilev ablonuna ilikin ilev arlabilir.
Bir diziyi kkten bye doru sralayan bir ilev ablonu tanmlayalm:
#include<iostream>
template<classT>
voidmswap(T&a,T&b)

240/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


{
Ttemp=a;
a=b;
b=temp;
}
template<classT>
voidsort(T*p,size_tsize)
{
for(size_ti=0;i<size1;++i)
for(size_tj=0;j<size1i;++j)
if(p[j]>p[j+1])
mswap(p[j],p[j+1]);
}
intmain()
{
inta[10]={10,9,8,7,6,5,4,3,2,1};
doubleb[5]={5.4,2.3,3.5,8.7,1.9};
sort(a,10);
sort(b,5);
return0;
}
Yukardaki ilev ablonlarn inceleyelim. mswap isimli ablon herhangi trden iki
nesnenin deerlerinin takas edilmesini salayan ilevler retmek amacyla tanmlanyor.
sort ilev ablonu ise dizileri bubble sort algoritmasyla sraya sokmak iin tanmlanyor.
sort ilev ablonu iinde mswap ilev ablonuna ar yapldn gryorsunuz.

Bir lev ablonuyla Ayn simli Normal Bir lev Bir Arada
Bulunabilir
Bir ilev ablonuyla ayn isimli normal bir ilev bir arada bulunabilir.
Bu durumda ift anlamllk hatas (ambiguity) olumaz. Normal ilevin ilev ablonuna
kar bir ncelii vardr:
#include<iostream>
template<classT>
Tsum_square(Ta,Tb)
{
std::cout<<"templatefunction "<<std::endl;
returna*a+b*b;
}
intsum_square(inta,intb)
{
std::cout<<"nontemplatefunction"<<std::endl;
returna*a+b*b;
}
intmain()
{
intx=sum_square(4,7);
return0;

241/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


}

Normal bir ilevle bir ilev ablonunun ayn isimde olabilmesi, ilev ablonlarnn
zelletirilmesine yardmc olur. rnein:
template<classT>
voidfoo(Ta)
{
//...
}
Yukarda verilen foo ilev ablonunun yazlm olan ablon kodunun Date isimli bir snf
iin uygun dmediini dnelim. Bu durumda ayn isimli Date parametreli normal bir
ilev yazlabilir:
voidfoo(Datedate)
{
//...
}
Bu durumda foo ilevi Date trnden bir argman ile arldnda ilev ablonu
tarafndan ilev retilmez. zel olarak yazlan foo ilevi arlm olur.

Belirlenmi lev ablonu Argmanlar


Derleyici bir ilev ablonuna ilikin ilev arsyla karlatnda, ilev ablonu
parametresinin hangi tr olmas gerektiini karmaya alr (template argument
deduction). Eer derleyici bu abasnda baarl olamaz ise derleme zamannda hata
oluur. Aadaki rnei inceleyelim:

242/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


template<classT>
voidfunc(Ta,Tb);
intmain()
{
unsignedintuix=10u;
inty=3;
func(uix,y); //Geersiz
//..
return0;
}
Yukardaki rnekte
func(uix,y);
ars geersizdir. nk derleyici func ilevine yaplan ar ifadesindeki birinci
argmana bakarak T trnn unsigned int olduu sonucuna varr. Daha sonra kinci
argmann unsigned int trden olmadn grnce bu durumda hata iletisi verir.
stenirse ablon parametresinin trnn ne olduu derleyicinin karmna braklmayabilir.
zel bir szdizim kural ile ilev arsyla derleyiciye dorudan bildirilebilir. Bu duruma
"belirlenmi ilev ablonu argmanlar" (explicit template arguments) denir.
Bu amala ilev arsnda, ilev ismini izleyen bir asal ayra iinde, ablon
parametresine ilikin tr bilgisi derleyiciye aka bildirilir. Asal ayrac ilev ar ileci
izler:
func<unsignedint>(uix,y);
Yukardaki aryla, func ilev ablon parametresinin (T), unsigned int tr olarak kabul
edilmesi gerektii derleyiciye aka bildiriliyor. Bu durumda derleyici bir karm yapmaya
almadan, ablondan ilev retirken T tr yerine unsigned int trn kullanr. Yani
derleyici aadaki gibi bir ilev yazar:
voidfunc(unsignedinta,unsignedintb)
{
//..
}
Belirlenmi ablon argman kullanmnn baz faydalar vardr:
1. Baz durumlarda ilev ablonu kullanm gereksiz yere, fazla sayda ilevin
tanmlanmasna yol aar. rnein:
template<classT>
voidfunc(Ta);
bildirilen func ilev ablonu aadaki deyimlerle arlrsa derleyici 6 ayr farkl ilev
tanmlar:
func('A');
func(10);
func(10U);
func(25L);
func(12.f);
func(3.8);
Oysa programc yukardaki tm arlarn parametresi double trden olan bir ileve
yaplm olmasn isteyebilir. Ne de olsa dier doal trlerden argmanlar derleyici

243/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


tarafndan double trne dntrlebilir. Bylece programc gereksiz ilev tanmlarndan
kanm olur:
func<double>('A');
func<double>(10);
func<double>(10U);
func<double>(25L);
func<double>(12.f);
func(3.8);
2. Baz durumlarda da, ilev ablonu parametresinin derleyici tarafndan karm zaten
olanakszdr:
template<classT>
Tfunc()
{
//...
}
Yukardaki ilev ablonunda ablon parametresi olan T, ilevin geri dn deerinin tr
olarak kullanlyor. Peki derleyicinin bu ablona ilikin bir ilev arsn grdnde T
trnn ne olduunu karma ans var mdr? Bir de aadaki ablonu inceleyelim:
template<classT>
voidfoo()
{
Ta;
//...
}
Yukardaki ilev ablonunda ise T tr, ilev ana blou iinde tanmlanan a isimli nesnenin
tr olarak kullanlyor. Bu durumda da, ilev arsna bakarak derleyicinin T trnn ne
olduunu anlama ans olmaz. Ancak her iki rnekte de ilev arsnda, T trnn ne
olduu aka belirtilirse, derleyicinin karm yapmadan T trnn hangi tr olduunu
anlamas salanabilir.
yle bir ilev ablonu yazlmak istensin ki, bu ablon iki ablon parametresine sahip
olsun. lev ablonu bu parametrelere gnderilecek deerlerin toplam deeriyle geri
dnsn. Ancak geri dn deeri de, toplam deerini iinde tutabilecek genilikte bir
trden olsun:
template<classT,classU>
????sum(T,U);
ilevin geri dn deeri tr yerine ne yazlmaldr? T mi U mu? Bu rnee baklrsa her
iki trn de geri dn deeri tr olmas mmkn deildir:
charch;
unsigneduix;
//...
sum(ch,ui)
sum(uix,ch)
Eer ilev ablonunun tanm
template<classT,classU>
Tsum(T,U);

244/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

biiminde ise
sum(ch,ui)
ilevinin arlmas durumunda derleyicinin yazaca ilev
charsum(char,unsignedint);
biiminde olur ki bu durumda bilgi kayb kanlmazdr. Eer ablon ilevin tanm
template<classT,classU>
Usum(T,U);
biiminde yaplmsa
sum(uix,ch)
ilevinin arlmas durumunda derleyicinin yazaca ilev
charsum(unsignedint,char);
eklinde olur ki, yine bu durumda bilgi kayb kanlmaz olur.
Sorunu zmek iin ilev ablonu tanmna nc bir ablon parametresi eklenebilir:
template<classT1,classT2,classT3>
T1sum(T2a,T3b);
unsignedintux=sum('a'+768U);
lev ars byle yaplrsa, T1 trnn ne olduu derleyici tarafndan ilev ar
ifadesinden karlamaz. Oysa sz konusu ilev belirlenmi argmanla arlrsa bu
durumda hata olumaz:
unsignedintux=sum<unsignedint>('a'+768U);
Yukardaki ar ile derleyiciye T1 trnn hangi tr olarak ele alnmas gerektii ak bir
ekilde bildiriliyor. Derleyici bu arya ynelik olarak aadaki parametrik yapya sahip
bir ilev yazar:
unsignedintsum(chara,unsignedintb);
Birden fazla ablon parametresinin bulunmas durumunda, ablon parametrelerinin
hepsinin belirlenmesi zorunlu deildir. Soldan balayarak istenilen sayda ablon
parametresi, ilev arsnda aka belirlenebilir. Ak olarak belirlenmemi ablon
parametrelerinin hangi trden alnacaklar derleyicinin karmna braklm olur.
Aadaki rnei inceleyin:
template<classT,classM,classU>
Tfunc(Ma,Ub)
{
Ttemp;
//...
returntemp;
}

245/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


intmain()
{
func<int>('A',12);
func<int,double>('A',12);
func<int,double,double>('A',12);
//...
return0;
}
main ilevi iinde yaplan birinci arda func ilev ablonunun birinci parametresi olan T
tr ak bir ekilde belirtiliyor. Bu durumda T tr int tr olarak seilir. M tr ve U tr
derleyicinin karmna braklyor. Derleyici ilev arsna bakarak M trn char tr, U
trn ise int tr olarak belirler, ilevi bu trlere gre yazar.
main ilevi iinde yaplan ikinci arda func ilev ablonunun birinci ve ikinci argmanlar
olan T ve M tr ak bir ekilde belirtiliyor. Bu durumda T tr int M tr double tr
olarak seilir. U tr ise derleyicinin karmna braklyor. Derleyici ilev arsna bakarak
U trn int tr olarak belirler, ilevi bu trlere gre yazar.
nc arda ise tm ablon argmanlar aka belirleniyor. Hibir argman
derleyicinin karmna braklmyor. Derleyici T trn int tr olarak, M ve U trlerini
double tr olarak belirler. levi bu trlere gre yazar.

lev ablonlar ve lev Yklemesi


ablon ilevlerin kullanm ilev yklemesi ile ilikili olsa da, ablon ilevler ve ilev
yklemesi ayr aralardr:
1. Ayn isme sahip ancak parametre deikeni says farkl ilevler tanmlanarak bu
ilevler arlabilir. Ancak ilev ablonu sz konusu olduunda verilen ablona ilikin
derleyicinin yazaca tm ilevlerin parametre deikeni says ayndr.
2. lev yklemesi mekanizmasna konu olan, ayn isimli ilevlerin kaynak kodlar farkl
olabilir. Yani bu ilevler isimleri ayn olmasna karn farkl iler yapabilir. Ama bir
ablondan retilen ilevlerin kaynak kodlar ayn, yalnzca parametre deikenleri trleri
farkldr.

lev ablonlar da Yklenebilir


Parametrik yaplar farkl, isimleri ayn olan ilev ablonlar tanmlanabilir.
Nasl ayn isimli ilevler bulunabiliyorsa, ayn isimli ilev ablonlar da bir arada
bulunabilir. Tabii bu ilev ablonlarnn, parametrik yaplar, ablon parametre ya da ar
parametrelerine bal olarak verilen genel imzalar birbirinden farkl olmak zorundadr.
Aadaki kod parasn derleyerek altrn:
inlineconstint&getmin(constint&a,constint&b)
{
returna<b?a:b;
}
template<typenameT>
inlineTconst&getmin(constT&a,constT&b)
{
returna<b?a:b;
}
template<typenameT>
inlineconstT&getmin(constT&a,constT&b,constT&c)
{
returngetmin(getmin(a,b),c);
}

246/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

#include<iostream>
usingnamespacestd;
intmain()
{
cout<<getmin(10,20,30)<<endl;
cout<<getmin(7.0,42.0)<<endl;

cout<<getmin('a','b')<<endl;
cout<<getmin(7,42)<<endl;

cout<<getmin<>(7,42)<<endl;
cout<<getmin<double>(7,42)<<endl;
cout<<getmin('a',42.7)<<endl;
return0;
}
main ilevi iinde yaplan tm arlar tek tek ele alalm:
getmin(10,20,30)
ars iin
template<typenameT>
inlineconstT&getmin(constT&a,constT&b,constT&c)
ablonundan T trnn int tr olmas karmyla bir ilev retilir.
getmin(7.0,42.0);
ars iin
template<typenameT>
inlineTconst&getmin(Tconst&a,Tconst&b)
ablonundan T trnn double tr olmas karmyla bir ilev retilir.
getmin('a','b')
ars iin
template<typenameT>
inlineTconst&getmin(constT&a,constT&b)
ablonundan T trnn double tr olmas karmyla bir ilev retilir.
getmin(7,42)
ars bir ilev ablonuna ilikin deildir. nk
inlineconstint&getmin(constint&a,constint&b);
biiminde bir ilev bilidirmi yaplmtr. Gerek ilevin ilev ablonuna ncelii vardr.

247/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


getmin<>(7,42)
ars gerek ileve deil ilev ablonuna ilikindir. nk ilev arsnda ilev ismini ii
bo bir asal ayra izliyor.

getmin<double>(7,42)
ars ise iki ar parametreli ilev ablonuna ilikindir. Ancak ablon parametresinin
tr derleyicinin karmna braklmadan double tr olarak bildiriliyor.
Son olarak
getmin('a',42.7)
ars yine gerek ileve ilikindir. lev arsnda kullanlan argmanlarn trleri
farkldr. Ancak iki ar parametreli ilev ablonunun ar parametreleri ayn ablon
parametresi trndendir. Bu durumda ilev ablonundan ilev retilmesi mmkn deildir.

lev ablonunun Belirlenmi Bir Tr in zelletirilmesi


Yazlan bir ilev ablonu tm veri trleri iin uygun dmeyebilir. Belirli bir tr iin,
retilecek ilevin, ablonda verilen algoritmaya gre deil de verilecek baka bir tanma
gre yazlmas istenebilir. Buna ilev ablonunun bilinli zelletirilmesi (explicit
specialization) denir. Aadaki rnei inceleyelim:
template<classType>
Typemax(Typea,Typeb)
{
returna>b?a:b;
}
#include<iostream>
intmain()
{
constchar*p1="Mehmet";
constchar*p2="Ahmet";
std::cout<<max(p1,p2)<<std::endl;
return0;
}
max ilev ablonu kendisine gnderilen iki nesneden byk olann deeri ile geri dnen
ilevlerin retiminde kullanlabilir.
Byklk ilikisi char, int, double gibi doal trler iin aktr. Yukardaki ilev ablonun
kullanlmasnda bir hata sz konusu olmaz. Ancak iki dizgenin daha bynn
bulunmas iin bu ablonun kullanlmas doru olmaz. Yukardaki genel algoritma
karlatrmay > ileci ile yapmaktadr. ki dizge > ileci ile karlatrldna
karlatrlan yalnizca dizgelerin yerletirildii bellek bloklarnn adresidir. phesiz
istenilen dizgelerin szlkteki konumlarna ilikin (lexicographical) bir karlatrmadr. C+
+ dili byle durumlarda ilev ablonu iin tre bal zel ilev tanmlar yaplabilmesine
izin verir. Bu mekanizmaya "lev ablonunun belirlenmi bir tr iin zelletirilmesi"
(Template Explicit Specialization) denir. Aadaki kodu inceleyin:
template<classType>
Typetmax(Typea,Typeb)
{
returna>b?a:b;

248/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


}

template<>
constchar*max<constchar*>(constchar*p1,constchar*p2)
{
return(strcmp(p1,p2)>0?p1:p2);
}
#include<iostream>
intmain()
{
inti=max(50,10);
std::cout<<"i="<<i<<std::endl;
constchar*p1="Necati";
constchar*p2="Ergin";
std::cout<<"max="<<max(p1,p2)<<std::endl;
return0;
}

Szdizimi inceleyelim. template anahtar szcn bu kez ii bo bir asal ayra izliyor.
Bu asal ayratan sonra ilevin geri dn deerinin tr yazlyor. Ancak bu kez ilev
bilinen bir tr bilgisi ile, yani ablon ilev argmanna bal kalmadan yazlyor. Daha
sonra ilev ismi geliyor. lev isminden sonra gelen asal ayra iine bu kez yine tr
bilgisi yazlyor.
Yukardaki szdizime gre belirli bir tre ynelik zelletirme yaplabilmesi iin, ana ilev
ablonu tanmnn derleyici tarafndan grlebilir olmas gerekir. Yani ancak daha nce
tanmlanm olan bir ilev ablonu zelletirilebilir.

lev ablonlarnda Szdizim Kontrolleri


Derleyicilerin ou, ilev ablonlarnda szdizim kontroln iki ayr aamada
gerekletirir. Birinci kontrol henz ilev ablonu arlmadan yaplr. Bu aamada baz
temel kontroller yaplr. Hibir biimde ve olaslkta geerli olamayacak durumlar daha bu
aamada derleme zaman hatas olarak belirlenir. Gerek szdizim kontrol ilev
ablonuna ilikin bir aryla karlaldnda, yani derleyicinin gerek ilevi yazmas
srasnda yaplr. Aadaki rnei ele alalm:
template<typenameT>
voidfunc(Tp)
{
p.foo();
}
intmain()
{
func(10);

//Geersiz

return0;
}
Yukardaki kod parasnda derleyici ilev ablonunun kodunun zerinden getiinde
herhangi bir hata vermez. nk uygun bir ilev arsyla T tr bir snf tr olarak
belirlenebilir. O snfn da func isimli bir public ye ilevi olabilir. Ancak ilev uygun

249/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


olmayan bir trden argmanla arldnda, derleyici ilev arsn bir hata olarak
belirler.
Derleyicinin szdizim kontrollerini hangi aamalarda yapaca standart olarak
belirlenmemitir. Baz derleyiciler ilev ablonuna ilikin bir ar ile karlamadka
neredeyse hi bir szdizim geerlilik kontrol yapmaz.

lev ablonlarnn Yeri


lev ablonlar kod dosyasna, yani .cpp dosyasna, yerletirilemez. Derleyicinin her
kaynak dosyay derlemesi srasnda , ilev ablonu tanmlamalarn yeniden grmesi
gerekir. Projenin birden fazla modlden olumas durumunda, bamsz derlenen her
modlde, eer bu ilev ablonu arlm ise tanmlamasnn derleyici tarafndan her
modlde grlmesi gerekir. Farkl modllerde ayn ilev ablonu kullanlyorsa bu ilev
ablonu tanmlamalarnn tamamen zde olmas gerekir.
lev ablonlarnn balk dosyalarnda tanmlanmas, ablonun kullanld her modle bu
balk dosyasnn eklenmesi en iyi zmdr.
lev ablonu tanmlamalar, static anahtar szc ile balatlmamsa d balantya
sahiptir. Bu durumda rnein, ayn ablon ilev ayn almla hem a.cpp hem de b.cpp
dosyasndan kullanlm olsun. Derleyici ayn alm hem a.obj hem de b.obj iine yazar.
Ancak balayc bunlardan yalnzca bir tanesini alan koda yerletirir. Yani farkl
modllerden ayn ilev ablonu kullanlm olsa bile, alan dosyada bir tane bulunur.

lev ablonlarnda Varsaylan Argmanlar


Normal ilevlerde olduu gibi, ilev ablonlar da varsaylan argmanlar alabilir. Varsaylan
argman olarak kullanlan ifade ablon parametresine bal olabilecei gibi ablon
parametrelerinden bamsz da olabilir. Aadaki ablonu inceleyelim:
template<typenameT>
voidfunctemp(T&r,Tval=0)
{
r=val;
}
Yukarda tanmlanan functemp isimli ablondan retilecek bir ileve tek bir argman
geildiinde, ilevin ikinci parametresi olan val deikenine otomatik olarak 0 deeri
kopyalanr. imdi de aadaki ablonu inceleyin:
template<typenameT>
voidftemp(T*ptr,constT&val=T())
{
*ptr=&val;
//
}
Tanmlanan ftemp isimli ablondan retilecek bir ileve, tek bir argman geildiinde
ilevin ikinci parametresi olan val referans varsaylan kurucu ilevle yaratlacak bir geici
nesneye balanr. Eer T tr doal veri trlerinden biri olarak belirlenirse bu referans
deeri 0 olan bir geici nesneye balanr. Daha nce deindiimiz szde balang ilevi
(pseudo constructor) kuraln anmsayn.
Varsaylan argman olarak kullanlan ifadeye dayanlarak ablon parametresinin hangi
tre ilikin olduu bilgisi karlamaz. Aadaki rnei inceleyin:

250/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


template<typenameT>
voidfunc(Tx=42);

intmain()
{
func<int>();
//Geerli.Tinttrolarakalnr.
func(); //Geersiz.Ttrnnneoldu?ubilgisikarlamaz.

return0;
}

typename Anahtar Szc


Bir ilev ablonunun parametresinin bildiriminde class veya typename anahtar
szcklerinin kullanlabileceini biliyorsunuz. Ancak typename anahtar szcnn ikinci
bir kullanm vardr. Burada class anahtar szc typename anahtar szcnn yerine
kullanlamaz. Bir ilev ablonu iinde ablon parametresine bal olarak bir tr bilgisinin
kullanldn dnelim:
template<classT>
voidfunc(Tval)
{
T::Dollarsum;
//
}

//Geersiz

Yukardaki ilev ablonu ana blou iinde T::Dollar bir tr bilgisi olarak kullanlyor.
Burada typename anahtar szcnn kullanlmas zorunludur.
typenameT::Dollarsum;
deyimiyle tanmlanan sum T tr hangi snfa ilikin ise, o snf trnn iinde bildirilmi
olan Dollar trnden bir nesnedir.

ablonlarn Tr Belirtilen parametreleri ve Tr Belirtmeyen


Parametreleri
ablonlarn, ablon parametreleri tr belirten (type parameter) ya da tr belirtmeyen
(non type) eklinde olabilir. Parametre yazlrken class ya da typename anahtar szc
kullanlrsa parametrenin aslnda herhangi bir tr bilgisi ifade eden bir anlama geldii
varsaylr. Fakat class ya da typename yerine int, long gibi doal trlere ilikin bir tr
kullanlrsa bu durumda ablon parametresi tr belirtmez. O trden bir "deimez ifadesi"
belirtir. Bu durumda ablon ileve ar yaplrken, bu parametreler iin bir deimez
ifadesi kullanlmas gerekir. rnein:

251/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<ctime>
template<classT,size_tsize,classR>
voiddisplay(Rfptr)
{
Ta[size];

for(intk=0;k<size;++k)
a[k]=fptr();
sort(a,a+size);
for(intk=0;k<size;++k)
std::cout<<a[k]<<"";
std::cout<<"\n********************************"<<std::endl;
}
doubledrand()
{
returnstatic_cast<double>(rand())/RAND_MAX;
}
intmain()
{
srand(time(0));
display<int,100>(rand);
display<double,10>(drand);

return0;
}
Yukarda tanmlanan display isimli ilevin ablon parametresi var. Bunlardan ikincisi
tre bal olmayan bir parametre. Bu parametreye karlk gelen deer ilev arsnda
belirlenmelidir.
levin amac belirli trden N tane rastgele deeri kkten bye doru ekrana
yazdrmak. ablonun tre bal birinci parametresi yazdrlacak rastgele deerlerin trn
belirliyor. ablonun ikinci yani tr d parametresi rastgele deerlerin saysn belirliyor.
ablonun tre bal olan nc parametresi rastgele say retiminde kullanlacak ilevin
trn belirliyor. Aadaki ary inceleyelim:
display<double,10>(drand);
Derleyicinin bu ablondan retecei ilevin arlmasyla drand ilevi kullanlarak 10 tane
double trden deer elde edilir. Bu deerler sral bir biimde ekrana yazdrlr. lev
ablonu iinde tr d parametre olan size ilev tanm iindeki dizinin boyutu olarak
kullanlyor. arlan sort ilevi ise STL'in standart bir ilev ablonudur.

Standart C++ ablon Ktphanesi Nedir


STL (Standard Template Library) ilk kez 90 l yllarn balarnda kullanlmaya balamtr.
Daha sonra alnan bir kararla STL'in C++'n standart ktphanesi yaplmasna karar
verilmitir. 1998 standartlaryla eitli eklentilerle STL, C++n standart ktphanesi
yaplmtr.
STL ilev ve snf ablonlarndan oluur. Bu ilev ve snf ablonlarnn tanmlar eitli
balk dosyalarnn iine yerletirilmitir. rnein, <algorithm> isimli balk dosyasnda
ok sayda standart ilev ablonu vardr. STL deki tm ilev ve snf ablonlar std isim
alan iinde tanmlanmtr. Bu nedenle programcnn bunlar kullanrken, std isim alann

252/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


dikkate almas gerekir. Ktphanedeki global ilev ablonlar algoritma olarak
isimlendirilir. Snf ablonlar ise farkl veri yaplarnn kodlanmas amacyla tanmlamtr.
Algoritmalar iterator kavram kullanlarak snf ablonlaryla btnletirilmitir.
teratrler, nesne tutan snflar zerinde baz genelletirilmi ilemlerin yaplmasn
salayan gstericiler ya da akll gstericilerdir (smart pointers).

rnek STL lev ablonlar


STL'de ok sayda ilev ablonu bulunur. Bu ilev ablonlar, yaptklar ilere gre eitli
gruplara ayrlmtr. yi bir STL kullanm iin zel bir eitim gerekir.
Bu ilev ablonlarnn kullanlabilmesi iin yaplmas gereken o ablonun bulunduu balk
dosyasn kaynak koda eklemektir. STL ilevlerinin byk ounluu istenilen bir veri
yaps zerinde (dinamik dizi, bal liste, ikili aa) ilem yapmaktadr. Diziler de bir veri
yaps olarak ele alndklarndan, bir ok STL ilev ablonu diziler zerinde de ilem
yapabilir. Bu ilevler daha sonra ayrntl olarak ele alacamz iterator mantna
dayandrlmtr. Algoritmalarn ou bir veri yapsnda bulunan ilk elemannn ve sondan
bir sonraki elemannn konum bilgisini alacak biimde dzenlenmitir. Algoritmalarn ou
normal diziler iin de kullanlabilir. Normal bir dizi sz konusu olduunda, dizinin ilk
elemannn ve son elemandan bir sonraki elemann adresi algoritmaya geilerek,
algoritmann dizinin tm elemanlar zerinde i yapmas salanabilir. Aada STL'de
bulunan baz ilev ablonlar rnek olarak veriliyor. STL blmnde tm ilev ablonlarn
tek tek ele alacaz.

sort lev ablonu


Elemanlar bellekte ardl olarak yer alan bir veri yapsnda tutulan elemanlar sralamak
iin kullanlr. ablonun bildirimi aadaki gibidir:
template<classRandomIt>
voidsort(RandomItfirst,RandomItlast);
Herhangi trden bir dizi ya da dinamik bir dizi sz konusu olduunda ilevin first ve last
isimli ar parametrelerine, sralanacak dizinin ilk elemannn ve son elemandan bir
sonraki nesnenin adresi geilmelidir.

find lev ablonu


find ilev ablonu ile bir veri yapsnda bir deer sral bir biimde aranr, aranan deer
bulunursa bulunduu yerin konum bilgisi ile bulunamaz ise son elemandan bir sonraki
elemann konum bilgisiyle geri dnlr:
template<classInputIt,classValueType>
InputItfind(InputItfirst,InputItlast,constValueType&val);

copy lev ablonu


copy ilev ablonu bir veri yapsndaki elemanlar bir baka veri yapsna kopyalamak iin
kullanlr. lev, kopyalanacak veri yapsndaki ilk ve sondan bir sonraki elemann konum
bilgilerini ve kopyalamann yaplaca hedef veri yapsndaki ilk elemann konum bilgisini
alr. lev hedef veri yapsndaki sondan bir sonraki elemann konum bilgisiyle geri dner:
template<classInputIt,classOutputIt>
OutputIterator
copy(InputItsourceBeg,InputItsourceEnd,OutputItdestBeg);

random_shuffle lev ablonu


Bellekte bitiik olarak yer alan bir veri yapsnda tutulan elemanlar kartrmak iin
kullanlr. Kartrma ilemi rastgele elemanlarn yer deitirmesiyle yaplan bir ilemdir.

253/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


template<classT>
voidrandom_shuffle(RandomItfirst,RandomItlast);

for_each lev ablonu


Bir veri yapsndaki tm elemanlarn belirli bir ilemden geirilmesi amacyla kullanlr.
ablonun bildirimi aadaki gibidir:
template<classInputIt,classUnaryProc>
UnaryProc
for_each(InputItbeg,InputItend,UnaryProcop)
Veri yapsnn (first last) aralndaki tm elemanlar op ar parametresiyle belirlenen
ileve argman olarak gnderilir.
Aada rnek olarak verilen ilev ablonlarna ilikin rnek bir kod veriliyor:
template<typenameT>
voiddisplay(Tbegin,Tend)
{
for(Titer=begin;iter!=end;++iter)
std::cout<<*iter<<"";
std::cout<<endl;
}
voidfunc(int&r)
{
r%=5;
}
#include<iostream>
#include<algorithm>
#include<cstdlib>
intmain()
{
constintsize=20;
inta[size];

for(intk=0;k<size;++k)

a[k]=rand()%100;

cout<<"adizisiyazdrlyor"<<endl;
display(a,a+size);
sort(a,a+size);
cout<<"adizisisraland"<<endl;
cout<<"adizisiyazdrlyor"<<endl;
display(a,a+size);
random_shuffle(a,a+size);
cout<<"adizisikartrld\nadizisiyazdrlyor"<<endl;
display(a,a+size);
cout<<"dizidearanacakde?erigirin:";
intval;
cin>>val;
int*ptr=find(a,a+size,val);
if(ptr==a+size)

cout<<"dizide"<<val<<"degeribulunamad!"<<endl;
else{

cout<<"bulundu!"<<endl;

254/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


*ptr*=*ptr;
cout<<"adizisiyazdrlyor"<<endl;
display(a,a+size);
}

intb[size];
copy(a,a+size,b);
cout<<"bdizisiyazdrlyor"<<endl;
display(b,b+size);
for_each(b,b+size,func);
cout<<"for_eachilevindensonrabdizisiyazdrlyor"<<endl;
display(b,b+size);

return0;
}

255/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

ALIMA ZAMANI HATALARININ YAKALANMASI


VE LENMES
alan programlarda herey beklendii gibi gelimeyebilir. Oluturulan programlarn
almasnda beklenmedik durumlar ortaya kabilir. rnein programn almas annda
bir dosyann almas gerekiyor iken eitli nedenlerden bu dosya alamayabilir. Heap
alanndan (C++ dilindeki ismiyle free store'dan) yaplmaya allan bir dinamik yer
ayrma ilemi, yeteri kadar bo alan olmad iin baarsz olabilir. Program kullanan
kiinin girdii veri ya da veriler, programn bekledii dorultuda, kabul edilebilir snrlar
iinde olmayabilir. Program iinde beklenmedik bir verinin ilenmesi sonucu sfra blme
ilemi yaplyor olabilir. Bir dizinin bir elemanna bir atama yaplmak istenirken, ayrlm
olan bir bellek alannn dna yanllkla erimek sz konusu olabilir. Buna benzer
beklenmedik durumlara C++ programclnda "exception" denir. Bir ilev iinde byle bir
hata olutuunda ne yaplmaldr? Eer ne yaplmas gerektii ak bir ekilde biliniyorsa,
bir hatann olumas durumunda yaplmas gerekenler yaplabilir. Ancak temel sorun
udur: Darya hizmet vermek amacyla tanmlanan bir ilev, ne durumda arlm
olduunu bilemez, yani ou zaman tanmlanan ilevin iinde bir hata durumu olutuu
saptanabilse de, ne yaplmas gerektii konusunda yeterli bilgi yoktur. Hata olutuu
zaman ne yaplmas gerektiine ou zaman, iinde hata oluan ilevi aran kodlar
tarafndan karar verebilir.
O zaman iinde hata oluan ilevin sorumluluu hata durumunu kendisini aran
ilevlere bildirmektir. inde hata oluan kod, kendisini aracak ilevleri bu durumdan
haberdar etmelidir. Bylece bu ilevi arm olan ilevler, hata durumu hakknda bilgi
sahibi olduklarnda, gerekirse bir nlem alma ansna sahip olur.
Peki bir ilev iinde bir alma zamannda beklenmedik bir durumun olumas durumunda
ne yaplabilir? Programc bu durumda, program kullanann bir zarar grmemesi iin ne
gibi nlemler alabilir? te exception handling (alma zaman hatalarnn yakalanmas
ve ilenmesi) C++ dilinin doal aralarndan biri olan ve bu konuda kullanlan bir
mekanizmadr. C++ dilinin hatalarn yakalanmas ve ilenmesi mekanizmasn yakndan
tanmaya balamadan nce, bu konuda kullanlan geleneksel aralar inceleyelim ve
nesne ynelimli programlama tekniinde bu aralarn neden yetersiz kaldn grelim.
C++ dilinin ilk dnemlerinde dilin kendi yaps iinde alma zaman hatalarnn
yakalanmas ve ilenmesi mekanizmas yoktu. Bu ama iin C dilinde de kullanlan
geleneksel yntemler kullanlyordu. Bu yntemler 3 ana grup altnda toplanabilir:
1. levlerin, yaptklar i konusunda baarl ya da baarsz olduklarn gsteren bir geri
dn deeri retmeleri (Bir hata deerinin geri dndrlmesi).
2. Baarszlk durumunda global bir bayrak deikene ilgili hatay belirleyen ayrt edici bir
deer atanmas (hata deeri) ve dier ilevlerin bu global deikenin deerini snyarak
nlem almalar.
3. Programn almasnn sona erdirilmesi.
Nesne ynelimli programlama sz konusu olduunda her yntemin de ok nemli
yetersizlikleri ve sakncalar vardr. Bu yetersizlik ve sakncalardan bir ksm zellikle ok
byk projeler sz konusu oldugunda, kabul edilebilir olmaktan kar. imdi bu
sakncalarn neler olabilecei konusuna deinelim:

Bir Hata Deerinin Geri Dndrlmesi


Bu teknik kk programlarda belirli bir yere kadar kullanlabilir. levler bir hata
durumunda, daha nceden belirlenmi olan hata deerlerine geri dner. arlan
ilevlerin geri dn deerleri snanarak bir hata oluup olumad, ve ne tr bir hatann
olutuu saptanr. Ancak bu tekniin nemli dezavantajlar vardr. Geri dn deeri
olarak verilen hata deerleri bir standarda bal deildir. Bir ktphanede rnein 0

256/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


deeri baarszlk belirtirken baka bir ktphanede 0 deeri baar durumunu
gsterebilir. C dilinin standart ilevleri iin bile bu konuda bir birlik olduunu
syleyemeyiz. Dosya aan standart C ilevi olan fopen ilevinin 0 (NULL) deeri dosyann
baarl bir ekilde alamadn gsterirken, dosyay kapayan fclose ilevinin 0 olan geri
dn deeri dosyann baarl bir ekilde kapatldn gstermektedir. C dilinde uygulama
gelitirenler genellikle ilevin baar ya da baarszlklarn gsteren geri dn
deerlerini simgesel deimezler biiminde tanmlayarak balk dosyas iine yerletirir.
Ancak phesiz bu simgesel deimezler de standart bir hale getirilmemitir.
Ayr ekipler tarafndan farkl zamanlarda gelitirilmi ktphaneler, ayn proje iinde
kullanldnda, hata durumlar sz konusu olabilir. levlerin geri dn deerlerinin farkl
biimlerde yorumlanmas karklklar yaratr.
Ayrca her bir geri dn deerinin snanmas ve yorumlanmas, zahmetli ve zaman alc
bir ilemdir. ou zaman bunun iin ek bir koda gereksinim duyulur. lev her
arldnda geri dn deeri mutlaka ilenmelidir. Geri dn deeri snanmadan
kullanlrsa, baz durumlarda alan program bile kebilir. rnein malloc ilevinin geri
dn deerinin, snanmadan kullandn dnelim. malloc ilevi baarsz olduunda
NULL adresine geri dner. Bylece bir gsterici hatasna neden olunur.
arlan bir ilev iinde bir hata durumu oluursa, arlan ilevin yrtlmesi, normal
olarak retecei geri dn deeri ifadesine gelmeden nce, hata olutuu bilgisini veren
bir baka return deyimiyle sonlandrlr. Baka bir kod da ilevin geri dn deerini
snayan ve ilev herhangi bir hata deeri geri dndrmse, programn devam edip
etmemesi hakknda karar veren ek kod parasdr. Bu da bir ok durumda yazlan kodun
boyutunu byk lde artrr ayrca programn okunabilirliini bozar, programn
gelitirilmesi ve test edilmesi konusunda sakncalar yaratr.
Baz durumlarda arlan ilev iinde bir baarszlk ya da hata olutuunda, bu durumu
darya iletecek zel bir hata deeri kullanlamaz. rnein bir adrese geri dnen bir ilev,
baarszlk ya da bir hata durumunda NULL adresine geri dnebilir. Ama hesap edilmek
istenen bir tamsay deerine geri dnen bir ilev, bir hata durumu olutuunda hangi
deere geri dnebilir? nk ayrt edici ve hatay gsterebilecek bir deer sz konusu
deildir. C dilinden tandmz atoi ilevini ele alalm:
intatoi(constchar*str);
atoi ilevi adresini ald yazdan, karakterler olarak kodlanm int trden bir deeri
ekerek geri dn deeri olarak iletir. Peki ya yaz bir int deeri gsteren geerli bir yaz
deilse atoi ilevi hangi deer ile geri dnebilir? Derleyicilerin ou bu durumda atoi ilevi
0 deeriyle geri dndrr. Bu da pheli bir durum yaratr. Peki atoi ilevine gnderilen
yaznn iinde gerekten "0" varsa ve bu deerin elde edilmesi gerekiyorsa?
nemli bir nokta da C++ dilinde baz ilevler iin geri dn deeri diye bir kavramn sz
konusu olmamasdr. rnein kurucu ilevler (constructors), tr dntrme ilevler iin
geri dn deeri diye bir kavram sz konusu deildir. Bu ilevler iinde oluabilecek hata
durumu yukarda anlatlan geleneksel teknikle yakalanamaz.

Global Bir Bayrak Deikene Deer Atanmas


alma zaman hatalarnn bildirilmesinde alternatif bir teknik de global bir deikene
atama yaplmasdr. Global bir deikenin deeri yaplan son ilemin baars hakknda bir
fikir verir. C dilinde hata durumunda geri dn deeri mekanizmas standart bir hale
getirilmemitir ama global bir deikene atama yaplmas mekanizmas standart bir hale
getirilmitir. C dilinin standart bir balk dosyas olan <errno.h> dosyas global bir
deiken olan errno deikenine deer atanmas konusundaki mekanizmay tanmlar.
Standart ilevler iinde bir hata durumu olutuunda errno deikenine ayrt edici bir
deer atanr. Bu yntemin de nemli sakncalar vardr: ok ilemli bir almada (multithread) bir ak iindeki ilev ars yznden oluan bir hata durumu, ilgili global
deikenin deeri daha snama amacyla alnamadan baka bir ak tarafndan tekrar
deitirilebilir. Ayrca byle bir hata kodunun global bir deikenden srekli olarak
alnarak okunmas ok disiplinli bir programlama teknii gerektirmektedir.

257/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Global bir deikene yaplan atama ya da ilevin geri dn deerinin snanmas ilev
iinde oluan bir hatay ilevi arana iletebilir ancak bu hatann ortadan kaldrlmas
konusunda bir ey yaplmaz. rnein dosya aan bir ilev dosyann alamadn darya
bildirebilir ancak baka bir ilevin alamam olan bu dosyaya bir veri aktarmas ve bu
dosyay kapatmas konusunda bir nlem alamaz. Dahas errno gibi bir deikenin deeri
alndktan sonra, snamay yapan kii tarafndan tekrar sfrlanmas gerekir ki, bundan
sonra saptanacak hata bildirimlerinde bir yanllk olumasn. Eer programc global
deikeni tekrar normal deerine getirmeyi unutursa baka bir ilevin baars
snandnda, ilev aslnda baarl olmu iken programc tarafndan ilevin baarsz
olduu gibi yanl bir yargya varlabilir. Bylece gereksiz bir ekilde, olmayan bir hata
ilenmeye allr ki bu da phesiz beklenmeyen sonular yaratabilir.

Programn Sonlandrlmas
alma zamannda oluan hatalarn ilenmesi konusundaki en kkten aralardan biri
ciddi bir hata ile karlaldnda programn aknn sonlandrlmasdr. Bu durum
phesiz ilk iki yntemdeki baz yklerden programcy kurtarr. Program bir hata
olutuunda sonlandrlaca iin arlan bir ilevin geri dn deerinin bir hata
durumunun saptanmas amacyla snanmasna, ya da global bir bayrak deikeninin
deerinin her ilev arsndan sonra snanmasna gerek kalmaz. Standart C dilinde bir
programn sonlandrlmas iki ayr ilevle gerekletirilebilir. exit ve abort ilevleri. Bu
ilevleri ksaca hatrlayalm:

exit levi
Bir standart C ilevi olan exit, cstdlib balk dosyas iinde bildirilmitir.
voidexit(intstatus);
exit ilevi, arld zaman program sonlandrr. exit ilevi, main ilevi baarl bir ekilde
sona erdiinde arlabilecei gibi, bir hata durumununun olumas durumunda da
arlabilir. exit ilevi, kontrol iletim sistemine devretmeden nce btn dosyalarn
tampon alanlarn tazeler (flush eder), tm ak dosyalar kapatr. exit ilevine gnderilen
0 deeri, programn baaryla sonlandrldn anlatrken sfr d bir deer ise programn
baarszlk nedeniyle sonlandrld iletisini verir. exit ilevine ar olarak gemek iin,
okunabilirlik asndan cstdlib balk dosyas iinde aadaki simgesel deeimezler
tanmlanmtr:
#define
#define

EXIT_SUCCESS
EXIT_FAILURE

0
1

C++'ta exit ilevi arlrsa program sonlandrlmadan nce tm global snf nesneleri iin
sonlandrc ilevler arlr. Ancak yaratlm olan yerel snf nesneleri ve dinamik snf
nesneleri iin sonlandrc ilevler arlmaz.
exit ilevi arldnda programn sonlandrlmasndan nce, programcnn belirleyecei
baz ilevlerin arlmas salanabilir. Bu amala standart atexit ilevi kullanlr:
atexit ilevinin de bildirimi stdlib.h balk dosyas iindedir:
intatexit(void(*)(void);
Yukardaki bildirimden de grld gibi atexit ilevinin parametre deikeni geri dn
deeri ve parametresi olmayan bir ilevi gsterecek gstericidir. atexit ilevine adresi
gnderilen ilev, exit ileviyle program sonlandrlmadan nce arlmak zere kaydedilir.
levin geri dn deeri ilevin baar durumunu gsterir. levin 0 deerine geri
dnmesi kayt ileminin baarl olduunu anlatrken 0 d bir deere geri dnmesi
baarszlk durumunu bildirir. atexit ileviyle birden fazla ilev kayt edilebilir. Bu durumda

258/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


kayt edilen ilevler, kayt edilmelerine ters srada arlr. Aadaki program derleyerek
altrnz:
#include<iostream>
#include<cstdlib>
usingnamespacestd;
voidfunc1()
{
cout<<"func1()"<<endl;
}
voidfunc2()
{
cout<<"func2()"<<endl;
}
voidfunc3()
{
cout<<"func3()"<<endl;
}
intmain()
{
atexit(func3);
atexit(func2);
atexit(func1);
exit(EXIT_FAILURE);
}

abort levi
abort ilevi de cstdlib balk dosyasnda bildirilmitir:
voidabort(void);
abort ilevi arldnda program sonlanr. abort arld yere baar durumu gsteren
bir deer iletmez. Bu ilev programn anormal bir ekilde sonlandrlmasna iaret eder.
lev stderr akmna "abnormal program termination" yazsn yazarak program
sonlandrr. abort ilevi ile program sonlandrldnda dosyalarn tampon alanlar
tazelenmez, ne yerel ne de global snf nesneleri iin sonlandrc ilevler arlr.
Kritik uygulamalarda bir hata olumas durumunda birdenbire programn sonlandrlmas
kabul edilebilecek bir yaklam deildir. rnein bir hastahanedeki yaam destek nitesini
yneten bir program iinde beklenmedik bir durum olutuunda programn
sonlandrlmas durumu kabul edilebilir mi? Ticari bir ok uygulamada da durum byledir.
Bir faturalama program, bankacla ynelik bir uygulama, bir hata olutu diye birdenbire
sonlandrlamaz. Gerek hayata ilikin programlarda bu durumlar iin yeterli ve gerekli
nlemlerin alnmas gereklidir.
letim sistemi gibi bir uygulamada bile, alma zamannda ciddi bir hatann olumas
durumunda programn (iletim sisteminin) sonlandrlmas sorunlu durumlar yaratabilir.
alan bir ilev bir hata durumu saptadnda ou zaman oluan hatann ciddiyeti
konusunda bir fikir sahibi olamaz. rnein dinamik blok elde etmeye alan bir ilev, sz
konusu ilemin baarsz olmas durumunda, dinamik yer ayrma ileminin ne amala
yapldn bilmez. rnein dinamik yer elde etme ilemi programcnn bir debugger
kullanmas annda ya da bir tablolama programn kullanmas durumunda istenmise,
pekala bir uyar iletisi verilerek kullancnn ak olan btn programlar kapatarak iini

259/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


yle srdrmesi istenebilir. Ancak dinamik yer ayrma ileminin baarszlk nedeni
tamamyla donanmsal da olabilir. Bu durumda daha ciddi bir nlem alnmas gerekir. Yani
hatann ne nedenle olup olmad programn sonlandrlaca m yoksa bir nlem alnarak
srdrlecei mi konusunda bir seim ans verilmelidir.
Baz durumlarda exit ya da abort ilevleriyle programn ak sonlandrlabilse de nesne
ynelimli programlama ortamnda, programn ak bu ilevler ile sonlandrlmamaldr,
zira bu ilevler C++ dilinin nesne tabanl programlama modeli hakknda bilgi sahibi
deillerdir.
C++ dilinde bir snf nesnesi, kurucu ilev ya da herhangi bir ye ilevi kanalyla bir takm
kaynaklar tutabiliyor olabilir. Bu kaynaklar, dinamik olarak elde edilen bloklarn balang
adresleri, dosyalara ilikin handle deerleri, iletiim amacyla portlara ilikin set edilmi
deerler, giri k birimlerine ilikin aygtlar, kilit kontrolleri vs. olabilir. Birok durumda
bu kaynaklarn, nesnenin yapt i bitince serbest braklmas ya da geri verilmesi gerekir.
C++ dilinde genel olarak bu kaynaklar nesneye ilikin sonlandrc ilev yardmyla geri
verilirler ya da serbest braklr. Yerel snf nesneleri, bilinirlik alanlar sona erdiinde
otomatik olarak serbest braklr. Ancak ne exit ne de abort ilevi yerel nesnelerin
sonlandrc ilevlerinin arlmasn salar. Bu nedenle programlarn bu ilevler ile ani
olarak sonlandrlmas, geri dn olmayan zararlarn olumasna neden olabilir. Bir veri
taban sistemi tamamyla bozulabilir, dosyalar kaybedilebilir, deerli veriler kaybolabilir.
Nesne ynelimli programlamada exit ve abort ilevleri kullanlmamaldr!
Grld gibi, C dilinin hata saptamasna ve ilenmesine ilikin geleneksel yntemlerden
hibiri C++ dili iin yeterli deildir. C++ dilinin kullanlmasndaki ana temalardan biri
byk projelerin C diline gre daha iyi ve daha gvenli bir ekilde yazlmasna olanak
salamasdr.
C++ dilinin dinamik gelime sreci iinde C++ dilinin yaratclar alma zamanna ilikin
hatalarn yakalanmasna ve ilenmesine ilikin yeterli bir mekanizmann eksikliinin
farknda olduklarndan, yukardaki sakncalar iermeyen bir yntemin arayna girdiler.
nerilen sistem, beklenmeyen bir durum olutuunda programn aknn otomatik olarak,
hatay ileyecek bir kod parasna akn salanmasyd. Sz konusu yntem basit ve etkili
olmalyd, bir takm deerlerin srekli olarak test edilmesi ilkesine dayanmamalyd. Fakat
en nemlisi, bir hata olutuunun saptanmas durumunda, hatay ileyen kodun bu
durumdan otomatik olarak haberdar olmasnn salanmasyd. Ayrca bir hata yerel olarak
kendi kod grubu iinde ilenemediinde, o kapsamdaki yerel snf nesnelerinin tutmakta
olduu kaynaklar, daha genel bir hata ileyicisinin devreye girmesinden nce, sisteme
iade edilmeliydi. Uzun sren incelemeler ve aratrmalar sonucunda alma zamannda
oluan hatalarn yakalanmasna ve ilenmesine ilikin bir mekanizmaya ynelik tasar
1989 ylnda kabul edilerek C++ diline eklendi. C++ ncesinde baka programlama dilleri
bu ynde mekanizmalar oluturmutu. rnein daha 1960'l yllarda PL/1 dili dilin kendi
yaps iinde var olan bir hata ileme mekanizmasna sahipti. Yine 1980'li yllarn
balarnda Ada dili byle bir mekanizmay kendi bnyesi iine katmt. Fakat bu
mekanizmalar C++ dilinin nesne ynelimli programlama yaklamna uygun
dmyorlard. Bu yzden C++ diline eklenen mekanizma kendi tr iin ilkti ve
kendisinden sonra gelitirilen bir ok programlama dili tarafndan kullanld.
alma zamannda hatalarn yakalanmasna ve ilenmesine ilikin bir mekanizmann
programclara salanmas derleyiciyi yazanlara eitli zorluklar getirir. rnein ilk C++
derleyicisi olan cfront UNIX iletim sistemi altnda alyordu. Bir ok UNIX derleyicisi gibi
cfront da nce C++ kaynak kodunu C koduna dntryor daha sonra elde edilen C
kodunu derliyordu. cfront derleyicisinin 4.0 srmnn hata ileme mekanizmasna sahip
olmas planlanmt. Ancak btn gerekleri salayan bir hata ileme mekanizmasnn
gelitirilmesi o kadar karmak bir prosesti ki, 4.0 srmn gelitiren ekip, almaya
balamasndan 1 yl sonra projeyi sonlandrma karar ald. cfront 4.0 srm hi olmad.
Ancak daha sonra hata ileme mekanizmas C++ dilinin doal bir arac durumuna
getirildi. Daha sonraki derleyiciler daha sonra bu arac desteklemeye balad.

260/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

alma Zaman Hatalarn Saptama ve leme Mekanizmasn


mplemente Etmek Neden Zordur?
Mekanizmay bir derleyicinin implemente etmesindeki birinci zorluk oluan belirli hatay
ileyecek uygun bir kodun (handler) bulunmasdr.
kinci zorluk, hatay saptayan kod parasnn hatay ileyecek koda gnderecei hata
nesnesinin ok biimli zelliklere sahip olabilmesidir. Yani tremi snf trnden bir hata
nesnesini ileyecek olan uygun bir ileyici kod bulunamad zaman taban snf trnden
nesneyi alabilecek bir hata ileme kodunun devreye girebilmesidir. Ancak ilk zamanlarda,
ok biimlilii destekleyen bir nesnenin alma zamanndaki trn saptayacak bir
mekanizma (Dynamic typing) C++ diline eklenmemiti. Hata ileme aracnn yeterli bir
duruma getirilebilmesi iin nce dinamik tr kontrol mekanizmasnn sfrdan
gelitirilmesi gerekiyordu.
Baka bir komplikasyon da hatann ilenmesi durumunda, hata ileyici ileve programn
akn ynlendirmeden nce yerel snf nesnelerinin sonlandrc ilevlerinin arlmasnn
salanmasyd. Bu mekanizmaya ngilizcede yn dengelenmesi (stack unwinding) denir.

alma Zaman Hata leme Mekanizmasnn Uygulanmas


Exception Handling esnek ve karmak bir aratr. C dilinde kullanlan geleneksel hata
ileme yntemlerinin sakncalarn iermez ve ok eitli alma zaman hatalar iin
kullanlabilir. Ancak bir kaynak kod iinde, C++ dilinin dier aralar gibi bu ara da kt
kullanlm olabilir. Bu mekanizmay etkili bir ekilde kullanabilmek iin, mekanizmay iyi
bir ekilde tanmak ve geri planda makina dzeyinde neler olduunu anlamak gerekir.

alma Zaman Hata leme Mekanizmasnn Bileenleri


CZHI mekanizmasnda, alma zaman iinde bir hata olutuunda programn ak bu
hatay ileyecek uygun bir kod parasna (handler) ynlendirilir. Bu ynlendirmeyle
birlikte hatay ileyen koda bir nesne deerle (call by value) ya da adresle (call by
reference) geilir. Sz konusu nesneye bundan sonraki blmlerde "hata nesnesi"
(exception object) diyeceiz. Hata nesnesi doal veri trlerinden olabilecei gibi, bir snf
trnden de olabilir.
Mekanizmann drt bileeni vardr.

try blou
try blou ile ilikilendirilen catch bloklar (hata ileyen kodlar -handler)
throw ifadesi
hata nesnesinin kendisi

Mekanizma kabaca yle zetlenebilir:


alma zaman iinde bir hata olutuunda bu durumda throw ifadesiyle bir hata nesnesi
gnderilir. Gnderilen bu hata nesnesini hata ileyen kodlardan uygun olan bir tanesi
yakalar. Eer hata yakalanamaz ise standart abort ilevi arlarak program sonlandrlr.

throw Anahtar Szc ve Hata Nesnesinin Gnderilmesi


throw C++ dilinin bir anahtar szcdr. throw anahtar szcn bir ifade izler. throw
anahtar szcn izleyen ifade gnderilen hata nesnesinin trn ve deerini belirler.
Gnderilen hata nesnesini bir hata ileyen kod paras yani ingilizce ismiyle bir handler
yakalar. throw ifadesi herhangi bir ilevin iinde yer alabilir. Aadaki kod parasn
inceleyin:

261/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


int&Array::at(intindex);
{
if(index>=m_size)
throwindex;
returnpd[index];
}
Yukarda Array snfnn at isimli ye ilevinin tanm yer alyor. levin kaynak kodu iinde,
dardan gelen index deerinin geerli olup olmad snanyor. index deeri geerli
deilse, int trden bir hata nesnesi gnderiliyor.

try Blou
try C++ dilinin bir anahtar szcdr. try anahtar szcn bir bloun izlemesi
zorunludur. inden bir hata nesnesi gnderilme olasl bulunan kod paras bir try blou
iine alnabilir:
#include<iostream>
#include"array.h"
intmain()
{
Arraymyarray(10);
intindex;

std::cout<<"birindexdegerigirin";
std::cin>>index;

try{
intx=myarray.at(10);
}
//...
return0:
}
Yukardaki main ilevinde arlan at ilevi iinden bir hata nesnesi gnderilebilecei iin
intx=myarray.at(10);
deyimi bir try blou iine alnm.
Bir try blou iinde C++ dili szdizimine uygun herhangi bir deyim bulunabilir. try blou
iinde bildirim ya da tanmlama yaplabilir. Bir try blou yerel bir bilinirlik alan oluturur.
Bir try blou iinde bildirimi yaplan deikenler bu bloun dnda grlmez.

catch Anahtar Szc ve catch Bloklar


catch C++ dilinin bir anahtar szcdr. catch anahtar szcn alan ve kapanan bir
ayra izler. Bu ayra iinde, ilevlerdeki parametre deikeni bildirimine benzer bir ekilde
deiken bildirimi yaplabilir. Ayralardan sonra yine bir blok yerletirilir. catch anahtar
szcn bir ayracn izlemesi ve ayracn kapanmasndan sonra da bir bloun
yerletirilmesi szdizimsel bir zorunluluktur.
catch blou hatay ileyen bloktur(handler). catch bloklar try bloklarn izler. Bir try
bloundan sonra herhangi bir catch blounun yer almamas geersizdir. Eer bir catch
ayrac iinde tanmlanm nesnenin tr ile gnderilen hata nesnesinin tr tamamen
ayn ise, catch parametresine gnderilen hata nesnesinin deeri aktarlr. Programn ak
catch blou iinde akmaya ynlendirilir. Bu duruma "gnderilen hata nesnesinin

262/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


yakalanmas" denir. Bir try blou ayr bir bilinirlik alan belirtir. Bu blok iinde tanmlanan
nesneler try blounu izleyen catch bloklar iinde bilinmez.
try blou ile catch blou arasnda baka bir kod olamaz. Bir try bloundan sonra istenilen
sayda catch blou yer alabilir. imdiye kadar anlatlanlar bir kod paras ile
rnekleyelim:
#include<iostream>
#include<cstdlib>
usingnamespacestd;
intmain()
{
intval;
cout<<"pozitifbirsayigiriniz:";
cin>>val;
try{
if(val<0)
throwval;
}
catch(intx){
cout<<x<<"negatif!programsonlaniyor!"<<endl;
exit(EXIT_FAILURE);
}
cout<<val<<"degerigirildi!"<<endl;
return0;
}
Bir try blounu birden fazla catch blou izleyebilir. Bu durumda catch parametrelerinin
trlerinin farkl olmas gerekir. Ayn trden nesne bekleyen birden fazla catch
parametresinin bulunmas geersizdir. Aadaki rnei inceleyin:
#include<iostream>
voidmay_raise_exception();
intmain()
{
try{
may_raise_exception();
}
catch(int){
//...
}
catch(double){
//...
}
catch(long){
//...
}
std::cout<<"programnakisibunoktadandevamedecek!"<<std::endl;
//...
return0;
}

263/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Yukarda tanmlanan main ilevi iinde bir try blou oluturuluyor. Oluturulan try blou
iinde may_raise_exception ilevi arlyor. try blounu ayr catch blou izliyor. Birinci
catch blou ya da baka bir deyile birinci hata ileyen blok, int trden bir hata nesnesini
yakalamaya alyor. kinci hata ileyen blok, double trden, -nc hata ileyen blok,
long trden bir hata nesnesini yakalamaya alyor. Herhangi bir catch blou gnderilen
hata nesnesini yakalarsa, programn ak iinde ilgili catch blounun iindeki deyimler
yrtlr. Programn ak catch bloundan sonra en son catch bloundan sonra yer alan
deyimle srer.
catch bloklar break deyimiyle sonlanan case'ler gibidir. Uygun bir catch blou bir hata
nesnesini yakaladnda programn ak bu catch blounun iine girer. Bu catch blounun
kodu yrtldkten sonra programn ak son catch blounu izleyen kod parasnn
yrtlmesiyle srer.
try blou iine alnan kod paras iinde gnderilen hata nesnesinin yakalanmas iin
throw ileminin dorudan bu blok iinde yaplmas gerekmez.
try{
func();
}
catch(int){
//...
}
Yukardaki try blou iinde func ilevi arlyor. func ilevi iinde arlan bir ilevin de,
int trden bir hata nesnesi gndermesi durumunda, catch blou bu hata nesnesini de
yakalar.

throw fadesiyle catch Parametresinin Uyumu


Bir catch blounun gnderilen hata nesnesini yakalayabilmesi iin throw ifadesi ile catch
parametresinin trlerinin tamamen ayn olmas gerekir. catch parametresinin nnde
bulunan const ya da volatile niteleyicileri tam uyumu bozmaz. Ancak dier otomatik tr
dnm ve ykseltme kurallar burada geerli deildir. rnein throw ifadesi char
trden catch parametresi int trden ise, tamsayya ykseltme (integral promotion) kural
iletilmez. Benzer ekilde gnderilen hata nesnesinin trnn float tr olduunu kabul
edelim. Parametresi double trden olan bir catch blou float trden bir hata nesnesini
yakalayamaz.

Gnderilen Hata Nesnesinin Bir Snf Trnden Olabilmesi


inde alma zamann hatasnn oluabilecei kod parasnn, hatay ileyecek kod
parasna gnderdii hata nesnesi, bir snf trnden de olabilir. Bu durumda phesiz bu
hatay yakalayacak catch blounun parametresi ayn snf trnden bir nesne ya da ayn
snf trnden bir referans olmaldr.
Hata nesnesi oluturmada ounlukla doal trler yerine snf nesneleri kullanlr. Bylece
hata olutuunda gnderilen snf nesneleri catch parametresine alndktan sonra, snfn
ye ilevleri kullanlarak oluan hata ele alnr. Snf ktphanelerinin ounda ok
biimlilii destekleyen hata ileme snflar vardr. C++ standart ktphanesinde de
hiyerarik hata ileme snflar tanmlanmtr.
Bir ktphane iinden gnderilecek hata nesnelerinin bir snf hiyerarisi biiminde
organize edilmesinin nemli bir faydas da, ktphaneye yeni hata snflarnn
eklenmesinden sonra hata ileyen kodlarda bir deiikliin gerekmemesidir.

catch all Blou


stenirse, ne trden olursa olsun gnderilen bir hata nesnesinin bir catch blou tarafndan
yakalanmas salanabilir. Bu durum catch blou ayrac iine nokta atomu (elipsis)
yerletirilmesiyle salanr:

264/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


try{
func();
}
catch(){
//
}
Yukardaki rnekte, try blou iinde arlan func ilevi iinden ne trden hata nesnesi
gnderilirse gnderilsin, try blounu izleyen catch all blou bu hata nesnesini yakalar.

catch Bloklarnn Uygun Sras


Uygulamalarda genellikle catch bloklarnn parametreleri, en zel olandan en genel olana
doru yukardan aaya doru seilir. Yani tremi snf parametreli catch bloklar taban
snf parametreli catch bloklarndan daha yukarda yer alr. nk catch bloklar yukardan
aaya doru taranr. Aadaki kodu inceleyin:
#include<stdexcept>
#include<iostream>
usingnamespacestd;
intmain()
{
try{
char*buff=newchar[100000000];
//...
}
catch(bad_alloc&r){
cout<<"memoryallocationfailure";
//...
}
catch(exception&r){
cout<<r_exception.what()<<endl;
}
catch(...){
cout<<"bilinmeyenhatanesnesi"<<endl;
}
return0;
}
main ilevinde yer alan try blou iinde, new ileciyle byk bir dinamik blok elde
edilmeye allyor. try blounu izleyen ilk catch blou bad_alloc snf trnden hata
nesneleri yakalanmaya allyor. bad_alloc trnden bir hata nesnesi yakalandnda
daha aadaki catch bloklarna hi baklmaz. kinci catch blou ile standart exception
snfndan tremi herhangi bir snf trnden hata nesnesi yakalanabilir. catch blou
iinde snfn what ye ileviyle, hatann niteliini gsteren bir yaznn ekrana yazdrldn
gryorsunuz. Son catch blou catch all bloudur. Bu bloa kadar yakalanamayan bir
hata nesnesi mutlaka catch all blou tarafndan yakalanr. Eer proje iinde gnderilen
tm hata nesneleri exception snf hiyerarisine ait snflardan ise, normal olarak catch all
blou tarafndan hi bir hata nesnesinin yakalanamamas gerekir. Bu blok tarafndan bir
hatann yakalanmas projeyi yazanlarn kontrol dnda bir hata nesnesinin gnderilmi
olduunu gsterir.

Yakalanamayan Hata Nesnesi


Gnderilen bir hata nesnesinin bir catch blou tarafndan yakalanamamas durumuna
"yakalanamayan hata nesnesi" (uncaught exception) denir.

265/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Yakalanamayan hata durumunda terminate isimli standart bir ilev otomatik olarak
arlr. terminate ilevinin nceden belirlenmi (default) davran, standart abort ilevini
ararak program sonlandrmaktr. Standart terminate ilevinin kodunun aadaki gibi
olduunu dnebilirsiniz:
void(*fp)()=abort;
voidterminate()
{
(*fp)();
}
Ancak istenirse, terminate ilevinin abort ilevi yerine baka bir ilevi armas
salanabilir. terminate ilevinin programc tarafndan belirlenen baka bir ilevi
armasn salamak iin set_terminate isimli standart ilev arlabilir. Hem terminate
ilevinin hem de set_terminate ilevlerinin bildirimleri <exception> balk dosyas
iindedir:
typedefvoid(*terminate_handler)();
terminate_handlerset_terminate(terminate_handlerfp);
voidterminate()
Yukardaki bildirimden u anlam kartlr:
terminate_handler parametre deikeni olmayan ve geri dn deeri retmeyen bir
ilevi gsteren gsterici trnn yeni tr ismidir.
set_terminate ilevi terminate_handler trnden bir geri dn deerine ve
terminate_handler trnden bir parametre deikenine sahiptir. Daha uzun bir ifadeyle
set_terminate ilevinin geri dn deeri, geri dn deeri retmeyen ve parametre
deikeni olmayan bir ilev trnden adrestir. set_terminate ilevinin parametre
deikeni geri dn deeri retmeyen ve parametre deikeni olmayan bir ilevi
gsteren gstericidir. Bu durumda set_terminate ilevine bu trden bir ilevin adresi
geilmelidir. ilev isimlerinin ileme sokulduunda otomatik olarak ilgili ilevin balang
adresine dntrldn hatrlayn:
#include<iostream>
#include<exception>
#include<cstdlib>
usingnamespacestd;
voidmay_raise_exception()
{
throw"gnderilenhatanesnesiyakalanamayacak!";
}
voidmyterminate()
{
cout<<"Benmyterminateisleviyim"<<endl;
cout<<"gonderilenhatanesnesiyakalanamadigiicinbencagrildim"<<
endl;
cout<<"exitislevinicagirarakprogramisonlandiracagim!";
exit(EXIT_FAILURE);
}
intmain()
{

266/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


set_terminate(myterminate);
try{
may_raise_exception();
}
catch(int){
//...
}
catch(double){
//...
}
catch(long){
//...
}
cout<<"Hatanesnesiyakalanirsaprogramburadandevamedecek\n";
//...
return0;
}
Yukardaki rnekte, main ilevinde nce set_terminate ilevine daha nce tanmlanm
olan myterminate ilevinin adresi geiriliyor. Bylece terminate ilevi arldnda,
terminate ilevinin nceden belirlenmi davran olan abort ilevini armas yerine,
myterminate ilevini armas salanyor.
try blou iinde arlm olan may_raise_exception ilevi const char * trden bir hata
nesnesi gnderiyor. Ama try blounu izleyen catch bloklarnn hibirinde bu trden bir
hata nesnesi yakalanamyor. Bu durumda yakalanamayan hata durumu oluuyor.
Otomatik olarak terminate ilevi arlyor. terminate ilevi de myterminate ilevini
aryor. myterminate ilevi de ekrana bulgu iletilerini yazdktan sonra, exit ilevini
ararak program sonlandryor.

Ynn Dengelenmesi
Bir hata nesnesinin gnderilmesi ve gnderilen hata nesnesinin yakalanmas ilev ar
mekanizmasna benzer gibi grnse de aslnda durum ilev arsndan ok farkldr.
Aadaki rnei dikkatle inceleyin:
#include<iostream>
usingnamespacestd;
voidfunc1();
voidfunc2();
voidfunc3();
intmain()
{
func1();
//...
return0;
}
voidfunc1()
{
func2();
//...
return;
}

267/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidfunc2()
{
func3();
//...
return;
}
voidfunc3()
{
//...
return;
}

Yukardaki programda, main ilevi func1 ilevini, func1 ilevi func2 ilevini, func2 ilevi de
func3 ilevini aryor. Programn ak func3 ilevi iinde ilerlerken return deyimiyle
karlaldnda, ak func2 ilevinde kald yerden srer. func2 ilevinde return deyimi
ile karlaldnda ise bu durumda func1 ilevinde kalnan yerden ak srer. Nihayet
func1 ilevinin almas sona erdiinde, bu kez programn ak main ilevinde kald
yerden srer.
Oysa func3 ilevi iinde bir hata nesnesi gnderilmi olsayd, programn ak dorudan
bu hata nesnesinin yakaland catch blouna ynlenirdi. Bu durumu salamak iin
gerekletirilen ilemlere ynn dengelenmesi (stack unwinding) denir. Aadaki kodu
inceleyin:

268/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include<iostream>
voidfunc1();
voidfunc2();
voidfunc3();
intmain()
{
try{
func1();
}
catch(intx){
//...
}
//...
return0;
}
voidfunc1()
{
func2();
//...
}
voidfunc2()
{
func3();
//...
}
voidfunc3()
{
throw5;
//...
}
Yukardaki programda func3 ilevi iinde throw anahtar szcyle bir hata nesnesi
gnderildiinde, programn ak bu noktadan dorudan main ilevi iindeki catch blouna
ynlendirilir.
lev arlarnda arlan ilevin kodunun yrtlmesi sonunda, arlan ileve geri
dnlmesi normal olarak yna(stack) yazlan bilgilerle gerekleir. Programn almas
srasnda aran ilevin komutu yn alanna yazlr. arlan ilevin kodunun yrtlmesi
sona erdiinde, yani return deyimi ile karlaldnda program yn alanndan programn
aknn srecei noktann adresini alarak programn akn bu noktaya ynlendirir.
aran ilevin arlan ileve gndermi olduu arlar da yna yerletirilir. aran
ilevin kendisi de yerel deikenler tanmlanm ise bunlar iin de yn alannda yer
ayrlr. Eer arlan ilevin kendisi de bir ilevi armsa, yine geri dn noktasna
ilikin adres yna yazlr. Bir ilevin yrtlmesi sona erdiinde, yndan geri dn
adresi ekilerek programn ak o noktaya ynlendirilir. Yndaki yerel deikenlerin de
mr sona erince bu deerler de yndan kartlr. Ynda yer alan otomatik mrl
nesne eer bir snf nesnesi ise bu snf nesnesinin sonlandrc ilevi arlr.
Bir ilevin kodunun yrtlmesi return deyimi ile deil de bir hata nesnesi gnderilmesi
nedeniyle sonlandrlrsa ne olur? Bu durumda yine srasyla yndaki deerler yndan
karlr. Ancak programn ak bu durumda geri dn adresine ynlendirilmez.
Programn aknn devam edecei noktann belirlenmesi iin bir try blou iinde yer alan
geri dn adresi aratrlr. Byle bir geri dn adresi bulunduunda programn ak

269/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


geri dn noktasn izleyen ilk deyime deil, sz konusu try blounu izleyen catch
bloklarna ynlendirilir. Bu ileme "ynn dengelenmesi" (stack unwinding) denir.
Yn dengelenmesi mekanizmasnda, ilevden yaplan normal geri dnlerde olduu gibi
yndaki snf nesneleri iin sonlandrc ilevler arlr. Bir ilevin geri dn
mekanizmas ile yalnzca o ilev tarafndan yna yerletiren nesneleri ele alnrken, bir
hata nesnesi gnderilerek ynn dengelenmesi durumunda ilgili catch blouna
ulalncaya kadar ynda yer alan tm nesneler ele alnr. Bu nesnelerin bir snf
trnden olmas durumunda bu snf nesneleri iin sonlandrc ilevler arlr. Yn
dengelenmesi mekanizmas olmasayd, throw noktas ile catch noktas arasnda mrleri
srmekte olan yerel snf nesneleri iin sonlandrc ilevler arlmazd. Bu da bu snf
nesnelerinin tuttuu kaynaklarn (resources) serbest braklmamas ya da sisteme geri
verilmemesi anlamna gelirdi.
Dinamik snf nesneleri yn alannda deil "free store" alannda yer alr. Bir hata nesnesi
yakalandnda dinamik snf nesneleri iin sonlandrc ilev arlmaz. Bunun
uygulamadaki nemi udur: Eer programn kulland kaynaklar dinamik snf
nesnelerine balanmlarsa, bir hata olumas durumunda bu nesnelerin sonlandrc
ilevleri arlmayaca iin, bu kaynaklar geri verilemez. Dinamik nesnelerin akll
gsterici nesnelerine balanmasyla bu sorun zlebilir. Akll gsterici snflarna ileride
deineceiz.

throw fadesinin catch Parametresine Kopyalanmas


throw ilemi ile throw ifadesi nce derleyici tarafndan oluturulmu bir geici blgeye
alnr. Geici blgeden catch parametresine kopyalanr. Yani throw ifadesinin catch
parametresine kopyalanmas dorudan deil, geici blge ile iki aamada yaplr.
Derleyicinin oluturduu bu geici blge throw ifadesi ile ayn trdendir. Uygulamada
throw ifadesi genellikle snf trlerine ilikin olur. throw ifadesi bir snfa ilikinse, geici
blgenin devreye girmesi anlam karmaklna yol aabilir. Bu karmakl engellemek
iin eitli durumlar tek tek ele alalm:
i) throw ifadesi bir snf trndendir. catch parametresi de ayn trden bir snf nesnesidir.
Bu durumda nce geici blge iin kopyalayan kurucu ilev arlarak geici blgeye
atama yaplr. Sonra catch parametresi iin kopyalayan kurucu ilevin arlmasyla, geici
blgeden catch parametresine kopyalama yaplr. Programn ak catch blounu
bitirdiinde, ters srada yani nce catch parametresi iin sonra geici blge iin
sonlandrc ilev arlr. throw ileminde snf nesnesi kullanlm ise yn dengelemesi
srasnda geici blgeye kopyalama ileminden sonra bu nesne iin sonlandrc ilev
arlr. Bu biimdeki bir hata ileme mekanizmas ok fazla kopyalayan kurucu ilev
arld iin, genellikle tercih edilmez.
ii) throw ifadesi bir snf trndendir. catch parametresi ayn snf trnden bir referans
olur. Bu durumda geici blge iin kopyalayan kurucu ilev arlr. Fakat daha sonra
geici blgenin adresi catch parametresi olan referansa aktarlr. Geici nesne catch blou
boyunca yaar. catch blounun sonunda geici blge iin sonlandrc ilev arlr. Bu sk
kullanlan bir tekniktir. rnein C++'n standart ktphanesindeki hata nesnesi yakalama
teknii byledir.
iii) throw ilemi bir snf trnden adres ile yaplr. catch parametresi de ayn snf
trnden bir gsterici deiken olur. Bu durumda geici blge de ayn snf trnden bir
gsterici olacana gre, ne geici blge iin ne de catch parametresi iin herhangi bir
kurucu ilev arlmaz. Tabii throw ifadesindeki adres yerel bir nesneye ilikin
olamamaldr. Bu teknikte genellikle programc new ileci ile dinamik olarak elde ettii
hata nesnesini gnderir. rnein:
thrownewSample();

270/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


throw ilemi yaplm olsa bile dinamik nesneler yaamaya devam eder. Byle bir throw
ilemi ile geici blgeye dinamik nesnenin adresi aktarlr. Bu adres buradan da catch
parametresine aktarlr:
thrownewSample();
gibi bir ifade iin
catch(Sample*p)
{
//...
deletep;
}
ilemi yaplmaldr. Bu yntem geici blge ve catch parametresi iin kopyalayan kurucu
ilev arlmad iin, en verimli yntemdir. Ancak bu yntemde throw ileminde
yaratlan geici nesnenin boaltlmas catch blounun sonunda programc tarafndan
yaplmaldr. rnein MFC ktphanesi bu yntemi kullanmaktadr. Oluturulan hata
nesnelerinin yaratlmasn, catch parametresine kopyalanmasn ve yok edilmesini izlemek
iin aadaki kod parasn derleyerek altrn:
#include<iostream>
usingnamespacestd;
classSample{
public:
Sample(inta):m_a(a){cout<<"Sample::Sample(int)"<<endl;}
Sample(constSample&r){m_a=r.m_a;cout<<"Sample::Sample(const
sample&)"<<endl;}
~Sample(){cout<<"Sample::~Sample()"<<endl;}
voiddisplay()const{cout<<"a="<<m_a<<endl;}
private:
intm_a;
};
voidfunc1()
{
Samplea(1);
throwa;
}

voidfunc2()
{
thrownewSample(2);
}
intmain()
{
try{
//func1();
func2();
}
catch(Samplea){
a.display();
}

271/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


catch(Sample*ptr){
ptr>display();
deleteptr;
}
cout<<"end"<<endl;

return0;
}

Tremi snf nesnesinin tr ile ilgili taban snf nesnesinin tr arasnda tam uyum
olduu kabul edilir. Yani tremi snf nesnesinin adresiyle throw ilemi yapldnda,
taban snf trnden bir gstericiye sahip catch blou bunu yakalayabilir. Uygulamalarn
ounda snf ktphanesinde bir tretme hiyerarisi iinde hata ileme snflar bulunur.
MFC'de ktphane ierisinde normal d bir durumla karlaldnda, ilgili hata snf
trnden bir nesne dinamik olarak yaratlr ve dinamik hata nesnesinin adresiyle throw
ilemi yaplr. Programc ktphanedeki btn throw ilemlerinin bir hata snf nesnesinin
adresiyle yapldn bilir. Dolaysyla oluabilecek her trl hata durumunu aadaki gibi
ele alabilir:
try{
//...
}
catch(CException*pcException)
{
//...
deletepCException;
}
Hata snflar da sanal ilevlere sahip olabilir. Bylece okbiimlilii destekleyecek bir
ekilde tasarm yaplabilir. Taban snfn sanal ilevlere sahip olmas ok biimli bir hata
ele alma ilemini salayabilir. rnein, yukardaki catch blounda CException snfnn
sanal display() isimli bir ilevi arlabilir. Bylece oluan hata durumuna ilikin hata iletisi
ekrana ya da bir dosyaya yazdrlabilir.
Bir snf ktphanesi kullanlarak proje gelitiriliyorsa, programc var olan hata
snflarndan tretme yaparak kendi hata snflarn oluturmaldr. rnein MFC de bir seri
port uygulamas gelitirildiini dnelim. Bu durumda CException snfndan
CSerialException gibi bir snf tretilerek, aadaki gibi bir throw ilemi yaplabilir:
try{
thrownewCSerialException;
//...
}
catch(CException*pCException){
pCException>Disp();
deletepCException;
}
CException snfndan tretilmi CMemoryException gibi bir snf olduunu dnelim.
Aadaki gibi try-catch bloklar oluturulmu olsun.

272/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


try{
//...
}
catch(CMemoryException*pException){
//...
}
catch(CException*pException){
//...
}
Burada CMemoryException snfndan yaplan throw ilemleri birinci catch blou
tarafndan, dierleri ikinci catch blou tarafndan yakalanr. Burada catch bloklarnn
yerleimi nemlidir. Yani CException snfna ilikin catch blounun aada olmas gerekir.

iie try bloklar


Bir try blou baka bir try blounun iinde yuvalanm olabilir (nested try blocks). Bu
durumda her bir try blounu ayr catch bloklar izlemelidir.
Aadaki rnei inceleyelim :
#include<iostream>
voidfunc1()
{
throw1;
}
voidfunc2()
{
throw2.3;
}
intmain()
{
try{
func1();
try{
func2();
}
catch(doublex){
std::cout<<"hatayakalandi:"<<x<<std::endl;
}
}
catch(intx){
std::cout<<"hatayakalandi:"<<x<<std::endl;
}
std::cout<<"hatayakalandiktansonraprogramdevamediyor!"<<
std::endl;
return0;
}
Yukardaki rnekte dtaki try blounun iinde baka bir try blou daha yer alyor. teki
try bloundaki kodun almas srasnda bir hata nesnesi gnderilmesi durumunda, yani

273/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


func2 ilevi tarafndan bir hata nesnesinin gnderilmesi durumunda, gnderilen hata
nesnesi nce iteki try blounun catch blou tarafndan yakalanmaya allr. Eer iteki
try blouna ilikin catch blou gnderilen hata nesnesini yakalayamaz ise, bu kez
gnderilen hata nesnesini dtaki try blouna ilikin catch blou yakalamaya alr.
phesiz, yalnzca dtaki try blou iinde yer alan kod parasnn almas durumunda,
eer bir hata nesnesi gnderilirse, yani func1 ilevi iinden bir hata nesnesi gnderilirse,
bu hata nesnesini yalnzca dtaki catch blou yakalamaya alr.

Farkl Derinliklerdeki try catch Bloklar


try ve catch bloklar farkl derinliklerde yer alabilir. Bir try blou iinde bir hata nesnesi
gnderildiinde, bu hata nesnesini yakalama olasl bulunan catch bloklarnn
aratrlmas aadan yukarya doru yaplr. Yani ilk nce throw deyimine en yakn
durumda olan ve throw deyimini kapsayan try bloklarnn catch bloklarna baklr. Hata
buradaki catch bloklar tarafndan yakalanamamamsa, bu kez srasyla daha yukardaki
catch bloklar aratrlr. Aadaki rnei dikkatli ekilde inceleyiniz, program derleyerek
altrn:
#include<iostream>
#include<cstdlib>
voidfunc1();
voidfunc2();
voidfunc3();
intmain()
{
try{
func1();
}
catch(double){
std::cout<<"hatamainisleviicindeyakalandi!"<<std::endl;
exit(EXIT_FAILURE);
}
return0;
}
voidfunc1()
{
try{
func2();
}
catch(long){
std::cout<<"hatafunc1isleviicindeyakalandi!"<<std::endl;
exit(EXIT_FAILURE);
}
}
voidfunc2()
{
try{
func3();
}
catch(int){
std::cout<<"hatafunc2isleviicindeyakalandi!"<<std::endl;
exit(EXIT_FAILURE);
}
}

274/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

voidfunc3()
{
try{
//throw'A';
//throw1;
//throw1L;
throw1.5;
}
catch(char){
std::cout<<"hatafunc3isleviicindeyakalandi!"<<std::endl;
exit(EXIT_FAILURE);
}
}
func3 ilevi iinde gnderilen hata nesnesinin trn deitirerek program yeniden
derleyip altrn. Programn almas srasnda oluan farkll gzleyin.

levi Kapsayan try Blou


stenirse tanmlanan bir ilevin tm ana blou bir try blou grevi yapabilir. Bu durumda
ilev parametre ayracnn kapatlmasndan sonra, ancak ilevin ana blounun
almasndan nce try anahtar szc kullanlr. Aadaki rnei inceleyin:
voidfunc(intx)
try
{
//...
}
catch(int){
//...
}
catch(double){
//...
}
levi kapsayan try blouna ilikin catch blou ak bakmndan ilevin iinde kabul edilir.
Yukardaki szdizim ile, eer func ilevi iinde herhangi trden bir hata nesnesi
gnderilirse programn ak ilevin ana blounu izleyen catch bloklarna srar. try
blounun bann ayn zamanda func ilevin ana blounun balangc ve try blounun
sonunun ayn zamanda ilevin ana blounun sonu olduuna dikkat edelim. stenirse main
ilevi de bu ekilde bir try blou iine alnabilir:
intmain()
try
{
//...
}
catch(int){
//...
}
catch(double){
//...
}

275/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

Hata Nesnesi Belirlemeleri


Bir ilev iinde bir hata nesnesinin gnderilip gnderilmeyecei, gnderilecekse
gnderilecek hata nesnesinin hangi trlerden olabilecei zel bir szdizim ile ilevin
bildiriminde ve tanmnda belirtilebilir. Buna "hata nesnesi belirlemesi" (exception
specification) denir.
lev bildiriminde parametre ayracnn kapanmasndan sonra throw anahtar szc
yazlr. Bu szc izleyen ayracn iine ilevin gnderebilecei hata
nesnesinin/nesnelerinin tr/trleri yazlabilir:
doublefunc()throw(Exception);
Yukardaki bildirimde, geri dn deeri double trden olan, parametre deikenine sahip
olmayan func ilevinin Exception snf trnden bir hata nesnesi gnderilebilecei
bildiriliyor.
Byle bir bildirimle iki ilev salanr.
1. levin Exception snf trnden bir hata nesnesi gnderebilecei bilgisi verilir. Bylece
kaynak kodun okunabilirlii artar. levi aran programc, ilev ar kodunu bir try
blou iine alarak, ilev iinde bir hata nesnesinin gnderilmesi durumunda, bu hata
nesnesini yaklamak ve hatay ilemek iin bir nlem alabilir.
2. Derleyiciye ilevin ne trden bir hata nesnesi gnderebilecei bildirilmi olur. Bylece
derleyicinin rettii kod sonucunda, programn alma zamannda eer baka bir trden
hata nesnesi gnderilirse, standart bir ilev arlarak programn ak sonlandrlr.
Bir ilevin iinden birden fazla trden farkl hata nesneleri de gnderilebilecei iin bu
durumun da ilev bildiriminde belirtilmesine olanak salanmtr. Bu durumda ilev
bildirimindeki throw ayracnn iine virgllerle ayrlm biimde gnderilebilecek hata
nesnelerinin trleri yazlr:
doublefunc()throw(bad_alloc,MathException);
Yukardaki ilev bildiriminden func ilevinin bad_alloc ya da MathException snf
trlerinden bir hata nesnesi gnderebilecei belirtilmektedir.
throw(bad_alloc,MathException)
bildiriminin ilev tanmnda da yazlmas zorunludur. Yani birinde bulunup dierinde
bulunmamas geersizdir. func ilevi aadaki gibi tanmlanmaldr:
doublefunc(doublex)throw(bad_alloc,MathException)
{
//...
}
Yine okunabilirlii artrma amacyla, bir ilevin herhangi bir hata nesnesi gndermedii
bilgisi de ilev bildiriminde verilebilir. Bu durumda ilev bildiriminde yer alan throw
anahtar szcn ii bo bir ayra izler.
intfoo(int)throw();
Yukardaki foo ilevinin bildiriminde, foo ilevinin herhangi bir hata nesnesi gndermedii
belirtiliyor.
Bir ilevin bildiriminde throw anahtar szcnn yer almamas, ilevin herhangi bir hata
nesnesi gndermediine iaret etmez. Derleyici tarafndan bu durum, ilevin bir hata

276/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


nesnesi gnderip gndermedii ya da hangi trden bir hata nesnesi gnderebilecei
konusunda bir bilgi verilmedii biiminde yorumlanr.
intprocess(int);
Yukardaki ilev bildirimine gre process ilevinin bir hata nesnesi gnderip
gndermeyecei konusunda bir bilgi verilmiyor. process ilevi herhangi bir trden hata
nesnesi gnderebilecei gibi bir hata nesnesi gndermeyedebilir.
Hata nesnesi belirlemesi, bir ilevin imzasnn bir paras deildir. Parametrik yaplar ayn
hata belirlemeleri farkl ayn isimli iki ilev ayn bilinirlik alannda yer alamaz:
voidfunc(int)throw(int);
voidfunc(int)throw(double);//funcilevininyenidenbildirimindehata
Hata belirlemesi, ilevin trnn bir paras olmadndan typedef bildiriminde de yer
alamaz. Aadaki typedef bildirimi derleme zamannda hata oluumuna neden olur:
typedefvoid(*PVPTR)(int)throw(MathException);

//Geersiz!

Beklenmeyen Hata
Bir hata nesnesi gndermedii belirtilen bir ilev iinden throw ifadesiyle bir hata nesnesi
gnderilmesi, ya da belirli trden bir hata nesnesi gnderdii belirtilen bir ilevin baka
trden bir hata nesnesi gndermesi derleme zamannda kontrol edilmez . Bu durummda
derleme zamannda bir hata olumaz. Bu kontrol programn alma zamannda yaplr. Bir
ilevin bildiriminde throw anahtar szc kullanlmsa, yani gnderebilecei hata
nesnesi ya da nesnelerinin trleri hakknda bilgi verilmise o ilevin belirtilmeyen bir
trden hata nesnesi gndermesi durumuna "beklenmeyen hata" (unexpected exception)
denir.
Bir ilevin iinde beklenmeyen bir hata durumu olutuunda, yani ilev bildiriminde
belirtilmeyen bir trden hata nesnesi gnderildiinde, unexpected isimli standart bir ilev
arlr. unexpected ilevinin nceden belirlenmi davran standart terminate ilevini
armaktr. terminate ilevinin de nceden belirlenmi davrannn, abort ilevini
armak olduu daha nce aklanmt.
Nasl terminate ilevinin nceden belirlenmi davrann deitirmeye ynelik
set_terminate() ilevi var ise, unexpected ilevinin de nceden belirlenmi davrann
deitirebilmek iin set_unexpected ilevi tanmlanmtr:
Bu ilev <exception> balk dosyas iinde aadaki gibi bildirilmitir:
typedefvoid(*terminate_handler)();
terminate_handlerset_unexpected(terminate_handlerfp)throw();
voidunexpected()
set_unexpected ilevinin bildiriminden aadaki bilgiler karlabilir:
terminate_handler parametre deikeni olmayan, geri dn deeri retmeyen bir ilevi
gsteren gsterici trnn yeni tr ismidir.
set_unexpected ilevi terminate_handler trnden bir geri dn deerine ve
terminate_handler trnden bir parametre deikenine sahiptir.
set_unexpected ilevinin geri dn deeri, geri dn deeri retmeyen ve parametre
deikeni olmayan bir ilev trnden adrestir. set_unexpected ilevinin parametre
deikeni geri dn deeri retmeyen ve parametre deikeni olmayan bir ilevi
gsteren gstericidir. Bu durumda set_unexpected ilevine byle bir ilevin adresi
geilmelidir. lev isimlerinin birer adres olduunu hatrlayn:

277/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidfunc();
//...
set_unexpected(func);
set_unexpected ilevine adresi gnderilen ilev aada tanmlanan ilevlerden birini
yapmaldr:
terminate ilevini ararak program sonlandrmak (zaten bu nceden belirlenmi
(default) davrantr.
abort ilevini armak.
exit ilevini armak.
Bir hata nesnesi gndermek
Bir ilevin tanm iinde hata belirlemesiyle bildirilen snflarn dnda bir hata nesnesi
gnderildiinde, ilgili ilev bu hatay kendi iinde ele alabilir. Bu durumda unexpected
ilevi arlmaz. Aadaki rnei inceleyin:
voidfunc(intval)throw(Exception)
{
try{
//...
throwstring("Hata!");
}
catch(string){
//...
}
//...
}
Yukardaki rnekte func ilevinin Exception snf trnden bir hata nesnesi
gnderilebilecei bildiriliyor. Ancak ilev iinde, standart string snf trnden bir hata
nesnesi gnderiliyor. Gnderilen hata nesnesinin, ilev iinde yer alan catch blou
tarafndan yakalandn gryorsunuz. Bu durumda unexpected ilevi arlmaz.
Hata belirlemelerine ilikin kontrol derleme zamannda deil, programn alma
zamannda yaplr. Aadaki kodu inceleyin:
voidfunc(double)throw(string,Exception);
voidprocess(intval)throw(string)
{
//...
func(7.5);
//...
}
Yukarda func isimli ilevin bildiriminde, ilevin string ya da Exception snf trnden bir
hata nesnesi gnderebilecei bildiriliyor. Aada tanmlanan process ilevinin tanmnda
ise, string snf trnden bir hata nesnesi gnderilebilecei bildiriliyor. Oysa process ilevi
iinde, Exception snf trnden bir hata nesnesi gnderme olasl bulunan func ilevi
arlyor. Bu durumda derleme zamannda bir hata olumaz. Ancak programn alma
zaman srasnda process ilevinin kodu altnda, func ilevi arldnda gerekten
Exception snf trnden bir hata nesnesi gnderilirse, bu durumda unexpected ilevi
arlr.
Bu durumun salanmas iin process ilevin tanmnn aadaki gibi yapldn
dnebelirsiniz.

278/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidprocess(intval)throw(string)
{
try{
//ilevinkodu
}
catch(string&){
throw;
}
catch(...){
unexpected();
}
}
Bu durumda
voidfoo(void)throw()
{
//...
}
gibi bir ilev tanmnn da gerekte derleyici tarafndan aadaki gibi ele alnd
dnlebilir, deil mi?
voidfoo(void)throw()
{
try{
//...
}
catch(...){
std::unexpected();
}
}

bad_exception Snf Trnden Hata Belirlemesi


Bir ilevin bildiriminde yer alan hata belirlemesinde standart bad_exception snf
kullanlabilir. Bunun anlam udur: Eer sz konusu ilev, hata belirlemesinde belirtilen
snflarn dnda bir trden hata nesnesi gnderirse, yani beklenmeyen hata nesnesi
durumu oluursa bu durumda unexpected ilevi arlmaz. bad_exception snf
trnden bir hata nesnesi gnderilir.

Taban Snf le Tremi Snf Arasndaki Hata Belirlemesi Uyumu


C++ dilinin kurallarna gre tremi snfn hata belirlemeleriyle taban snfn hata
belirlemeleri arasnda bir uyum olmak zorundadr. Taban snfn sanal ilevini ezen, bir
tremi snf ilevi, taban snfn gnderdii hata nesneleri trlerinin dnda bir hata
gndermemelidir. Aadaki rnei inceleyin:

279/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classException{};
classMathException:publicException{};
classSpecialException{};
classBase{
public:
virtualvoidfunc1()throw(Exception);
virtualvoidfunc2()throw(Exception);
virtualvoidfunc3()throw(MathException);
virtualvoidfunc4()throw(MathException);
virtualvoidfunc5()throw(Exception);
virtualvoidfunc6()throw();
};
classDer:publicBase{
voidfunc1()throw(MathException);
//Geerli
//voidfunc2()throw(SpecialException);
Geersiz!
voidfunc3()throw(MathException);
//Geerli
//voidfunc4()throw(Exception);
Geersiz!
//voidfunc5()throw(Exception,SpecialException); Geersiz!
virtualvoidfunc6();//Geersiz!
};
Der snf Base snfndan tretiliyor. Der snfnn, Base snfnn sanal ilevlerini ezen
ilevlerinin hata belirlemelerinde, Base snfnn gndermedii bir hata tr kullanlamaz.
Der snfnn func2, func4 ve func5 ilevlerinin bildirimi geersizdir.

lev Gstericileri ve Hata Belirlemeleri


Bir ilev gstericisinin tanmnda, gstericinin gsterecei ilevin hata belirlemeleri de
belirtilebilir:
void(*fp)()throw(Myclass);
Yukardaki bildirimden u anlalr:
fp geri dn deeri retmeyen, parametre deikeni olmayan ve Myclass snf trnden
bir hata nesnesi gnderme olasl olan bir ilevi gsterecektir. Byle bir ilev gsterici
deikeni, parametrik yaps ayn ama, baka snf trnden hata nesnesi gnderme
olasl olan bir ilevi, gsteremez:
voidfunc()throw(Exception);
void(*fp)()throw(Myclass)=&func;

//Geersiz!

Hata leyen Kodun Yeniden Hata Nesnesi Gndermesi


Hata nesnesini yakalayan ve ileyen bir kod yakalam olduu hata nesnesini yeniden
gnderebilir. Yeniden gnderilen hata nesnesi daha yukar bir seviyede kapsayan bir try
blou tarafndan tutulmaya allr. Bylece hata yakalayan bir catch blou yakalad bir
hatay ksmen ele alabilir. Yapmas gerekenleri yaparak, daha sonra hatann daha yukar
seviyedeki catch bloklar tarafndan yakalanabilmesini salamak iin, hata nesnesini
yeniden gnderebilir.
catch blounun iinde, throw anahtar szc yannda bir ifade olmakszn, yaln olarak
kullanlrsa bu ileme "hata nesnesinin yeniden gnderilmesi" (rethrow) denir.

280/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


try{
func();
}
catch(...){
//...
throw;
}
Yeniden throw ileminde, hata nesnesi bir dtaki (kapsayan) catch blouna gnderilir. Bu
ilemde geici blge silinmez. Yani ilk throw ilemindeki ifade geici blgede kalr. Bir
baka deyile gnderilen ayn hata nesnesidir. Aadaki kodu inceleyiniz:
#include<iostream>
#include<string>
enum{SUCCESS,FAILURE};
classFile
{
public:
File(constchar*str){}
boolis_valid()const{
//...
returnfalse;
}
intopen_new_file()const{returnFAILURE;}
};
classException{
//...
};
classFileException:publicException
{
public:
FileException(constchar*p):s(p){}
constchar*get_message()const{returns.c_str();}
private:
std::strings;
};
voidfoo(File&);
usingnamespacestd;
intmain()
{
try{
Filef("letter.txt");
foo(f);//1
}
catch(...){
cout<<"yenidengonderilenhatanesnesiyakalandi"<<endl;
}

return0;
}

281/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

voidfoo(File&r)
{
try{
if(!r.is_valid())
throwFileException("letter.txt");
}
catch(FileException&r_ex){
cout<<"gecersizdosya:"<<r_ex.get_message()<<endl;
if(r.open_new_file()==FAILURE)
throw;
}
}
foo ilevinde yer alan try blou iinde, is_valid ilevi ile dosyann geerlilii snanyor.
Dosya geersiz ise FileException snf trnden bir hata nesnesi gnderiliyor. try blounu
izleyen catch blou ile gnderilen hata nesnesi yakalanyor. Ekrana bir hata iletisi
yazdrlyor. Daha sonra yeni bir dosya almaya allyor. Eer yeni dosya alamam ise
hata nesnesi yeniden gnderiliyor. main ilevi iinde yaplan foo ilevi arsnn bir try
blou iine alndn bu try blounu ise bir catch blounun izlediini gryorsunuz.
Yeniden gnderilen hata nesnesi bu kez catch all blou tarafndan yakalanr. Programn
ekran kts aadaki gibi olur:
gecersizdosya:letter.txt
yenidosyaacilamiyor!
tekrargonderilenhatanesnesiyakalandi
ou durumda hata nesnesini yakalayarak ksmi olarak ileyen kod paras, hata nesnesi
zerinde deiiklik de yapar. Bylece yeniden gnderilen hata nesnesini yakalayan kod
paras, hatann ksmen ele alndndan haberdar olur. te catch parametrelerinin bir
snf trnden olmas yerine bir snf trnden referans olarak seilmesinin bir nedeni de
budur. catch parametresi bir snf trnden olursa, hata nesnesi zerinde yaplan
deiiklikler yalnzca yerel bir kopya zerinde yaplr:
Aadaki gibi bir catch blounu ele alalm:
catch(Exceptione)
{
e.set_value(/**/); //catchparametresizerindede?iiklikyaplyor...
throw;
//Hatanesnesiyenidengnderiliyor.
}
Yukardaki catch blouyla, gnderilen hata nesnesinin kendisi yakalanmaz. Gnderilen
hata nesnesi catch parametresi olan e nesnesine ilkdeer verir. Dolaysyla
e.set_value(/**/);
arsyla deitirilen, asl hata nesnesi deil catch parametresidir. Yeniden throw
deyimiyle gnderilen hata nesnesi zerinde bir deiiklik yaplmamtr. Ancak catch
parametresi referans olsayd, durum deiirdi:

282/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


catch(Exception&r)
{
r.set_value(/**/);
throw;
}

//hatanesnesizerindede?iiklikyaplyor...
//hatanesnesiyenidengnderiliyor.

Yukardaki catch blou hata nesnesinin kendisini yakalar.


r.set_value(/**/);
arsyla deitirilen hata nesnesinin kendisidir. Bu durumda yeniden gnderilen hata
nesnesi, zerinde deiiklik yaplm olan hata nesnesidir.

Kurucu levlerden Hata Nesnesi Gnderilmesi


Kurucu ilevler iin geri dn deeri diye bir kavramn sz konusu olmadn
biliyorsunuz. Kurucu ilevler iinde oluan normal d durumlarn, geri dn deeri ile
darya iletilmesi mmkn deildir. Kurucu ilev iinden bir hata nesnesi gnderilmesi sk
karlalan bir durumdur.
Bir kurucu ilev iinden gnderilen hata nesnesi yakalandnda, kurucu ilevi arlm
olan nesne iin, yani *this nesnesi iin sonlandrc ilev arlmaz. Zira nesnenin
oluturulma sreci henz sona ermeden bir hata nesnesi gnderilmitir. Bir hata nesnesi
yakalandnda, yalnzca ynda yer alan oluumu tamamlanm yerel nesneler iin
sonlandrc ilevler arlr.
Peki ya iinde throw ilemi yaplan kurucu ilev dinamik bir nesne iin arlmsa? Bu
durumda new ileci ile *this nesnesi iin bellekten ayrlm dinamik alann free store
alanna geri verilmesi gvence altna alnmtr.

Bileik Nesnelerde Yer alan Elemanlarn Kurucu levlerinden Hata


Nesnesi Gnderilmesi
imdi de bir snfn baka bir snf trnden elemanlara sahip olduunu dnelim.
Elemanlardan birinin kurucu ilevi iinden bir hata nesnesi gnderildiinde, ancak
oluumu tamamlanm elemanlar iin sonlandrc ilevler arlr. Durumu incelemek ve
gzlemek iin aadaki kod parasn derleyerek altrn:
#include<iostream>
classMem1{
public:
Mem1(){std::cout<<"Mem1()::Mem1()"<<std::endl;}
~Mem1(){std::cout<<"Mem1()::~Mem1()"<<std::endl;}
};
classMem2{
public:
Mem2(){std::cout<<"Mem2()::Mem2()"<<std::endl;}
~Mem2(){std::cout<<"Mem2()::~Mem2()"<<std::endl;}
};
classOwner{
Mem1m1;
Mem2m2;
public:
Owner(){std::cout<<"Owner::Owner()"<<std::endl;throw1;}
~Owner(){std::cout<<"Owner::~Owner()"<<std::endl;}
};
intmain()
{

283/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


try{
Ownerx;
}
catch(intx){
std::cout<<"hatayakalandi!"<<(<<x<<)"<<std::endl;
}
return0;
}
Owner snfnn Mem1 snf trnden m1, ve Mem2 snf trnden m2 isimli private
elemanlara sahip olduunu gryorsunuz. Tm snflarn kurucu ve sonlandrc ilevleri,
arldklarnda ekrana arldklarn gsteren bir yaz yazdryor. Owner snfnn kurucu
ilevi iinde int trnden bir hata nesnesi gnderiliyor:
//
Owner(){cout<<"Owner::Owner()"<<endl;throw1;}
//
main ilevi iinde Owner snf trnden x isimli bir nesne yaratldn, tanmlama
deyiminin try blou iine alndn gryorsunuz. try blounu izleyen catch blou ile int
trden hata nesnesi yakalanr. Hata nesnesi yakalandnda hangi snf nesneleri iin
sonlandrc ilevler arlr? m1 ve m2 snf nesnelerinin oluturulma sreci tamamlanm
olduu iin bu nesnelerin sonlandrc ilevleri arlr. Ancak Owner snfnn sonlandrc
ilevi arlmaz. nk Owner snf nesnesinin oluturulmas henz tamamlanmamtr.
Programn ekran kts aadaki gibi olur:
Mem1()::Mem1()
Mem2()::Mem2()
Owner::Owner()
Mem2()::~Mem2()
Mem1()::~Mem1()
hatayakaland!(1)
Bu kez Owner snfnn kurucu ilevi iinde deil de, Mem2 snfnn kurucu ilevi iinden
bir hata nesnesi gnderildiini dnelim:
//
Mem2(){cout<<"Mem2()::Mem2()"<<endl;throw2;}
//
Gnderilen hata nesnesi yakalandnda, yalnzca Mem1 snfnn sonlandrc ilevi arlr.
Bu durumda programn ekran kts aadaki gibi olur:
Mem1()::Mem1()
Mem2()::Mem2()
Mem1()::~Mem1()
hatayakalandi!(2)
Tretmede de benzer bir durum sz konusudur. Bir tremi snf nesnesinin oluturulmas
durumunda nce taban snf nesnesi oluturulur deil mi? Tremi snfn kurucu ilevi
taban snfn kurucu ilevini arr. Taban snf nesnesinin kurucu ilevi iinden bir hata
nesnesi gnderildiinde hangi snflarn sonlandrc ilevleri arlr?

Kurucu levi Sarmalayan try Blou


Bir kurucu ilevin tamam try blou ile kapsanabilir:

284/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Foo::Foo()
try
{
//...
}
catch(bad_alloc)
{
//...
}
Kurucu ilevde M.I.L. szdizimi kullanlmas durumunda da kurucu ilevi sarmalayan bir
try blou oluturulabilir:
Foo::Foo()
try:x(a),y(b)
{
//...
}
catch(bad_alloc)
{
//...
}
Yukardaki gibi bir try blounda, yalnzca kurucu ilev ana blou iinden gnderilecek hata
nesneleri deil, ayn zamanda elemanlarn kurucu ilevleri iinden gnderilen hata
nesneleri de yakalanabilir.
Kurucu ilevi sarmalayan try blounun uygulamada bir nemi daha vardr: Byle bir
kurucu ilev hata belirlemesiyle, public arayznde belirli bir tr dnda hata nesnesi
gndermemeyi gvence altna alabilir. Kurucu ilev iinde gnderilen baka trden bir
hata nesnesi, her trden hata nesnesini yakalayan bir catch blou ile yakalanarak,
istenilen trden bir hata nesnesinin daha yukarya gnderilmesi salanabilir. Aadaki
rnei inceleyin:
#include<string>
classEx{
//...
};
classFoo{
std::strings;
public:
Foo(constchar*)throw(Ex);
};
Foo::Foo(constchar*str)throw(Ex)
try:s(str)
{
//...
}
catch(...)
{
throwEx();
}
Yukardaki rnekte Foo snfnn kurucu ilevi hata belirlemesi ile ancak Ex snf trnden
bir hata nesnesi gndereceini bildiriyor. Foo snfnn kurucu ilevinin bir try blou ile

285/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


sarmalanm olduunu gryorsunuz. Kurucu ilevi sarmalayan try blounu, her trden
hata nesnesini yakalayabilen bir catch blou izliyor. Bu catch blou ile bir hata nesnesinin
yakalanmas durumunda, Ex snf trnden bir hata nesnesi gnderiliyor. Bylece hata
belirlemesiyle verilen gvenceye uyulmas salanyor.

Kurucu levler Tarafndan Elde Edilen Kaynaklar ve Hata


Nesneleri
Bir ok snfn tasarmnda, snf nesnesinin kullanaca bir kaynak, snfn kurucu ileviyle
snf nesnesine balanr. Snfn sonlandrc ilevinin arlmasyla bu kaynak geri verilir.
Eer bu kaynaklar bir gstericiye balanrsa, kaynan balanmasndan sonra, kurucu
ilev iinden bir hata nesnesi gnderilmesi durumunda, balanan kaynaklarn geri
verilebilmesi mmkn olmaz.
Bu kaynaklar akll gsterici (smart pointer) snflarndan nesnelere balanabilir. STL
iinde bu ama iin tasarlanm ablon temelli auto_ptr isimli standart bir akll gsterici
snf vardr. "Akll gstericiler" bal altnda bu konuya daha ayrntl bir ekilde
deineceiz.

Sonlandrc levlerden Hata Nesnesi Gnderilmesi


Sonlandrc ilevlerden hata nesnesi gnderilmesi dilin kurallarna gre geerli olmasna
karn, genellikle nerilmez.
Bir sonlandrc ilev ayr nedenden dolay arlm olabilir:
1. Bir snf nesnesinin bilinirlik alan sona ermitir. Snf nesnesinin mr sona erdiinden,
snfn sonlandrc ilevi arlr.
2. Dinamik bir snf nesnesi delete ileci kullanlarak free store'a geri verilmek
istendiinde dinamik snf nesnesi iin de sonlandrc ilev arlr.
3. Gnderilen bir hata nesnesi bir catch blou tarafndan yakalandnda, yn
dengelenmesi sreci iinde, ilgili catch blouna ulalmasna kadar ynda yer alan tm
yerel snf nesneleri iin sonlandrc ilev arlr.
Eer bir sonlandrc ilev ynn dengelenmesi srasnda arlmsa, sonlandrc ilev
iinden bir hata nesnesi gnderilmesi durumunda programn aknn ilevin dna
kmasna izin verilmez. Bu durumda otomatik olarak std::terminate ilevinin arlmas
gvence altna alnmtr.
Sonlandrc ilev iinde, hata nesnesi gnderme olasl olan bir ilevin arlm olmas
son derece normal bir durumdur. Ancak arlacak ilevler iinden gnderilmesi olasl
olan hata nesneleri, yine sonlandrc ilev iinde yer alan catch bloklaryla yakalanmal,
hatann daha yukarya gnderilmesine izin verilmemelidir:
Myclass::~Myclass()
{
//
try{
if(x<0)
throw1;
}
catch(int){
//
}
//
}
Yukardaki rnekte Myclass isimli snfn sonlandrc ilevi iinde gnderilen int trden
hata nesnesi, yine ayn ilev iinde yakalanyor.

uncaught_exception levi

286/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Bir baka olanak ise, sonlandrc ilev iinde bir hata nesnesi gndermeden nce, yani bir
throw ilemi yapmadan nce, bir hatann ilenmekte olup olmadnn snanmasdr. Bir
hata nesnesinin ilgili bir catch blou tarafndan tutulmasyla yani bir catch blouna
girilmesiyle, ilenmesinin bitmi olduu kabul edilir.
Standart <stdexcept> balk dosyas iinde bildirilen uncaught_exception ileviyle bir
hatann ilenmekte olup olmad snanabilir:
booluncaught_exception();
lev true deere geri dnerse bir hata durumu ileniyor demektir. Yani bir hata nesnesi
gnderilmi ancak henz catch blouna girilmemitir. Eer sonlandrc ilevin kodu iinde
uncaught_exception ilevi arlm ve true deere dnmse, sonlandrc ilevin yn
dengelenmesi srasnda yerel bir snf nesnesinin yok edilmesi yznden arld anlam
kar:
Sample::~Sample()
{
//
if(x<0){
if(uncaught_exception())
return;
throw1;
}
return;
}
Yukardaki kod parasnda Sample snfnn sonlandrc ilevi iinde, x deikeninin
deerinin 0dan kk olmas durumunda nce uncaught_exception ilevi arlyor.
Ancak ilevin false deerine geri dnmesi durumunda bir hata nesnesi gnderiliyor.

Global Snf Nesnelerinin Kurucu ve Sonlandrc levlerinden Hata


Nesnesi Gnderilmesi
Global snf nesnelerinin kurucu ilevleri main ilevin almaya balamasndan nce
arldndan, bu nesnelerin kurucu ilevleri iinden gnderilen hata nesnelerinin
yakalanma ans yoktur. Global nesnelerin sonlandrc ilevlerinden gnderilen hata
nesnelerinin de yakalanma ans yoktur. nk global nesnelerin sonlandrc ilevleri de
main ilevinden sonra arlr.

STL deki Hata Snflar


STL deki snflar ablon tabanl olmasna karn hata snflar ablon tabanl deildir. Hata
snflar <exception> ve <stdexcept> balk dosyalar iinde bildirilmitir. Standart
ktphanedeki hata snflar da bir tretme hiyerarisi iermektedir. Tretme
hiyerarisinin tepesinde "exception" isimli bir snf bulunur. exception snf standart
exception balk dosyas iinde bildirilmitir:
classexception{
public:
exception()throw();
exception(constexception&right)throw();
exception&operator=(constexception&right)throw();
virtual~exception()throw();
virtualconstchar*what()constthrow();
};
exception snfndan tretilen btn standart hata snflar, what isimli sanal ilemi ezer.
Bu ilev, hatay tanmlayan bir yaznn balang adresine dnmektedir.

287/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

STL'de yer alan standart snflardan bazlarna ilikin ilevler bir hata durumuyla
karlatklarnda, exception snfndan tretilmi snf trlerinden hata nesnesi gnderir.
STL ktphanesinden gnderilen tm hata nesneleri exception snfndan tretilmi
snflardan olduklar iin, bu hata nesnelerinin tm parametresi exception snf trnden
referans olan bir catch blou tarafndan yakalanabilir.
standart exception snfndan yine standart logic_error ve runtime_error isimli snflar
tretilmitir.
Bu snflarn tanm <stdexcept> isimli balk dosyasnda yaplmtr. logic_error snf
mantksal tabanl hatalarn ele alnmas iin dnlmtr. run_time_error snf ise
programn alma zamannda ortaya kabilecek hatalar iin dnlmtr. Programc
kendi hata ileme snflarn taban snf olan exception snf yerine bu snflardan da
tretebilir:
classMyException{
public:
MyException(constchar*pMessage):logic_error(pMessage){}
};
logic_error snfndan da aadaki snflar tretilmitir:
domain_error
invalid_argument
length_error
out_of_range
bad_cast : dynamic_cast ileci tarafndan gnderilen hata nesnesi bu snf trndendir.
bad_typeid:
runtime_error snfndan ise aadaki snflar tretilmitir:
range_error
overflow_error
bad_alloc:new ileci tarafndan gnderilen hata nesnesi bu snf trndendir. Bo bir snf
olarak tanmlanmtr.
Programc zel bir ktphane sisteminde almyorsa hata ileme snflarn STLin
snflarndan treterek oluturmaldr. C++ dilinin baz normal d durumlarnda
gnderdikleri hata nesneleri de exception snfndan tretilmitir.

288/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

289/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

ALIMA ZAMANINDA TR BELRLENMES


alma zamannda tr bilgisinin elde edilmesi C++ diline eklenen son zelliklerden
biridir. Standartlar ncesi oluturulmu derleyicilerde, bu zellik desteklenmeyebilir. Baz
derleyiciler de, bu zellii istee bal olarak etkin duruma geiriyor olabilir. Bu zellie
ksaca RTTI (Runtime Type Information/Identification) denir.
RTTI, C++ dili tarafndan standart hale getirilmi, bir nesnenin trnn alma
zamannda belirlenebilmesine ynelik, baz aralara verilen genel isimdir.
Byle bir aracn standart bir hale getirilmesinden nce, zaten yazlm gelitiren baz
firmalar, alma zamannda bir nesnenin trnn belirlenebilmesine ynelik aralar
kendileri gelitirip, kendi oluturduklar snf ktphaneleri iin kullanyorlard. Ancak bu
durum farkl ktphanelerin kullanlmas durumunda bir takm tanabilirlik sorunlarna
yol ayordu. nk bir firmann kulland bileen, baka bir firmann kulland bileen
ile uyumsuz olabiliyordu. RTTI aralarnn standart hale getirilmesi, gelecekte
oluturulacak farkl snf ktphanelerinin birbirleriyle uyumlu olmas konusunda atlm
nemli bir adm kabul edilebilir.

alma Zamannda Bir Nesnenin Trnn Belirlenmesi (RTTI)


Nedir?
Mekanizmay iyi anlayabilmek iin nce "aa doru dnm" (downcast) konusunu
incelemek gerekir. Aa doru dnm ne anlama gelir?
Taban snf trnden bir gsterici deikene, tremi snf trnden bir nesnenin adresi
dorudan dorudan atanabilir. ngilizcede bu duruma "Yukar doru dnm"
(upcasting) denir. "Aa doru dnm" (downcasting) ise, taban snf trnden bir
adresin tremi snf trnden bir gstericiye, tr dntrme ileci kullanlarak atanmas
ilemidir. Tr dntrme ileci kullanlmadan, taban snf nesnesinin adresinin, tremi
snf trnden bir gstericiye atanmas dilin kurallarna gre geersizdir.
Bir snf hiyerarisi iinde, bir taban snftan tremi eitli snflarn yaratldn
dnelim. Tremi snf trnden bir snf nesnesinin adresi, taban snf trnden bir
gsterici deikene atanabilir. Ya da byle bir ilem referans kullanlarak yaplabilir.
Peki taban snf trnden gsterici ile bir ye ileve ar yapldnda, hangi ilev arlr?
Eer arlan sanal bir ilev deilse, taban snfn ilevi arlr. Ancak arlan sanal bir
ilev ise, taban snf gstericisine hangi tremi snf trnden bir nesnenin adresi
atanmsa, o tremi snfa ilikin ilev arlr. Tabi bunun iin, tremi snfn devir ald
sanal ilevi ezmi (override) olmas gerekir. Sanal ilevin sz konusu olmas durumunda,
zaten taban snfa ilikin gstericinin iinde ne trden bir nesnenin adresinin tutulduunun
bilinmesine gerek kalmaz.
Ancak baz durumlarda, tremi snfa ilikin bir nesnenin adresi taban snf trnden bir
nesneye atanm olsa da, halen bu gsterici yoluyla tremi snf trlerinden birine ilikin,
sanal olmayan bir ilev arlmak istenebilir. te RTTI aralar arlkl olarak byle
durumlarda kullanlr. Bu ara ile, ye ilevi arlacak nesnenin tr bilgisi elde edilerek
ye ilevin arlp arlmayacana karar verilir.
Sz konusu gereksinimi basit bir rnekle gstermeye alalm. Aadaki kodu inceleyin:

290/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classBase{
//..
public:
virtualvoidvfunc();
};
classDer1:publicBase{
//...
public:
virtualvoidvfunc();
voidfoo();
};
classDer2:publicBase{
public:
virtualvoidvfunc();
//...
};
classDer3:publicBase{
public:
virtualvoidvfunc();
//...
};
voidprocess(Base*baseptr)
{
baseptr>vfunc();
//baseptrDer1snftrndeniseDer1snfnnfooislevinin
//cagrilmasigerekiyor.
}
Base snfnn vfunc isimli bir sanal ye ilevi var: Bu ilev Base snfndan treyen Der1,
Der2 ve Der3 snflar tarafndan eziliyor. Bylece okbiimli bir snf hiyerarisi
oluturuluyor. Der1snf, Base snfndan devir ald bu sanal ilevin dnda, kendisi de
foo isimli bir ilev tanmlyor.
Base snf trnden bir gsterici parametre deikenine sahip, global process isimli ilev,
okbiimli ilev yapmak amacyla tanmlanyor. Yani process ilevi Base trnden bir
nesnenin adresi ile arlabildii gibi, Der1, Der2, Der3 snflar trlerinden bir nesnenin
adresi ile de arlabilir. process ilevi iinde, nce taban snfn, sanal vfunc ilevi
arlyor. Bu ilev sanal sanal olduu iin, hangi trden snf nesnesinin adresi process
ilevine geirilirse o snfa ilikin vfunc ilevi arlr. process ilevine adresi gnderilen
nesne Der1 snf trnden ise, bu snfn foo isimli ilevinin arlmas gerektiini
dnelim.
if(baseptr'ningsterdi?inesneDer1trndenise)
((Der1*)baseptr)>foo()
Peki ama taban snf iindeki gstericinin, Der1 snf trnden nesneyi gsterip
gstermedii nasl bilinebilir? Bu bilgi her zaman derleme zamannda elde edilemez.
Ancak alma zaman iinde devreye giren bir mekanizma yardmyla saptanabilir.
Yukardaki rnekte taban snf trnden gsterici olan baseptr gstericisi iindeki adres,
tr dntrme ileci ile tremi snf trnden bir adrese dntrlp, bu adres ile
tretilen Der1 snfnn foo ilevi arlyor. Ancak bu dntrme ilminin alma zaman
hatas olmamas iin, gerekten baseptr iinde Der1 snf trnden bir adres olup
olmadnn bilinmesi gerekir. Peki ptr iinde Der1 snf trnden bir adres deil de

291/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


rnein Base snf trnden bir adres varsa ne olur? Bu durumda foo ilevine this adresi
olarak geirilen adres geerli bir adres olmaz. foo ilevine yaplan ar bir gsterici
hatasna neden olur.
Aa doru dnm, tr dntrme ilelerinin kullanlarak taban snf trnden bir
adresten tremi snf trnden bir adresin elde edilmesidir. Ancak bu riskli bir ilemdir.
nk tr dntrme ilemi yapldnda, taban snf gstericisinin iinde gerekten
tremi snf trnden bir nesnenin adresi olup olmad bilinmeyebilir.
te RTTI aralar bu noktada ie yarar. Bu aralarla aa doru bir dnmn gvenilir
bir biimde yaplmas mmkndr.
C++ dilinde RTTI aralarnn ayr bileeni vardr:
1) dynamic_cast tr dntrme ileci
dynamic_cast C++ dilinin bir anahtar szcdr.
Bu ile, taban snf trnden bir adresi -eer mmkn ise- tremi snf trnden bir
adrese dntrr. Tr dntrme ilemi baarl olarak yaplrsa ilecin rettii deer,
hedef tr olan tremi snf trnden bir adrestir. Aksi halde, yani dntrme ilemi
baarl olmamsa, ile 0 deerini yani NULL adresini retir.
2) typeid ileci. Bir nesnenin trn kesin olarak belirleyen bir iletir.
typeid C++ dilinin bir anahtar szcdr.
3) Bilgi edinilmek istenen tr hakkndaki nemli bilgilerin tutulduu type_info snf.
RTTI aralar ancak sanal ileve sahip bir snf hiyerarisi iin kullanlabilir. Eski derleyiciler
alma zamannda tr belirlenmesini desteklemiyor olabilir. Yeni derleyicilerin ounluu
ise RTTI aralarn seime bal olarak etkin duruma geirir.
imdi bu aralar ayrntl olarak inceleyelim:

dynamic_cast leci
Bu ile RTTI mekanizmasnn arlkl olarak kullanlan aracdr. Bu ilecin kullanlmasyla,
taban snf trnden bir adresin, programn alma zamannda tremi snf trnden bir
adrese gvenilir bir ekilde dntrlp dntrlemeyecei renilebilir.
lecin kullanm daha nce aklanan yeni tr dntrme ilelerinin (static_cast,
const_cast, reinterpret_cast ) kullanmna benzer.
dynamic_cast<Der1*>(baseptr)
Yukardaki ifade ile baseptr adresi Der1 snf trnden bir adrese dntrlmeye
allyor. Eer baseptr nesnesinin iinde gerekten Der1 snf trnden bir nesnenin
adresi varsa, dnm baarl olur. Bylece ile Der1 snf trnden bir adres retir.
Eer baseptr gsterici deikeni iinde Der1 snf trnden bir adres yoksa, dnm
baarl olmaz, ile 0 (NULL) adresini retir.
dynamic_cast ilecinin terimi olan adresin -yukardaki rnekte baseptr gstericisininokbiimlilii destekleyen bir snf trnden olmas zorunludur. Yani baseptr gsterici
deikenin ait olduu snfn, en az bir sanal ilev iermesi gerekir. Aksi halde ilecin
kullanm geersizdir.

292/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidprocess(Base*baseptr)
{
baseptr>vfunc();
if(Der1*der1_ptr=dynamic_cast<Der1*>(baseptr))
der1_ptr>foo();
}
imdi process ilevi iinde alma zamannda tr belirleniyor. baseptr gstericisi
dynamic_cast ilecinin terimi yaplarak, Der1 * trne dntrlyor. dynamic_cast
ilecinin rettii deer Der1 trnden gsterici olan der1_ptr deikenine atanyor. Eer
atanan deer NULL adresi deilse, bu gsterici yoluyla, tremi Der1 snfnn foo isimli
ilevi arlyor.
dynamic_cast ilecinin tr dntrme ilemini baaryla yapp yapmad mutlaka
snanmaldr.

bad_cast Snf
dynamic_cast ileci ile snf nesnesi gsteren bir ifade yani bir sol taraf deeri, snf
trnden bir referansa da dntrlebilir:
#include<iostream>
classBase{
//...
public:
virtual~Base(){}
};
classDer:publicBase{
//...
};
voidfunc(Base&baseref)
{
Der&r=dynamic_cast<Der&>(baseref);
//...
}
intmain()
{
Derder;
func(der);
return0;
}
Peki dntrme ileminin baars nasl snanabilir? Bir adres trne dntrme
yapldnda, dntrme ileminin baarsz olduu dynamic_cast ilecinin NULL adresi
deeri retmesiyle anlalyordu. Ancak NULL referans diye bir kavram olmad iin,
referansa yaplan dnmn baars bu ekilde snanamaz.
Dnmn baarszl durumunda exception handling mekanizmas devreye girer.
dynamic_cast ileciyle referansa yaplan bir dnm baarl olmaz ise standart bad_cast
snf trnden bir hata nesnesi gnderilir. bad_cast snf Standart C++ ktphanesi
tarafndan tanmlanm, standart exception snfndan tretilmi bir snftr. Bu snfn
tanm standart typeinfo balk dosyasndadr.

293/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidfunc(Base&baseref)
{
try{
Der&r=dynamic_cast<Der&>(baseref);
}
catch(std::bad_cast&){
//...
}
}
Ne zaman bir adres tr yerine bir referans trne dynamic_cast ileciyle dnm
yaplmaldr? Bu tamamyla programcnn seimidir. Programc oluturduu tasarm
dorultusunda bir seim yapar. Referansa yaplan bir dnm sz konusu olduunda,
baarszlk durumu gz ard edilemez. Mutlaka hata ileme aralar kullanlmaldr. Ancak
hata ileme aralarnn, programn alma zaman asndan bir maliyeti olduu iin,
programclarn ou dynamic_cast ileciyle bir referans trne deil bir adres trne
dnm yapmay tercih eder.

dynamic_cast leci ile static_cast leci Arasndaki Fark


static_cast ileci ile, bir snf trnden adresin, ayn hiyerari iinde baka bir snf
trnden adrese aa doru dntrlmesi geerlidir. rnein A snfndan B snf, B
snfndan da C snfn tretmi olalm. static_cast ileci ile A snf trnden bir adresi C
snf trnden bir adrese dntrmek geerlidir:
classA{
//...
};
classB:publicA{
//...
};
classC:publicB{
//...
};
voidfunc(A*aptr)
{
C*cptr=static_cast<C*>(aptr);
//...
}
Yukardaki kod parasnda, func ilevinin parametre deikeni olan aptr gstericisinin
deeri, ilevin ana blou iinde static_cast ileci ile, C snf trnden bir adrese
dntrlyor. Kod tamamen geerlidir. Ancak kodun geerli olmas aptr gsterici
deikeni iinde, C snf trnden bir nesnenin adresi olduunun gvencesi deildir.
Snama derleme zamannda yaplr. func ilevinin A snf trnden bir adresle arlmas
gsterici hatasdr.
static_cast ileci ile aa doru dnm yaplabilir. Ancak dnmn gvenli olup
olmad, programn alma zamannda snanmaz. lecin rettii deer, her zaman asal
ayra iine yazlan hedef trden adrestir. Ancak programn alma zamannda o adreste o
trden bir nesne olacann hibir gvencesi yoktur. imdi de dnmn dynamic_cast
ileci ile yapldn dnelim:

294/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


voidfunc(A*aptr)
{
if(C*cptr=dynamic_cast<C*>(aptr))

//...
}
Yukardaki rnekte func ilevi arldnda, func ilevine C snf trnden ya da C
snfndan treyen bir snf trnden adres geilirse, dynamic_cast ileci baarl olur. le
C snf trnden bir adres retir. Aksi halde ile NULL adresi retir. Snama programn
alma zamannda yaplr.

typeid leci ve type_info Snf


typeid ileci ile iki nesnenin trnn ayn olup olmad, programn alma zamannda
saptanabilir. typeid tek terimli nek konumunda bir iletir. lecin kullanm yledir:
typeid(ifade)
Bu ile ifadenin trn saptar ve ifadenin trne uygun
conststd::type_info&
trnden bir deer retir. Burada belirtilen ifade, sizeof ilecinde olduu gibi herhangi bir
tr ismi, ya da normal bir ifade olabilir. lecin terimi olan ifade, okbiimli bir snf
trnden bir nesne belirtiyorsa, elde edilecek bilgi alma zaman srasndaki dinamik
tre ilikindir. rnein baseptr, okbiimli bir tretme emasnda taban snf trnden bir
gsterici olsun. *baseptr, typeid ilecinin terimi yaplm olsun. baseptr alma
zamannda hangi nesneyi gsteriyor ise, o snfa ilikin tr bilgisi elde edilir.
typeid ilecinin rettii deer std::type_info snf trnden const bir referanstr. Bu
referans std::type_info snf trnden bir nesnenin yerine geer. type_info snfnn
kodlanmas derleyiciden derleyiciye deiebilir. Ancak bu snfn temel yaps standart
olup, tm derleyiciler iin ayndr:
namespacestd{
classtype_info{
//Derleyiciyeba?lksm
private:
type_info(consttype_info&);
type_info&operator=(consttype_info&);
public:
virtual~type_info();
booloperator==(consttype_info&,consttype_info&);
booloperator!=(consttype_info&,consttype_info&);
boolbefore(consttype_info&r)const;
constchar*name()const;
};
}
Yukardaki snf tanmnda baz noktalar inceleyelim :
type_info snf da dier snflarda olduu gibi std isim alan iinde bildirilmitir.
1. type_info snfnn bir varsaylan kurucu ilevi yoktur.
type_info snf trnden bir nesne varsaylan kurucu ilev arlacak ekilde yaratlmaz.
2. type_info snfnn kopyalayan kurucu ilevi ve atama ilecini ykleyen ilevi snfn
private blmne yerletirilmitir. Bu da u anlama gelir: typeid ilecinin rettii

295/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


referansa bir baka type_info trnden nesne atanamaz. Bir type_info nesnesi baka bir
type_info nesnesi ile ilk deer verilerek yaratlamaz.
#include <typeinfo>
type_info t1; // Geersiz!
type_info *ptr = new type_info;
// Geersiz!
type_info t2(type_id(unsigned int))
//Geersiz!
type_info snf trnden bir nesne, ancak typeid ileci ile elde edilebilir.
2. == ve != karlatrma ilelerini ykleyen, snfn public ilevleri tanmlanmtr.
type_info trnden nesnelerin eitlii bu ileler tarafndan snanabilir. Aadaki rnei
inceleyin:
#include<iostream>
#include<typeinfo>
classSample1{
//...
public:
virtual~Sample1(){}
};
classSample2{
//...
public:
virtual~Sample2(){}
};
classSample3{
//...
public:
virtual~Sample3(){}
};
intmain()
{
Sample1s1;
Sample2s2;
Sample3s3;
Sample1&rs1=s1;
Sample2*ptrs2=&s2;
if(typeid(Sample1)==typeid(Sample2))
std::cout<<"Aynitur!"<<std::endl;
else
std::cout<<"Farklitur!"<<std::endl;
if(typeid(rs1)==typeid(s1))
std::cout<<"Aynitur!"<<std::endl;
else
std::cout<<"Farklitur!"<<std::endl;
if(typeid(*ptrs2)==typeid(rs1))
std::cout<<"Aynitur!"<<std::endl;
else
std::cout<<"Farklitur!"<<std::endl;

296/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

return0;
}

3. Snfn char trden bir adrese geri dnen name isimli bir ye ilevi vardr. Bu ilevin
geri dn deeri olan adreste snfn ismi gsteren bir karakter dizisi vardr:
std::cout<<typeid(Sample1).name()<<std::endl;
std::cout<<typeid(*ptrs2).name()<<std::endl;
std::cout<<typeid(rs1).name()<<std::endl;
std::cout<<typeid(int).name()<<std::endl;
std::cout<<typeid(longdouble).name()<<std::endl;

//classSample1
//classSample2
//classSample1
//int
//longdouble

Ayrca snfn bool deere geri dnen before isimli bir ye ilevi vardr. Bu ilev type_info
trnden nesnelerin sralanabilmesi iin tanmlanmtr. Bu ye ilev ile *this nesnesine
ilikin trn, arguman olarak alnan type_info nesnesi ile karlatrlmas yaplr.

297/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Karlatrma derleyiciye zg bir biimde yaplr. rnein geri dn deeri true ise *this
nesnesine ilikin tr, "tretme hiyerarisinde daha yukarda" anlam kartlamaz.

typeid ilecinin okbiimli Olmayan Snflar in Kullanm


typeid ileci genel olarak okbiimli snflara ilikin uygulamalarda kullanlsa da, byle bir
zorunluluk yoktur. Yukardaki rnekte grld gibi typeid ilecinin terimi C++ dilinin
temel veri trlerinin ismi, ya da bu veri trlerinden nesneler de olabilir.
typeid ilecinin terimi olan nesne taban snf trnden ise, typeid ilecinin davran, sz
konusu taban snfn okbiimli olup olmamasna gre, yani sanal ilev ierip
iermemesine gre deiir. Aadaki rnei inceleyelim:
#include<iostream>
classBase{
//...
public:
};
classDer:publicBase{
//...
};
intmain()
{
Derder;
Base*base_ptr=&der;
std::cout<<typeid(*base_ptr).name()<<std::endl;
return0;
}
intmain()
{
Derder;
Base*base_ptr=&der;
std::cout<<typeid(*base_ptr).name()<<std::endl;
return0;
}
Yukardaki rnekte ekrana class Base yazlr. Base trnden bir gstericiye, Der trnden
bir nesnenin adresi atanm olmasna karn, typeid ilecinin retmi olduu referans ile
name ilevi arldnda, ekrana taban snfn ismi yazlr. nk Base snf okbiimli
snf deildir. Oysa Base snfnn tanm bir sanal ilev ierecek ekilde deitirilirse bu kez
ekrana class Der yazlr. Sample snfnn tanmn aadaki gibi deitirip, kaynak kodu
yeniden derleyin ve altrn:
classSample{
//...
public:
virtual~Sample(){}
};
Derleyiciler, yukarda belirtilen ve standartlara gre snf tanm iinde bulunmas gereken
ilevlerin dnda, type_info snf iin, baka faydal ye ilevler tanmlayarak
programcnn kullanmna sunabilir. rnein baz derleyiciler, snf trne ilikin ye
ilevlerin listesini veren bir ye ilev tanmlam olabilir. Yine baz derleyiciler snfa ilikin

298/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


bir nesnenin bellekteki organizasyonu hakknda bilgi veren bir ye ilev tanmlam
olabilir.

bad_typeid Snf
Birok uygulamada typeid ilecinin terimi, ierik ileci ile oluturulan bir ifadedir.
Bu durumda, ierik ilecinin terimi NULL adresi ise, standart bad_typeid snf trnden
bir hata nesnesi gnderilir. bad_typeid snf, standart exception snfndan tretilmitir.
Snfn tanm typeinfo balk dosyas iindedir.
Aadaki rnei inceleyin:
#include <iostream>
#include <typeinfo>
class Base {
//...
public:
};
void func(Base *ptr)
{
try {
std::cout << typeid(*ptr).name() << std::endl;
}
catch (std::bad_typeid &) {
std::cerr << "dereferencing null pointer" << std::endl;
exit(EXIT_FAILURE);
}
//...
}

RTTI aralarnn maliyeti


alma zamannda bir nesnenin trnn belirlenmesinin bir maliyeti vardr. RTTI
aralarnn kodlanmas derleyiciyi yazanlarn seimine braklmtr. Derleyicilerin ou
bellekte her bir veri tr iin bir type_info nesnelik alan ayrr. Daha nce belirtildii gibi
dynamic_cast mekanizmas yalnzca okbiimli nesnelere uygulanabilir. Sistemlerin
ounda, okbiimli her nesne, bu nesne iin ayrlm bellek alannda, ait olduu
okbiimli snfa ilikin tutulan sanal ilev tablosunun adresini tutan bir gstericiye
sahiptir. Bu gstericiye kavramsal olarak vptr (pointer to virtual functions table) denir.
Daha nceki konularda, sanal ilev tablosu iinde sanal ilevlerin adreslerinin tutulduu
belirtilmiti. te alma zaman tr bilgisinin elde edilmesi iin, derleyiclerin ou sanal
ilev tablosunun banda, tr bilgilerinin tutulduu type_info snf nesnesinin adresini de
tutar. Dolaysyla alma zaman tr bilgisinin elde edilmesi, aslnda gsterici ilemleriyle
yaplr. nce nesnenin sanal ilev tablo gstericisine eriilir. Bu gstericiden, sanal ilev
tablosunun adresi alnr. Sanal ilev tablosundan da, ilgili type_info nesnesinin adresi
elde edilir. Maliyetin bir sanal ilev arsnn maliyetine edeer olduu dnlebilir.
Her veri tr iin bir type_info nesnesinin var olmas, zellikle byk programlar iin
fazladan yk getirir. Yzlerce okbiimli snfa sahip bir programda yine yzlerce
type_info nesnesi yaratlr. Tm bu nesneler bellekte yer kaplar. Btn snf nesneleri gibi
type_info snf nesnelerinin de yaratlmasnn da zamansal bir maliyeti vardr. RTTI
program iinde hi kullanlmam olsa da type_info nesneleri yine yaratlr. te bu yzden
derleyiciler RTTI mekanizmasn bir anahtar ile aktif hale getirilmesine izin verir. RTTI
mekanizmasnn devre d braklmas, alabilir kodun klmesine ve alma hznn
artmasna neden olur.

typeid leci ile dynamic_cast lecinin Maliyet Asndan


Karlatrlmas

299/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


typeid ilecinin bir deer retmesi her nesne iin "sabit" bir sre iinde gerekleir. Sre
her okbiimli nesne iin, tretme snf hiyerarisi iinde yeri ne olursa olsun sabittir. Bu
sre bir sanal ilevin ars iin harcanan sreye edeer kabul edilebilir.
typeid(nesne)
gibi bir ifadenin edeeri
*(nesne.vptr[0])
gibi bir ileme karlk geldii dnlebilir.
Ancak dynamic_cast ilemi iin geen sre, sabit deildir.
dynamic_cast<T*>(base_ptr)
gibi bir ifadenin deerlendirilmesi iin geen sre, dntrlme ilemine sokulan snfn,
ait olduu snf hiyerarisinin derinliinin artmasyla artar.
Yukardaki ifadede base_ptr gstericisinin ait oldugu snfn ok derin bir tretme
zincirinin en tepesindeki snf olduunu dnelim. Dntrlmenin yaplaca tr de
snf hiyerarisi iinde yer almayan bir tr olsun. dynamic_cast ilecinin NULL adresi
retmesi iin tretme zincirinin en alt kademesine kadar gidilip kontrol yaplmas gerekir.
Tasarm asndan dynamic_cast ileci typeid ilecine tercih edilmelidir. nk
dynamic_cast ileci ile oluturulan kodun esneklii ve gelitilebilirilii type_id ileci ile
oluturulmu koda gre daha fazladr. Ancak buna kar dynamic_cast ilecinin maliyeti
de typeid ilecinin maliyetine gre daha fazladr.

alma Zamannda Tr Belirlenmesinin Sakncalar


Sanal ilev yaps her zaman RTTI aralarna tercih edilmelidir. RTTI aralarnn, bir
zorunluluk bulunmamasna karn kullanlmas, programlarn karmakln arttrr, test
ilemlerini zorlatrr. Kaynak kod deiikliklere kar daha krlgan hale gelir. Programn
almas yavalayabilir. RTTI aralarnn kullanlmas konusunda bir zorunluluk varsa, bu
durumda tasarm asndan, nce dynamic_cast ileci tercih edilmelidir.
C++ dilinde Nesne Ynelimli Programlama Teknii kullanlarak yazlm programlarda,
program tasarm, dier programlama dillerinde olduundan ok daha fazla neme
sahiptir. alma zamannda tr bilgisinin belirlenmesine ynelik gereksinim, nesne
ynelimli programlama tekniinin iyi bir ekilde uygulanmas durumunda, ou zaman
ortadan kalkar. RTTI ou zaman programcnn nesne ynelimli programlama konusunda
yeterli deneyime sahip olmamas nedeniyle bavurulan bir yntemdir. yi bir tasarmda
yalnzca zorunlu durumlarda kullanlmaldr. Peki dinamik tr kontrolnn yaplmasnda
tasarm asndan sorunlu olan durum nedir?
Aa doru dnmler gvenli bir ekilde yaplabilmesine karn, genel olarak aadaki
sakncalardan sz edilebilir:
1. Aa doru dnmler, karmakln hizmet veren kodlardan hizmet alan kodlara,
yani kullanc kodlarna kaydrlmasna neden olur. Bylece kodlarn karmakl artar,
buda kodlama maliyetinde bir arta neden olur.
2. Karmakln kullanc kodlarna kaymas kodlarn genel olarak bymesine neden olur.
3. Dnmn gvenli olup olmadn snamak iin, her dnm iin ayr bir kod
yazmak gerekir. Bu durumda bakm giderleri artar.
4. Bu dnmler programn almasnda genel bir yavalamaya neden olur. Yavalama
oran da, snf hiyerarisinin derinlii orannda artar.

300/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


5. Programn yaplacak eklemeler zorlar. ou zaman, tretme hiyerarisine eklenen
snflar iin ek snamalar ya da kontroller yapmak gerekir.
Ana sorun daha nce yazlm bir kod parasna ulaabilmek iin, fazladan bir kod yazma
zorunluluudur. stelik fazladan yazlan kod, programn geniletilmesi amacnda daha
sonradan sorunlara yol aabilir. Fazladan yazlan kod, bir snf tr iin alma
zamannda, o snf tr iin belirli ilevlerin arlp arlamayacan snamak iin yazlan
kodlardr. Ek kod iinde yaplan snama olumlu sonulanrsa aa doru bir dnm
yaplarak, istenen ilev arlr.
Eer daha nce yazlm olan bir kodu (server code) bulmak iin programc ek bir kod
yazm ise, programcnn yazm olduu ek kod karmaktr, eitli hatalara aktr. Oysa
nesne ynelimli Programlama tekniinin ana zelliklerinden birisi karmakl
indirgemektir. Dinamik tr kontrolunun uyguland ou durumda programcnn, ana
kodda oluturulan tretme hiyerarisi hakknda bilgi sahibi olmasn zorunlu klar, bu
durumda da ileride ana kodda kullanlan snf hiyerarisi yapsnda bir deiiklik
yapldnda, yazlan kodlarn geersiz bir duruma dmesine, yeniden yazlmak zorunda
kalnmasna neden olabilir, bu durum da yine nesne ynelimli programlama tekniinin
genel felsefesine aykrdr.

Aa Doru Dnmlere Seenek: Sanal levler


RTTI aralarn ve aa doru dnmleri (downcast) kullanmak yerine, dinamik
balama ve sanal ilevler kullanlabilir. Bu teknikte, yalnzca tremi snflarda
kullanlacak ye ilevler genelletirilerek taban snfa kaydrlr. Yani kullanc kodlar, sanal
ilevler biiminde nesnenin iine kaydrlr. Bu durumda aa doru dnmler
derleyiciler tarafndan hem otomatik olarak hem de gvenli bir ekilde yaplr. Aa
doru yaplan bir dnm eer gvenilir deilse, zaten derleme aamasnda derleyici
tarafndan saptanr. Ayrca bu tr bir tasarm, sz konusu programn gelitirilebirlii
konusunda da son derece esnek bir yap salar. Yeni bir tretme yaplmas durumunda
var olan ana snf kodlarnda bir deiiklik yaplmas gerekmez.
Aa doru dnm ve izleyen if deyiminden oluan kod paracklar ou zaman, sanal
ilev arlaryla deitirilebilir. Buradaki anahtar faktr, yetenek sorgulamasnn bir
hizmet isteine dntrlmesidir. Nesneye yaplan bir hizmet alma istei, bir sanal ilev
arsdr.

301/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

new ve delete lelerinin Yklenmesi


new ilecinin dinamik bir snf bir snf nesnesi elde etmek iin kullanldn dnelim:
classA{
//...
};
newA*pd=newA;
new ilecinin standartlar tarafndan gvence altna alnan davran yledir:
new ileci operator new isimli bir global ilevi ararak free store alanndan sizeof(A)
kadar byklkte bir blok elde eder. Daha sonra, elde edilen dinamik bellek blounun
balang adresi, A snfnn kurucu ilevine this adresi olarak geirilir. Bylece snfn
kurucu ilevi, dinamik olarak elde edilen bellek blounda, A snf trnden bir nesne
oluturur.
new ileci ve operator new terimleri sklkla birbirleriyle kartrlr. new, C++ dilinin bir
ilecidir. Programc hangi ilevi tanmlarsa tanmlasn, new ilecinin yukarda aklanan
davrann deitiremez. Ancak programc isterse, new ilecinin free store alanndan yer
elde etmek amacyla ard operator new ilevini ykleyebilir. Gerekte yklenen new
ileci deil operator new ilevidir.

operator new levi


Tek bir snf nesnesi iin free store alanndan yer elde etme ilemleri standart bir ilev
olan operator new tarafndan yaplr. Bu ilevin bildirimi
void*operatornew(size_t);
biimindedir. levin parametresi, new ilecinin terimi olmu ifadenin sizeof deeridir. Bu
ilev parametresine aktarlan byklkte bir dinamik bellek blou elde ederek bloun
balang adresini dndrr. new ilecinin kullanlmas durumunda, ilecin terimi olan
trn sizeof deeri derleyici tarafndan hesaplanarak bu ileve argman olarak gnderilir.
Yani
newA
gibi bir ifadenin, derleyici tarafndan nce aadaki gibi bir ilev arsna
dntrldn dnebilirsiniz:
operatornew(sizeof(A))
Bu ardan elde edilen adresle A snfnn kurucu ilevinin arld dnlebilir.
Programc isterse operator new ilevini dinamik bir blok elde etme amacyla dorudan da
arabilir. Aadaki rnei inceleyin:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char str[100];
cout << "bir yazi girin ";
cin >> str;

302/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


char *ptr = (char *)operator new(strlen(str) + 1);
strcpy(ptr, str);
strrev(ptr);

cout << "yazi = (" << ptr << ")" << endl;
//...
return 0;

rnekte, operator new ilevi, yerel str dizisine girilen yaznn uzunluundan 1 byte daha
byk bir dinamik alan elde ediyor. Bu alann adresi void * trnden bir deer olarak
dar iletiliyor. C++ da void trden adreslerin baka trden gstericilere dorudan
atanamadn anmsayn. Sz konusu dinamik bellek blounun balang adresi, char *
trne dntrlerek, ayn trden ptr gstericisine atanyor. Bu gsterici deiken
yardmyla ilgili yaz ileniyor.
operator new ilevi de yklenebilir. Bu ileci global olarak yklemek mmkn olduu gibi,
bir snfn ye ilevi olarak yklemek de mmkndr. Yklenen new ileci deil operator
new ilevidir. new ilecinin nceden belirlenmi davrann deitirme olana yoktur.

Global operator new levinin Yklenmesi


levin global olarak tanmlanmas durumunda new ileciyle yaplan btn dinamik yer
elde etme ilemlerinde, programc tarafndan tanmlanan new ilevi arlr. Yklenen
ilevin geri dn deeri void * trnden olmaldr. Baka trden bir geri dn deeri
seilmesi geersizdir. levin parametre deikeni size_t trnden olmaldr. Parametre
deikeninin baka bir trden olmas geersizdir. Aada global operator new ilevinin
yklenmesine ilikin bir rnek veriliyor. Program derleyerek altrn:
#include<iostream>
#include<cstdlib>
classA{
inta,b;
public:
A();
};
usingnamespacestd;
A::A()
{
cout<<"A::A()"<<endl;
cout<<"this="<<this<<endl;
a=b=0;
}
void*operatornew(size_tsize)
{
cout<<"operatornew()"<<endl;
cout<<"size="<<size<<endl;
void*ptr=malloc(size);
if(!ptr){
cerr<<"mallocbasarsz"<<endl;
exit(EXIT_FAILURE);
}
cout<<"eldeedilenblogunadresi:"<<ptr<<endl;

returnptr;
}

303/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

intmain()
{
cout<<"sizeof(A)="<<sizeof(A)<<endl;
A*pd=newA;
cout<<"pd="<<pd<<endl;
//...

return0;
}
Yukardaki programda tanmlanan A snfnn kurucu ilevi iinde, ilevin arldn
gsteren bir yaz ile this gstericisinin deeri ekrana yazdrlyor.
Tanmlanan operator new ilevinin ana blou iinde de, ekrana ilevin arldn
gsteren bir yaz bastrlmas salanyor. Bu ilev, parametre deikeni olan size
boyutunda bir dinamik bellek blou elde ederek bloun balang adresini dndryor.
lev geri dn deerini retmeden nce dinamik bellek blounun balang adresini
ekrana yazdryor.
main ilevi iinde ise nce ekrana A snfnn sizeof deerinin yazdrldn gryorsunuz.
Daha sonra new ileci kullanlarak bir A snf nesnesi iin bellekte dinamik bellek blou
elde ediliyor. new ilecinin rettii deer A snf trnden gsterici deiken olan pdye
atanyor. Son olarak pd gsterici deikeninin deeri ekrana yazdrlyor.
altrlan programa ilikin rnek bir ekran kts aada veriliyor:
sizeof(A)=8
operatornew()
size=8
eldeedilenblogunadresi:0x3d3dc0
A::A()
this=0x3d3dc0
pd=0x3d3dc0
Globaloperator newilevi istenirse birden fazla parametre deikenine sahip olacak
ekilde yklenebilir. Ancak ilevin ilk parametre deikeninin size_t trnden olmas
zorunludur. Bu durumda ilevin new ileci yoluyla arlmas mmkn olmaz. leve ar
yapmak zorunludur.

operator delete levi


delete C++ dilinin bir ilecidir. delete ilecinin terimi bir snf trnden adres olduunda,
derleyici nasl bir kod retir? nce delete ilecinin terimi olan adres ile snfn sonlandrc
ilevi arlr. Daha sonra operator delete isimli global bir ilev arlarak dinamik olarak
elde edilen bloun free strore alanna geri verilmesi salanr.
ptr gsterici deikeninin, A snf trnden dinamik bir nesneyi gsterdiini dnelim:
deleteptr
gibi bir ifadenin, derleyici tarafndan aadaki gibi bir koda dntrld dnlebilir:
ptr>~A();
operatordelete(ptr);
delete ilecinin bu davran standartlar tarafndan gvence altna alnmtr. Yazlacak
yeni ilevlerle bu davran deitirilemez. Ancak istenirse, delete ilecinin dinamik bellek

304/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


blounu free store a geri vermek amacyla kulland, operator delete isimli ilev
yklenebilir. Bu durumda delete ileci kullanldnda, artk programcnn yazd operator
delete ilevi arlr. levin bildirimi aadaki gibidir:
voidoperatordelete(void*);
lev, parametre deikenine balang adresi geilen dinamik bellek blounu free store
alanna geri verir. stenirse operator delete ilevi dorudan da arlabilir:
#include<iostream>
usingnamespacestd;
intmain()
{
cout<<"kactamsayi:";
intn;
cin>>n;
int*pd=(int*)operatornew(n*sizeof(n));
for(size_tk=0;k<n;++k){
pd[k]=rand()%1000;
cout<<pd[k]<<"";
}
cout<<endl;
//...
operatordelete(pd);
return0;
}
Yukardaki rnekte operator new ile elde edilen bellek blou, daha sonra standart
operator delete ilevi ile geri veriliyor.

operator delete levinin Yklenmesi


Programcnn yazaca operator delete ilevinin geri dn deeri olmamal ve ilevin ilk
parametre deikeni void * trnden olmaldr. Daha nce verilen rnee imdi aadaki
eklemeleri yapyoruz. nce operator delete ilevini yazyoruz:
voidoperatordelete(void*ptr)
{
cout<<"operatordelete()"<<endl;
cout<<"geriverilecekblogunadresi:"<<ptr<<endl;
free(ptr);
}
rnekteki A snf iin, bir de sonlandrc ilev ekliyoruz:
A::~A()
{
cout<<"A::~A()"<<endl;
cout<<"this="<<this<<endl;
}
main ilevinin sonunda, new ileci ile elde edilen dinamik bellek blounu geri vermek iin
delete ileci kullanlyor:

305/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


intmain()
{
cout<<"sizeof(A)="<<sizeof(A)<<endl;
A*pd=newA;
cout<<"pd="<<pd<<endl;
deletepd;
return0;
}
Eklemelerden sonra program yeniden derlenip altrldnda elde edilen rnek bir ekran
kts aada veriliyor:
sizeof(A)=8
operatornew()
size=8
eldeedilenblogunadresi:0x3d3dc0
A::A()
this=0x3d3dc0
pd=0x3d3dc0
A::~A()
this=0x3d3dc0
operatordelete()
geriverilecekblogunadresi:0x3d3dc0

operator new[] levi


Birden fazla sayda nesne iin bir dinamik bellek blounun elde edilmesi iin new[] ileci
kullanlr:
A*pd=newA[n];
new A[10] ifadesi ile nce operator new[] isimli global ilev arlarak, A snf trnden n
tane nesnenin kaplayaca kadar bir bellek blou elde edilir. Daha sonra A snfnn kurucu
ilevi her bir dinamik nesne iin ayr ayr arlr. Yani new[] ileci dinamik bellek alan
elde etmek iin operator new[] ilevini kullanr.
Standartlara gre derleyicilerde byle bir ilevin tanml olmas gerekir. levin bildirimi
aadaki gibidir:
void*operatornew[](size_tsize);
levin geri dn deeri ayrlan dinamik bloun balang adresidir. levin parametre
deikeni ayrlacak dinamik bellek blounun bykldr. new[] ilecinin kullanlmas
durumunda blok bykl derleyici tarafndan hesaplanarak operator new ilevine
argman olarak geilir. Standart ktphanedeki operator new ilevi kendi tanm iinde
global operator new ilevini arr:
void*operatornew[](size_tsize)
{
returnoperatornew(size);
}
Yani programc operator new[] ilevini yklememi olsa bile new[] ile yaplan yer elde
etme ilemlerinde yine operator new ilevi arlr. Ancak isterse programc operator
new[] ilevini de tanmlayabilir. Bu durumda new[] ileci kullanldnda yer ayrma ilemi
programcnn yazaaca operator new[] ilevi ile yaplr. Programcnn yazaca ilevin geri
dn deeri void * trnden olmaldr. levin en az bir parametre deikeni olmal ve
ilevin ilk paramatre deikeni size_t trnden olmaldr.

306/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

operator delete[] levi


new[] ileci ile elde edilen dinamik bloklar delete[] ileci ile geri verilir. delete[] ilecinin
terimi bir snf trnden adres olduunda derleyici yle bir kod retir: nce ilece verilen
adresten balayan blok iinde yer alan btn snf nesnleri iin tek tek snfn sonlandrc
ilevi arlr. Sonra operator delete ileviyle, daha nce elde edilmi olan dinamik blok
free store a geri verilir. Yani delete[] ileci sonlandrc ilevi n kez ardktan sonra
operator delete[] ilevini kullanarak ayrlan dinamik blou geri verir.
operator delete standart bir ilevdir bildirimi aadaki gibidir:
voidoperatordelete[](void*ptr);
levin geri dn deeri yoktur. lev dinamik olarak ayrlm bir bellek blounun
balang adresini alr, blou free store a geri verir. Aslnda operator delete[] ilevi de
kendi iinde operator delete ilevini arr:
voidoperatordelete[](void*ptr)
{
operatordelete(ptr);
}
Tabii programc isterse operator delete[] ilevini ykleyebilir. Programcnn yazaca
operator delete[] ilevinin de geri dn deeri olmamaldr. levin en az bir parametre
deikeni olmal ve bu parametre deikeninin tr void * olmaldr.
Daha nce yazlan programn main ilevini aadaki gibi deitirelim:
intmain()
{
A*p=newA[4];
cout<<"p="<<p<<endl;
delete[]p;
return0;
}
Program yeniden derlenip altrldnda rnek bir ekran kts aadaki gibi olabilir:

307/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


operatornew()
size=36
eldeedilenblogunadresi:0x3d3ec0
A::A()
this=0x3d3ec4
A::A()
this=0x3d3ecc
A::A()
this=0x3d3ed4
A::A()
this=0x3d3edc
p=0x3d3ec4
A::~A()
this=0x3d3edc
A::~A()
this=0x3d3ed4
A::~A()
this=0x3d3ecc
A::~A()
this=0x3d3ec4
operatordelete()
geriverilecekblogunadresi:0x3d3ec0

Operator new ve operator delete levlerinin Bir Snf in


Yklenmesi
Bir snf kendisi iin yaplacak dinamik yer elde etme ilemlerini kendi ye ilevleriyle
yrtebilir. Eer bir snf iin operator new ve operator delete ilevleri arlrsa, global
ilevler deil programcnn snf iin yazd ilevler arlr.

Snfn operator new() levi


Bir snf iin operator new() ilevi yazlabilir. Derleyici, new ilecinin terimi olarak bir snfa
ilikin tr isminin verildiini grrse, nce sz konusu snfn, ismi operator new olan bir
ilevinin bulunup bulunmadn aratrr. Snfn byle bir ilevi varsa, new ileci dinamik
yer elde etme iin bu ilevi kullanr. Snfn byle bir ilevi yoksa bu snf tr iin new
ilecinin kullanlmas sonucu yaplacak dinamik yer elde etme ilemi yine global operator
new ilevi ile yaplr.
new ilecinin bir snf iin yklenmesiyle, bir snfa ilikin dinamik yer elde etme
ilemlerinin o snfa zg bir ekilde, dier snf trlerinden farkl bir biimde yaplmas
salanabilir. Ayn ekilde bir snf iin operator new[] ilevi de tanmlanabilir. Programc
isterse bir snfn operator delete ya da operator delete[] ilevlerini de yazabilir. Bylece
belirli bir snfa ilikin dinamik alan geri verme ilemleri yine o snfa zg bir biimde
yaplabilir.
Snf iin yazlacak operator new ilevinin geri dn deeri void trden bir adres
olmaldr. Aada rnek bir bildirim grlyor:
classA{
public:
void*operatornew(size_t);
};
A*ptr=newA;
new ilecinin teriminin A snf olduunu gren derleyici, A snfnn operator new ilevine
sahip olup olmadn aratrr. A snf iin operator new ilevi tanmlanm olduundan bu
ilev arlr. levin size_t trnden olan parametresine sizeof(A) deeri geilir.

308/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Snf iin operator new ve operator delete ilevlerinin tanmlanmas ya da tanmlanm
ilevlerin kaynak koddan kartlmas new ve delete ilelerinin kullanld kodlarda bir
deiiklik yaplmasn gerektirmez. nk global operator new ilevi de programcnn snf
iin tanmlad operator new ilevi de ayn ifade ile arlr. Programc operator new
ilevini tanmlam olsa bile, global olan ilevi arabilir:
A*ptr=::newA;
A snfnn operator new ilevi olmasna karn, new ilecinin nek konumundaki
znrlk ileci ile kullanlmas sonucu standart ktphanedeki operator new ilevi
arlr.

Snfn operator delete levi


Snf iin tanmlanacak operator delete ilevinin geri dn deeri olmamal, ilevin birinci
parametre deikeni void * trnden olmaldr. A snfna ilikin operator delete ilevinin
bildirimi aadaki gibi olabilir:
classA{
public:
void*operatornew(size_t);
voidoperatordelete(void*);
//...
}
delete ilecine verilen adres bir snf trnden ise, derleyici bu snfn operator delete
ilevine sahip olup olmadn aratrr. Eer snfn operator delete ilevi bildirilmi ise
bildirilen ilev arlr. Aksi halde global operator delete ilevi arlr.
A*ptr=newA;
//...
deleteptr;
ifadeleri iin derleyici yle bir kod retir: ptrnin gsterdii snf nesnesi iin nce snfn
sonlandrc ilevi arlr. Sonra ptr adresi A snfnn operator delete ilevine argman
olarak gnderilir.
operator new, operator[], operator delete, operator delete[] ilevleri snfn statik
ilevleridir. Bu ilevlerin bildirimlerinde static anahtar szc yazlmam olsa bile bunlar
derleyici tarafndan statik ye ilevler olarak ele alnr. Tabii programc isterse bu ilevlerin
bildirimlerinin nne static anahtar szcn yerletirebilir. Bu ilevler statik ye ilevler
olduklarndan snfn statik olmayan elemanlarna dorudan ulaamaz.
operator new ve operator delete ilevlerinin bir snf iin yklenmesine rnek olarak
aada kk bir program veriliyor. Program derleyerek altrn:
#include<iostream>
#include<cstring>
#include<new>
typedefunsignedcharByte;
classA{
chars[20];//yalnzcasnfnesnesiiindeyerkaplasndiye
staticByteallocation_pool[];
staticByteallocation_map[];
public:
staticconstsize_tmax_object_size=10;
A(){std::cout<<"A()\n";}
~A(){std::cout<<"~A()\n";}

309/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


void*operatornew(size_t);
voidoperatordelete(void*);
};
//cppdosyas
usingnamespacestd;
ByteA::allocation_pool[max_object_size*sizeof(A)];
ByteA::allocation_map[max_object_size]={0};
void*A::operatornew(size_t)
{
Byte*ptr=(Byte*)memchr(allocation_map,0,max_object_size);
if(!ptr){
cout<<"bellekyetersiz"<<endl;
throwbad_alloc();
}
intblock_no=ptrallocation_map;
cout<<block_no<<"nolublokkullanlyor"<<endl;
*ptr=1;

returnallocation_pool+(block_no*sizeof(A));
}
voidA::operatordelete(void*ptr)
{
if(!ptr)
return;
unsignedlongblock=reinterpret_cast<unsignedlong>(ptr)
reinterpret_cast<unsignedlong>(allocation_pool);
block/=sizeof(A);
cout<<block<<"nolublokgeriveriliyor!"<<endl;
allocation_map[block]=0;
}
intmain()
{
A*pa[A::max_object_size];

try{
for(size_ti=0;i<A::max_object_size;++i)
pa[i]=newA;
newA;
}
catch(bad_alloc){
cerr<<"bellekyetersiz!"<<endl;
}

deletepa[3];
//geriverilenbellekalnkullaniliyor!
A*ptr=newA;
deleteptr;

for(size_ti=0;i<A::max_object_size;++i)
deletepa[i];

return0;
}

310/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

rnek programda A isimli bir snf tanmlanyor. Snfn eleman olan char trden s dizisi
yalnzca snf nesnesinin belirli bir yer kaplamas amacyla ekledik. Snfn
max_object_size isimli const statik eleman snf trnden dinamik olarak yaratlabilecek
en fazla nesne saysn tutuyor. Snfn iki statik dizi eleman var. Byte trden
allocation_pool isimli dizi snf nesnelerinin yaratlabilecei bellek havuzunu belirliyor. En
fazla allocation_pool dizisinin boyutu kadar sayda dinamik A nesnesi yaratlabilecek. Byte
trden allocation_map dizisi ise allocation_pool dizisinin hangi bloklarnn kullanmda
olduu bilgisini tutuyor. Yani bir bayrak dizisi olarak kullanlyor. Dizinin k indisli
elemannn deerinin 0 olmas bellek havuzundaki ilgili bloun henz kullanmda
olmadn gsteriyor.
A snf iin tanmlanan operator new ilevi nce bayrak dizisini tarayarak bellek
havuzunda henz kullanlmayan bir blok olup olmadna bakyor. Bellek havuzundaki
bloklarn tm kullanmda ise yani havuzun tamam kullanma sunulmu ise, bad_alloc
snf trnden bir hata nesnesi gnderiliyor. Bellek havuzunda en az bir nesnelik yer
varsa, ilgili bloun balang adresi geri dn deeri olarak dar iletiliyor. Snfa ilikin
operator delete ilevi ise parametresine geilen adresin hangi bellek blouna ilikin
olduunu hesaplayarak bayrak dizisinin ilgili elemannn deerini sfrlyor. Blou yeniden
kullanma ayor.

Yeri Belirli new leci


new ilecinin baka bir biimi olan yeri belirli new ileci ile bir snf nesnesi istenilen bir
adreste yaratlr. lecin kullanlmas iin new balk dosyasnn koda eklenmesi gerekir. Bu
ile kullanldnda dinamik bir blok elde etmek iin bir ilev arlmaz. nk zaten snf
nesnesi ilece verilen adreste yaratlr. lecin kullanmnn genel biimi aadaki gibidir:
new(adres)trismi
lecin ayra iindeki terimi herhangi trden adres olabilir. lecin rettii deer tr
ismiyle belirlenen trden bir adrestir. Eer tr bir snf tr ise derleyicinin rettii kod
sonucunda o snfn kurucu ilevi arlr. Aadaki kod parasn inceleyin:

#include<iostream>
#include<new>
classA{
inta,b;
public:
A():a(0),b(0){std::cout<<"A::A()"<<std::endl;}
~A(){std::cout<<"A::A()"<<std::endl;}
voiddisplay()const{std::cout<<"a="<<a<<"\n"<<"b="<<b<<
std::endl;}
};
intmain()
{
chars[sizeof(A)];
A*ptr=new(s)A;

ptr>display();
ptr>~A();
}

311/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


rnekte sizeof(A) byte boyutunda yerel dizi tanmlanyor. Bu dizinin balang adresinin
new ilecine verildiini gryorsunuz. le dardan ald adresle snfn kurucu ilevinin
arlmasn salyor. Ancak daha sonra snfn sonlandrc ilevin arlmas isteniyorsa
ar ak bir ekilde yaplmaldr:
ptr>~A();
deyimiyle ptr gstericisinin gsterdii yap nesnesinin sonlandrc ilevi arlyor. C++ da
bir snfn sonlandrc ilevinin ak bir ekilde arlmas gereken tek yer burasdr. Eer
programc
deleteptr
gibi bir deyim yazsayd bu alma zamanna ilikin bir hata olurdu. Dinamik olarak elde
edilen bir blok olmamasna karn, operator delete ileviyle ptr deikeninin deeri olan
adres free store alanana geri verilmeye allm olurdu.
Yeri belirli new ilecinin de keli ayral biimi vardr. lecin bu biimi kullanlarak,
verilen bir adresten balayarak birden fazla snf nesnesinin yaratlmas salanabilir.
Aada daha nce yazlan main bu kez ilevin keli ayra biimini kullanacak biimde
yeniden tanmlanyoruz:
intmain()
{
chars[3*sizeof(A)];
A*ptr=new(s)A[3];

for(intk=0;k<3;++k)
ptr[k].display();
for(intk=0;k<3;++k)
ptr[k].~A();
return0;
}
Bu kez yerel s dizisini, A nesnesinin saca byklkte tanmladk. Yeri belirli new
ileci ile bu kez A snf nesneleri balang adresi verilen blokta yaratld. A snfnn
sonlandrc ilevinin her nesne iin ayrca arldna dikkat edin.

nothrow new leci


new ve new[] ilelerinin nothrow parametreli bir biimleri de vardr. Bu ileler dinamik
bellek alan elde edilemedii zaman bad_alloc snf trnden bir hata nesnesi gndermek
yerine NULL adresi retir. Bu ilelerin dinamik blok elde etmek iin ardklar global
ilevlerin bildirimleri yledir:
void*operatornew(size_t,constnothrow_t&)throw();
void*operatornew[](size_t,constnothrow_t&)throw();
Grld gibi bu ilevlerin bildirimi hata nesnesi belirleme szdizimiyle yaplm, bu
ilevler iinden bir hata nesnesi gnderilmedii bildirilmitir.
nothrow_t ilevlerin imzalarn farkl klmak iin tanmlanan bo bir yap trnn ismidir.
new balk dosyas iinde nothrow_t trnden ismi nothrow olan bir nesne bildirilmitir.
structnothrow_t{
}nothrow;
Bu ileler aadaki gibi kullanlr:

312/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

classA{
//...
};
voidfunc()
{
A*ptr=new(nothrow)A;
if(!ptr){
//...
}
}
//...
new anahtar szcnden sonra alan ayra iinde nothrow isminin yazldn
gryorsunuz. Daha sonra da bir tr ismi yer alyor. Derleyicinin rettii kodla, dinamik
bellek blou elde etmek iin arlan ileve sizeof(A) deeri ve nothrow nesnesi geilir.
Yukardaki main ilevinde nothrow new ileciyle, A snf trnden bir nesne iin dinamik
bir blok elde ediliyor. lemin baars, ilecin rettii deerin NULL adresi olup olmad
ile snanyor. Eer dinamik bir blok elde edilirse, derleyicinin rettii kodla A snfnn
kurucu ilevi arlr. Ayn ilecin keli ayral biimiyle birden fazla snf nesnesi iin de
dinamik bir bellek blou elde edilebilir:
A*ptr=new(nothrow)A[10];
Yukardaki deyimin yrtlmesi sonucunda dinamik bellek blou elde etme giriimi
baarl olmaz ise ptr gsterici deikenine NULL adresi atanr. levin baarl olmas
durumunda A snfnn varsaylan kurucu ilevi her bir snf nesnesi iin bir kez, yani
toplam 10 kez arlr.

set_new_handler levi
new ilecinin baarsz olmas durumunda bad_alloc snf trnden bir hata nesnesi
gnderdii aklanmtr. Ancak hata nesnesinin gnderilmesinden nce programc
tarafndan gnderilen bir ilevin arlmas salanabilir. Bu amala set_new_handler ilevi
kullanlr.
set_new_handler ilevi, new ilecinin baarszl durumunda bir hata nesnesi
gnderilmesinden nce arlmas istenen ilevin adresini argman olarak alr. Yani ilevin
parametre deikeni bir ilev gstericisidir. levin geri dn deeri de daha nce
belirlenmi bir ilevin adresidir:
typedefvoid(*new_handler)();
new_handlerset_new_handler(new_handler);
Yukardaki bildirimleri inceleyelim:
new_handler geri dn deeri ve parametre deikeni olmayan bir ilev adresi trne
verilen typedef ismidir.
set_new_handler ilevinin parametre deikeni bu trdendir ve ilev de bu tre geri
dner.
set_new_handler ileviyle bir ilev belirlemesi yaplmaz ise, new ileci baarsz
olduunda hibir ilevi armaz dorudan bad_alloc snf trnden bir hata nesnesi
gnderir.
operator new ilevi dinamik blok elde etme ileminde baarsz olduunda, belirlenen
ilevi yalnzca bir kez armaz. Gereken bellek alann buluncaya kadar bir dng iinde

313/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


srekli arr. Bu kural set_new_handler ilevine sunulacak ilevin tasarmna baz
olanaklar salar. Bu ilev aadaki biimlerde tasarlanabilir:
1. lev daha fazla bir bellek alann operator new ilevinin hizmetine sunabilir. Bylece
ilev iini bitirdiinde artk bellek yetersizlii sz konusu olmayacandan, operator new
ilevi bad_alloc snf trnden bir hata nesnesi gndermez, iini baaryla tamamlar.
Program baladnda byk bir bellek blou elde edilir, ilev bu bellek alann kk
paralar halinde operator new ilevinin kullanmna sunabilir.
2. set_new_handler ileviyle yeni bir ilev kayt edilebilir. Bylece operator new bu kez
yeni ilevi arr. Yeni kayt edilen ilev bellek alan elde etmek iin baka i yapabilir ya
da baka bir algoritma kullanabilir, bylece operator new ilevi iin bir bellek alan
yaratlabilir.
3. lev set_new_handler ilevini NULL adresiyle arr. Bylece ortada arlmas
gereken bir ilev kalmadndan operator new ilevi bad_alloc snf trnden bir hata
nesnesi gnderir.
4. levin kendisi bad_alloc snf trnden ya da bad_alloc snfndan tretilmi bir snf
trnden hata nesnesi gnderir. Bu durumda gnderilen hata nesnesi operator new ilevi
tarafndan yakalanamaz. Bylece gnderilen hata nesnesi, new ilecinin kulland yerde
ya da daha yksek seviyede yakalanmaya braklabilir.

314/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

OKLU TRETME
Bir snf tek bir tretme ilemiyle birden fazla taban snftan tretmeye oklu tretme
(multiple inheritance) denir.
classA{
//
};
classB{
//
};
classC:publicA,publicB{
//
};
Yukardaki kod parasnda C snf, A ve B snflarndan oklu tretme yoluyla tretiliyor.
Szdizimde : atomundan sonra her bir taban snf isminin eriim belirteciyle birlikte yer
aldna dikkat edin. Eer tretme ilemi
classC:publicA,B{
//
};
biiminde yaplsayd, C snf, A snfndan public tretmesiyle ancak B snfndan private
tretmesiyle tretilmi olurdu.
Bir oklu tretme ilemine ilikin taban snflarn says hakknda bir kstlama yoktur.
Ancak uygulamalarn ounda bir snf iki ayr taban snftan public tretmesi ile tretilir.
oklu tretme ile elde edilmi tremi snf nesnesinin iinde her taban snfn elemanlar
da yer alr. Tretilmi nesnelerin bellekteki yerleimi standart olarak belirlenmemitir.
Ancak derleyicilerin ou tremi snf nesnesi iinde taban snf nesnelerini, nce
bildirilen taban snf nesnesi daha dk saysal adreste olacak biimde yerletirir:

Yukardaki gibi bir tretme ileminden sonra tremi snf olan C snf trnden bir nesne
tanmland zaman, nesnenin bellekte yerleimi aadaki gibi olabilir:

oklu Tretmede Bilinirlik Alan ve sim Arama


oklu tretme durumunda tremi snf, btn taban snflara eriebilir. Taban snflara
eriim konusunda, hibir taban snfn dierine gre stnl yoktur. Btn taban snflar
ayn bilinirlik alan iinde kabul edilir. Her iki taban snfta da ayn isimli bir eleman ya da
ye ilev varsa, elemana eriim znrlk ileci ile yaplmamsa bu durum ift
anlamllk hatasna yol aar. Tremi snf bilinirlik alannda bir isim kullanldnda bu isim

315/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


nce tremi snf bilinirlik alannda aranr. Eer bulunamaz ise bu kez bir sra
gzetmeksizin, taban snflarn her birinin bilinirlik alan iinde aranr. Aadaki rnei
inceleyin:
#include<iostream>
classBase1{
public:
voidfunc(){std::cout<<"Base1::func()"<<std::endl;}
};
classBase2{
public:
voidfunc(){std::cout<<"Base2::func()"<<std::endl;}
};
classMder:publicBase1,publicBase2{
//...
};
intmain()
{
Mdermd;
//md.func();Geersiz!Ciftanlamllkhatas
md.Base1::func();//Geerli
md.Base2::func();//Geerli
return0;
}
Yukardaki programda Mder snf Base1 ve Base2 snflarndan oklu tretme ile elde
ediliyor. Hem Base1 hem de Base2 snflar iinde func isimli ilevin bildirildiini
gryorsunuz. main ilevi iinde tanmlanan Mder snf trnden md nesnesi ile, func
ilevinin arlmas derleme zamannda ift anlamllk hatas oluumuna neden olur. Ancak
istenirse znrlk ilecinin kullanlmasyla, yani ismin nitelenmesiyle ift anlamllk
hatas ortadan kaldrlabilir. stenilen taban snfn func isimli ilevinin arlmas
salanabilir:
md.Base1::func()
arsyla Base1 snfnn func ilevi
md.Base2::func();
arsyla ise Base2 snfnn func ilevi arlabilir.
oklu tretmenin farkl kollarndaki ayn isimli ilevler arasnda ilev yklemesi (function
overloading) yaplamaz. nk imzalar farkl, ayn isimli ilevlerin bulunmas ayn
bilinirlik alanna zgdr. Aadaki kodu inceleyin:
#include<iostream>
classBase1{
public:
voidfunc(int){std::cout<<"Base1::func(int)"<<std::endl;}
};
classBase2{

316/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


public:
voidfunc(double){std::cout<<"Base2::func(double)"<<std::endl;}
};
classMder:publicBase1,publicBase2{
//...
};
intmain()
{
Mdermd;
//md.func(3.7);Geersiz!iftanlamllkhatas
md.Base1::func(5);//Geerli.
md.Base2::func(3.14);//Geerli.
return0;
}
Yukardaki kodda, Base1 snf iinde double trden parametre deikenine sahip func
isimli bir ilev tanmlanrken, Base2 snf iinde int parametreli ayn isimli bir ilev
tanmlanyor. main ilevi iinde tanmlanan Mder snf trnden md nesnesi ile yaplan
md.func(3.7);
ars yine ift anlamllk hatas oluturur. nk farkl bilinirlik alanlarnda bulunan,
parametrik yaplar birbirinden farkl olan func ilevleri iin ilev yklemesi yaplmas
mmkn deildir. Ancak istenirse nitelenmi ismin kullanlmasyla bu ilevlerden istenilen
birinin arlmas salanabilir:
md.Base1::func(5);
ars ile Base1 snfnn func isimli ilevi arlrken
md.Base1::func(3.14);
ars ile Base2 snfnn func isimli ilevi arlm olur.

Taban Snflarn Kurucu levlerinin arlmas


oklu tretmede taban snfn varsaylan kurucu ilevleri, taban snflarn bildirim srasna
gre arlr. Yani nce bildirilen taban snfn kurucu ilevi daha nce arlr. Tremi
snfn kurucu ilevlerin bana eklenen bir kodla, bildirim sralarna gre tm taban
snflarn kurucu ilevlerinin arlmas salanr. Sonlandrc ilevlerin ars ters srada
olur. Aadaki rnei derleyerek altrn ve kurucu/sonlandrc ilevlerin arlma
srasn gzlemleyin:
#include<iostream>
classBase1{
public:
Base1(){std::cout<<"Base1::Base1()"<<std::endl;}
~Base1(){std::cout<<"Base1::~Base1()"<<std::endl;}
};
classBase2{
public:
Base2(){std::cout<<"Base2::Base2()"<<std::endl;}

317/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


~Base2(){std::cout<<"Base2::~Base2()"<<std::endl;}
};

classMder:publicBase1,publicBase2{
public:
Mder(){std::cout<<"Mder::Mder()"<<std::endl;}
~Mder(){cout<<"Mder::~Mder()"<<endl;}
};
voidfunc()
{
Mdermder;
}
intmain()
{
func();
return0;
}
Taban snflarn varsaylan kurucu ilevlerinin deil de parametreli kurucu ilevlerinin
arlmas isteniyorsa bunun iin MIL szdizimi kullanlmaldr.

oklu Tretilmi Snflarda Tremi Snf Taban Snf


Dntrmeleri
Bir tremi snfn public tretmesi yoluyla birden fazla taban snftan tretilmesi
durumunda, tremi snf nesnesi ayn zamanda taban snflardan herhangi birinin
trnden nesneymi gibi kullanlabilir. rnein bir tremi snf nesnesinin adresi taban
snflardan herhangi biri trnden gstericiye atanabilir. phesiz taban snflardan biri
trnden gstericiye tremi snf trnden bir adres atandnda, atanan adres tremi
snf nesnesinin ilgili taban snf alt nesnesinin adresidir. Aadaki rnei derleyip
altrn:

318/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classBase1{
intb1;
public:
};
classBase2{
intb2;
public:
};
classMder:publicBase1,publicBase2{
intm1;
public:
};
#include<iostream>
intmain()
{
Mdermd;
Base1*base1_ptr=&md;
Base2*base2_ptr=&md;
std::cout<<"&md="<<&md<<std::endl;
std::cout<<"base1_ptr="<<base1_ptr<<std::endl;
std::cout<<"base2_ptr="<<base2_ptr<<std::endl;
return0;
}
Programn ekran ktsndan da greceiniz gibi, dntrme sonunda adresin saysal
bileeni deiebilmektedir. Daha sonra ters bir dnmn yaplmas, yani adresin eski
haline getirilmesi mmkn olmayabilir.
ki ayr snftan oklu tretmeyle elde edilmi tremi snf nesnesinin adresinin her iki
taban snf trnden gstericiye de atanabilmesi, ilev yklemesi srasnda ift anlamllk
hatasnn olumasna neden olabilir.
Aadaki gibi iki ilevin bildirildiini dnelim:
voiddisplay(constBase1&)
{
std::cout<<"display(constBase1&)"<<std::endl;
}
voiddisplay(constBase2&)
{
std::cout<<"display(constBase2&)"<<std::endl;
}
voidfoo()
{
Mdermd;
display(md);
}

//Geersiz!iftanlamllkhatas

Tremi snf adreslerinin taban snf trlerinden adreslere dntrlmesinde, taban


snflarn birbirlerine gre stnlkleri yoktur. md nesnesi ile yukardaki rnekte bildirilen
her iki display ilevi de arlabilir. Bu durumda ift anlamllk hatas oluur. ift anlamllk
hatas tr dtrme ilecinin kullanlmas ile ortadan kaldrlabilir:

319/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

voidfoo()
{
Mdermd;
display(static_cast<Base1>(md));
display(static_cast<Base2>(md));
}

Elmas Oluumu
oklu tretmelerde taban snfn bazen iki kopyas bulunur. Bu ou kez istenmeyen bir
durumdur.
Aadaki rnei inceleyin:
classBase{
inta;
public:
voidfunc();
};
classDer1:publicBase{
public:
//...
};
classDer2:publicBase{
public:
//...
};

classMder:publicDer1,publicDer2{
public:
//...
};
Yukardaki rnekte Der1 ve Der2 snflar Base snfndan tretiliyor. Mder snf da oklu
tretme yoluyla Der1 ve Der2 snflarndan tretiliyor. Burada Mder snfndan bir nesne
tanmlanrsa nesnenin bellekteki grnts aadaki gibi olur:

320/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


Grld gibi Base snf alt nesnesinden iki tane bulunmaktadr. Oysa bir tane
bulunmas daha istenen bir durumdur.
Bu yapya "elmas oluumu" denir (Dreadful Diamond of Derivation).
Elmas oluumu bir ok durumda ift anlamllk hatasna yol aar. Aadaki main ilevini
inceleyin:
intmain()
{
Mdermd;
//md.func();
md.Der1::func();
md.Der2::func();
return0;
}

//Geersiz!iftanlamllkhatas

md.func() ars geersizdir. nk hangi taban snftan alnan func ilevine eriildii belli
deildir. Ancak eriim iin znrlk ileci ile kullanldnda bir hata olumaz.
md.Der1::func();//Der1snfndanalnanfuncilevia?rlyor.
md.Der2::func();//Der2snfndanalnanfuncilevia?rlyor.
Mder snf trnden bir nesne hem Der1 hem de Der2 snf trnden nesne ise, normal
olarak Mder snf trnden bir nesnenin adresi Base snf trnden bir gstericiye
atanabilir. Ancak elmas oluumu sz konusu ise byle bir atama ift anlamllk hatasna
neden olur. Derleyici Mder snf trnden nesnenin iinde yer alan iki ayr Base snf
trnden nesnenin hangisinin adresini Base snfndan gsterici iine yerletirecei
konusunda seim yapamaz. Aadaki main ilevini inceleyin:
voidfunc()
{
Mdermder;
Base*base_ptr=&mder;//Geersiz!iftanlamllkhatas
}
Ancak tr dntrme ilemiyle, Mder snf nesnesi iinde yer alan Base snf trnden
nesnelerden hangisinin adresinin Base snf trnden gstericiye atanmas gerektii
derleyiciye aka bildirilebilir:
Base*base_ptr=static_cast<Base*>(static_cast<Der1*>(&mder));
Yukardaki ifade ile mder nesnesinin adresi nce static_cast tr dntrme ileciyle Der1
* trne dntrlyor. Sonra elde edilen Der1* trnden adres bu kez yine static_cast
ileciyle Base * trnden bir adrese dntrlerek base_ptr gstericisine atanyor.
Elmas oluumunun yol at bir sorun da udur: Taban snflardan herhangi birinin ye
ilevi arldnda bu ye ilevin ortak olan taban snfn elemanlar zerinde deiiklik
yaptn dnelim. Byle bir deiikliin yaplmasndan sonra, bu kez oklu tretilmi
snf nesnesiyle dier dorudan taban snf nesnesinin bir ye ilevi arldnda, yaplan
deiiklik etkisiz kalr. nk her dorudan taban snf kendi taban snf nesneleri
zerinde ilem yapmaktadr. Dorudan taban snflarn taban snflar tek deildir.
Aadaki rnei inceleyin:

321/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


#include<iostream>
classBase{
intm_a;
public:
Base():m_a(0){}
voidset(intval){m_a=val;}
intget()const{returnm_a;}
};
classDer1:publicBase{
public:
voidfunc(intx){set(x);}
};
classDer2:publicBase{
public:
voiddisplay()const{std::cout<<get()<<std::endl;}
};
classMDer:publicDer1,publicDer2{
public:
//
};
intmain()
{
MDermder;
mder.func(135);
mder.display();

return0;
}
Yukardaki rnekte main ilevi iinde MDer snf trnden bir nesne tanmlanyor. Bu
nesne ile MDer snfnn Der1 snfndan ald func isimli ye ilevi arlyor. Der1 snfnn
func ye ilevi Base snfnn eleman olan m_a deikeninin deerini deitiriyor. Daha
sonra bu kez MDer snfnn Der2 snfndan ald display ye ilevinin arldn
gryorsunuz. Bu ilev Der2 snfnn taban snf olan Base snfnn m_a elemannn
deerini alyor ve ekrana yazdryor.
mder.func(135);
ars ile m_a elemannn deeri 135 yaplmasna karn, daha sonra yaplan
mder.display();
arsyla m_a elemannn deeri olarak ekrana 0 deeri yazlr. nk MBase snfnn
dorudan taban snflar olan Der1 ve Der2 Base snf trnden ayr taban snf alt
nesneleri zerinde ilemler yapmaktadr.

oklu Tretme Snflarnda Sanal levlerin Kullanlmas


oklu tretilmi snf her bir taban snfnn sanal ilevini ezebilirBu durumda oklu
tretmeyle tremi snf iin, sanal ileve sahip taban snf says kadar ilev tablosu
bulunmas gerekir. Bu tr durumlarda oklu tretilmi snf nesnesinin adresini taban
snflardan birine ilikin gstericiye aktarp o gsterici yoluyla o snfn sanal ilevi
arldnda, derleyici o gstericinin gsterdii yerde sanal ilev tablo gstericisini arar.

322/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

#include<iostream>
classBase1{
public:
virtualvoidbase1_vfunc(){std::cout<<"Base1::base1_func()"<<
std::endl;}
};
classBase2{
public:
virtualvoidbase2_vfunc(){std::cout<<"Base2::base2_func()"<<
std::endl;}
};
classMder:publicBase1,publicBase2{
public:
virtualvoidbase1_vfunc(){std::cout<<"Mder::base1_func()"<<
std::endl;}
virtualvoidbase2_vfunc(){std::cout<<"Mder::base2_func()"<<
std::endl;}
virtualvoidmder_vfunc(){std::cout<<"Mder::mder_func()"<<
std::endl;}
};
intmain()
{
Mdermd;
Base1*base1_ptr=&md;
Base2*base2_ptr=&md;
base1_ptr>base1_vfunc();
base2_ptr>base2_vfunc();
return0;
}
Yukarda yer alan main ilevinde Mder snf trnden bir nesne olan md nesnesinin adresi
hem Base1 snf trnden gsterici olan base_ptr nesnesine hem de Base2 snf
trnden gsterici olan base2_ptr nesnesine atanyor.
Hem base1_ptr hem de base2_ptr ile yaplan sanal ilev arlar sonunda, arlan Mder
snfnn ilevleri olur.

Sanal Tretme
oklu tretmeye konu olan dorudan taban snflar, ortak bir taban snftan tretilerek
elde edilmilerse, oul tretilmi snf nesnesinin iinde iki ayr ortak taban snf nesnesi
yer alr. ou zaman istenmeyen bu duruma "Elmas oluumu" ismini vermitik.
Ortak olan taban snfn oklu tretilmi snfta yalnzca bir kez yer almas isteniyorsa
sanal tretme (virtual inheritance) denilen ara kullanlabilir. En son elde edilecek oklu
tretilmi nesne, yalnzca bir kez yer almas istenen taban snftan tretme yaplrken
virtual anahtar szcnn kullanlmasyla bu durum salanabilir. Aadaki kodu
derleyerek altrn:

323/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classBase{
inta;
public:
voidfunc();
};
classDer1:virtualpublicBase{
public:
//...
};
classDer2:virtualpublicBase{
public:
//...
};
classMder:publicDer1,publicDer2{
public:
//
};
Der1 ve Der2 snflar Base snfndan "sanal" olarak tretiliyor. virtual anahtar szc :
atomundan sonra yer alyor. virtual anahtar szc public anahtar szcnden sonra
da yazlabilir.
Yukardaki tretme ilemlerinden sonra Mder snf trnden bir nesne tanmlandn
dnelim:
Mdermd;
Bu nesnenin bellekte yerleimi aadaki gibi olur:

Sanal Taban Snfn Kurucu levinin arlmas


Sanal tretmede kurucu ilevlerin arlmas durumunda bir farkllk vardr. oklu
tretilmi bir snf nesnesi yaratldnda ilk olarak sanal taban snfn kurucu ilevi arlr.
Sanal taban snfn kurucu ilevini en alttaki tremi snfn kurucu ilevi armaldr. En
alttaki tremi snf (most derived class) nedir?
A snfndan sanal tretme yoluyla B ve C snflarnn tretildiini daha sonra B ve C
snflarndan oul tretme ile D isimli bir snfn tretildiini dnelim. Son olarak da D
snfndan E isimli bir snf tretilmi olsun:

324/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

B snfnn kurucu ilevi sz konusu olduunda en alttaki tremi snf B snf olur. Yani B
snfnn kurucu ilevi, ilk olarak A snfnn kurucu ilevini armaldr.
D snfnn kurucu ilevi sz konusu olduunda bu kez en alttaki tremi snf D snf olur.
Yani D snfnn kurucu ilevi ilk olarak A snfnn kurucu ilevini armaldr.
E snfnn kurucu ilevi sz konusu olduunda en alttaki tremi snf E snf olur. Yani E
snfnn kurucu ilevi ilk olarak A snfnn kurucu ilevini armaldr.
Sanal taban snfn kurucu ilevinin arlmas gerektii durumlarda bir sorun olumaz.
nk derleyici zaten en alttaki tremi snfn kurucu ilevinin koduna, sanal taban
snfn (rneimizde A snf) kurucu ilevinin arsn ekler. Ancak sanal taban snfn
parametreli bir kurucu ilevi arlacaksa, bu en alttaki tremi snfn kurucu ilevi iinde
M.I.L. szdizimi ile sanal taban snfn parametreli kurucu ilevinin arlmas ile olur.
Aadaki rnei derleyerek altrn:
#include<iostream>
classBase{
public:
Base(){std::cout<<"Base::Base()"<<std::endl;}
};
classDer1:virtualpublicBase{
public:
Der1(){std::cout<<"Der1::Der1()"<<std::endl;}
};
classDer2:virtualpublicBase{
public:
Der2(){std::cout<<"Der2::Der2()"<<std::endl;}
};
classMder1:publicDer1,publicDer2{
public:
Mder1(){std::cout<<"Mder1::Mder1()"<<std::endl;}
};
classMder2:publicMder1{
public:
Mder2(){std::cout<<"Mder2::Mder2()"<<std::endl;}
};
intmain()
{
Mder2mder2;
Mder1mder1;
Der1der1;
Der2der2;
return0;
}
Programc asndan bu durumun nemi udur: Tretme hiyerarisi iindeki herhangi
derinlikte bir snf, sanal taban snfn varsaylan kurucu ilevini deil de parametreli bir
kurucu ilevinin arlmasn isterse, sanal taban snfn kurucu ilevini M.I.L. szdizimiyle
armaldr. Aadaki rnei inceleyin:

325/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


classVbase{
//...
public:
Vbase(int);
//...
};
classBase1:virtualpublicVbase{
//
public:
Base1():Vbase(0){}
};
classBase2:virtualpublicVbase{
//...
public:
Base1():Vbase(0){}
//...
};
classDer1:publicBase1,publicBase2{
//...
public:
Der1():Vbase(0){}
};
classDer2:publicDer1{
//...
public:
Der2():Vbase(0){}
};
Yukardaki rnekte Vbase isimli snfn varsaylan kurucu ilevi yok. Snfn yalnzca tek
parametreli bir kurucu ilevine sahip olduunu gryorsunuz. Bu snftan sanal tretme
yoluyla Base1 ve Base2 snflar tretiliyor. Base1 ve Base2 snflarnn kurucu ilevleri
iinde M.I.L. szdizimiyle sanal taban snfn tek parametreli kurucu ilevi arlyor.
Base1 ve Base2 snflarndan oklu tretme yoluyla Der1 snf tretiliyor. Der1 snfnn
kurucu ilevinde de tepedeki sanal taban snf olan Vbase snfnn tek parametreli kurucu
ilevi M.I.L szdizimi kullanlarak arlyor. Ayn durum Der1 snfndan tretilen Der2
snf iin de geerlidir. Hangi kademede olursa olsun tretme hiyerarisi iinde yer alan
bir snf sanal taban snfn parametreli kurucu ilevini MIL szdizimiyle armak
zorundadr. Aksi halde tremi snf trlerinden herhangi biri trnden nesne
tanmlanmas durumunda derleme zamannda hata oluur.

oklu Sanal Tretmede Sanal levlerin Durumu


oklu sanal tretmede taban snflardaki bir sanal ilevin aaya doru tek bir sonlanan
ilevi (final overrider) olmaldr. rnein aadaki gibi bir tretme emas sz konusu
olsun:

326/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

A snfnn func isimli bir sanal ilevinin olduunu dnelim. Bu ilev hem B snfnda
hem de E snfnda ezilmise (override edilmise) bu durum hata oluturur. Yalnzca E
snfnda ya da yalnzca F snfnda ezilmise bu durum geerlidir.
C++n standart ktphanesinde giri k ilemlerini yapacak snflarda oklu tretme
uygulanmtr:

ios snfndan sanal tretme yoluyla istream ve ostream snflar tretilmi, istream ve
ostream snflarndan da oklu tretme ile iostream snf tretilmitir.
Bu durumda C++n standart iostream snf sisteminde ios taban snf alt nesnesinden
yalnzca bir tane bulunur.
Burada istream snf zerinde ilem yapldnda ve bu ilemler ios elemanlarn
deitirdiinde ostream bu deiiklikleri grr.

oklu Tretmenin Bir Taban Snfn Arayznn Onarlmas


Amacyla Kullanlmas
Baz durumlarda hizmet veren bir taban snfn arayz programcnn elinde olmasna
karn snfn kodlama dosyas yani kaynak dosya programcnn elinde bulunmaz. Bu
durumda byle bir snf zerinde ancak kstl deiiklikler yaplabilir. Snfa normal bir ye
ilev eklenebilir ama snfa bir sanal ilev eklenemez. Sanal olmayan bir ilev sanal ilev
haline getirilemez. Byle bir durumda, hizmet veren taban snfda bu tr deiiklikler
yaplmas mmkn olmad iin oklu tretme aracndan faydalanlr.
Onarmak amacyla yaplan i zetle udur: nce baka bir soyut taban snf oluturulur.
Bu soyut snfla elde ara yz olan hizmet veren taban snftan oul tretme yoluyla bir
snf tretilir. Dier tretmeler artk oul tretilmi snftan yaplr. Aadaki rnei
dikkatli bir ekilde izleyin:
Elimizde aadaki gibi bir arayzn olduunu dnelim:
////server.h
classServerBase{
public:
virtualvoidvfunc()const;//sanalilev
voidnvfunc()const;//sanalolmayanilev(sanalolmasnistiyoruz)
~Base3rd();//sanalolmayansonlandrcilev(tasarmhatas)
};
classServerDer:publicServerBase{

327/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


public:
voidvfunc()const;//sanalileveziliyor
~Der3rd();
};
voidglobal_func(constServerBase3rd&);//okbiimliilemeyapanilev
Yukarda hizmet veren bir kaynak dosyann arayz grlyor. ServerBase snfnn vfunc
isimli sanal bir ilevi var. Ancak snfn nvfunc isimli ye ilev sanal olmayan bir ilevdir.
Bu arayzn onarlarak nvfunc ilevinin sanal bir ilev haline getirilmesi isteniyor. Yine
snfn sonlandrc ilevi belki de ihmal sonucu sanal yaplm. Oysa kullanc kodlar
ServerBase snfnn sonlandrc ilevinin sanal sonlandrc ilev olmasn istiyor. Bir de
belirli bir amac gerekletirmesi amacyla snfa new_vfunc isimli bir sanal ilevin
eklenmesi isteniyor.
global_func1 ilevi ise taban snf referans yoluyla ok biimli ilem yapan global bir ilev.
server. cpp dosyas elde bulunmad iin snfn kaynak kodlarn deitirme ansmz
olmadn yeniden anmsatalm.
server.cpp Kaynak dosyasnn da aadaki gibi olduunu dnelim:
voidServerBase::vfunc()const
{
cout<<"ServerBase::vfunc()const"<<endl;
//...
}
voidServerBase::nvfunc()const
{

cout<<"ServerBase::nvfunc()const"<<endl;
//...
}
ServerBase::~ServerBase()
{
cout<<"ServerBase::~ServerBase()"<<endl;
//...
}
voidServerDer::vfunc()const
{
cout<<"ServerDer::vfunc()"<<endl;
//...
}
ServerDer::~ServerDer()
{
cout<<"Der3rd::~Der3rd()"<<endl;
}
voidglobal_func(constBase3rd&r)
{

r.vfunc();
r.nvfunc();
}
Snama amacyla nce ismi NewBase olan bir snf tanmlayalm:

328/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin

classNewBase{
public:
virtualvoidvfunc()const=0;//safsanalilev
virtualvoidnvfunc()const=0;//safsanalilev
//yeniarayuzeiliskinilev
virtualvoidnew_vfunc()const=0;
virtual~NewBase(){cout<<"~NewBase()"<<endl;}
};
NewBase isimli snfta vfunc, nvfunc ve new_vfunc isimli ilevlerin saf sanal ilev olarak
bildirildiini gryorsunuz. imdi de ismi Join olan bir snf NewBase ve ServerBase
snflarndan oklu tretme yoluyla treteceiz:
classServerBase{
public:
virtualvoidvfunc()const;//sanalilev
voidnvfunc()const;//sanalolmayanilev(sanalolmasnistiyoruz)
~ServerBase();//sanalolmayansonlandrcilev(tasarmhatas)
};
classServerDer:publicServerBase{
public:
voidvfunc()const;//sanalileveziliyor
~ServerDer();
};
#include<iostream>
usingnamespacestd;
voidglobal_func1(constServerBase&);//okbiimliilemeyapanilev
//elimizdeolmayankodlamadosyas
voidServerBase::vfunc()const
{
cout<<"ServerBase::vfunc()const"<<endl;
//...
}
voidServerBase::nvfunc()const
{
cout<<"ServerBase::nvfunc()const"<<endl;
//...
}
ServerBase::~ServerBase()
{
cout<<"ServerBase::~ServerBase()"<<endl;
//...
}
voidServerDer::vfunc()const
{
cout<<"ServerDer::vfunc()"<<endl;
//...
}
ServerDer::~ServerDer()
{

329/330

C ve Sistem Programclar Dernei - C++ Ders Notlar - Necati Ergin


cout<<"ServerDer::~ServerDer()"<<endl;
}

voidglobal_func(constServerBase&r)
{
r.vfunc();
r.nvfunc();
}
classNewBase{
public:
virtualvoidvfunc()const=0;//safsanalilev
virtualvoidnvfunc()const=0;//safsanalilev
//yeniarayuzeiliskinilev
virtualvoidnew_vfunc()const=0;
virtual~NewBase(){cout<<"~NewBase()"<<endl;}
};
classJoin:publicNewBase,publicServerBase{
public:
voidvfunc()const{cout<<"Join::vfunc()"<<endl;
ServerBase::vfunc();}
voidnvfunc()const{cout<<"Join::nvfunc()"<<endl;
ServerBase::nvfunc();}
voidnew_vfunc()const{cout<<"Join::new_vfunc()"<<endl;}
~Join(){cout<<"Join::~Join()"<<endl;}
};
intmain()
{
Join&join_ref=*newJoin;
NewBase&nbase=join_ref;
nbase.vfunc();
cout<<"*******************************************"<<endl;
nbase.new_vfunc();
cout<<"*******************************************"<<endl;
global_func(join_ref);
cout<<"*******************************************"<<endl;
delete&nbase;
cout<<"*******************************************"<<endl;
return0;
}

330/330

You might also like