C++ / C Programlama

Eniqma
16-08-2006, 01:55   |  #1  
OP Yeni Üye
Teşekkür Sayısı: 0
23 mesaj
Kayıt Tarihi:Kayıt: Ağu 2006

Giriş

Yazılım geliştirme işi, gerçek dünyadaki bir uygulamanın bilgisayar üzerinde modellenmesidir. Bir yazılım sistemi iki ana unsurdan oluşur: veriler ve bu veriler üzerinde yapılan işlemler. Bilgisayarla çözülecek olan problemin ayrıştırılması (decomposition) aşamasında, programın temelinin hangi unsurlardan oluşacağına karar verilmelidir.

veriler mi ? işlemler mi?

Altprogramlara dayalı dillerde (C, Pascal) program bir dizi fonksiyon çağrısı görünümündedir. Her fonksiyon belirli bir grup işlemi kendisine gönderilen veriler üzerinde gerçekleştirir ve bir ya da daha çok sonuç oluşturur. Bu dillerde fonksiyonlar birer kara kutu gibi çalışırlar. Bu programlama modeli işlemleri temel olarak kabul etmektedir.

Nesneye dayalı programlama yönteminde veriler temel alınarak program tasarımı yapılır.

Bir yazılım sisteminin tasarımına başlanırken sorulması gereken ilk soru,

“Bu sistem ne yapar ?” DEĞİLDİR.

Sorulması gereken ilk soru,

“Bu sistem, işlemleri hangi veriler üzerinde uygular ?” OLMALIDIR.

Nesneye dayalı yöntemde düşünce şekli, problemi bilgisayarın tanıyacağı yapılara dönüştürmek değildir. Amaç, bilgisayarın ve yazılım ortamının probleme adapte edilmesidir. Bunun için problemi oluşturan varlıklar belirlenir. Varlıklar birbirlerinden fiziksel ve mantıksal ayrılıklarıyla ve problemin geri kalanından bağımsız olmalarıyla tanınırlar. Bu varlıklar programlama dilinde nesneler ile temsil edilir. Çözülecek problemdeki varlıklar ile programdaki nesneler arasında birebir ilişki kurulması amaçlanır.

Nesneye dayalı yöntemde yazılım geliştirmek, yeni veri tipleri (sınıf) yaratmak ve bu veri tiplerine, kendilerine gönderilen mesajlar karşısında nasıl davranacaklarını öğretmektir.

Bir sınıfa, gelen mesajlara nasıl bir davranışla karşılık vereceği metodlarla öğretilir.

Sınıfın kullanıcısı, bu veri tipinden örnekler (instances) yani nesneler türetir ve bu nesnelere mesajlar gönderir.


Verileri Temel Almanın Yararları:

· Uyumluluk (Compatibility): Verileri göz ardı ederek işlemlere (yordamlara) dayalı yapılan ayrıştırma program içi uyumluluğu güçleştirmektedir.
· Tekrar Kullanılabilirlilik (Reusability)
· Süreklilik (Continuity): Bir programın yazılması ve değiştirilmesi aşamasında veriler daha sabit bir yapıya sahiptir. Yordamlar ise daha sık değiştirilirler.

Nesneye Dayalı Programlamanın Özellikleri:

· Uygulamayı oluşturan varlıkları modellemek için, verilerin ve onların üzerinde işlem yapan yordamların bir arada bulunduğu ‘nesneler’ kullanılır (Veri Soyutlama).
· Nesneler, sınıf (class) adı verilen bir veri yapısı ile oluşturulur.
· Sınıfı kullanan programda nesneler tanımlanır ve bu nesnelere mesajlar gönderilir. Mesajlar karşısında bir davranışta bulunmak sınıfın işidir (Veri Gizleme).
· Veri soyutlama ve veri gizleme modüller arası bağımlılığı azaltır. Değişiklikler modül içinde kalır, tüm sistemi etkilemez.
· Kalıtım (inheritance) özelliği kullanılarak bir sınıf başka bir sınıftan türetilebilir.
· Yordamların çok şekillilik (polymorphism) özelliği vardır.

Nesneye dayalı programlamada 3 temel kavram:

1) Soyut veri tipi yaratma
2) Kalıtım
3) Çokşekillilik

C++' IN SUNDUĞU YENİLİKLER

Inline (macro) Tanımı:
Başına inline yazılan fonksiyonlar macro olarak tanımlanırlar. Bu fonksiyonlar için ayrı kod üretilmez, bunun yerine fonksiyon kodu çağrıldığı her yerde tekrarlanır.

inline int max (int i1,int i2){
return(i1>i2) ? i1 : i2;
}

Fonksiyon Parametrelerine Başlangıç Değerleri Verilmesi (Default)
Fonksiyonların parametre listesinde, parametrelere başlangıç değeri verilebilir. Başlangıç değeri verilmiş parametreler için fonksiyon çağrısı sırasında yeni bir değer belirtilmezse, başlangıç değeri kullanılır.

void GotoXY (int x, int y=wherey()){
goto(x,y);
}
.
GotoXY(1); //Bulundugu satırın başına
GotoXY(1,1); // (1,1) Noktasına

Başlangıç değerleri fonksiyon bildirimi (declaration) sırasında verilir. Birden fazla parametreye başlangıç değeri verilecekse, bu parametreler listenin sonunda yeralmalıdır.

Referans Operatörü &
& operatörü bir değişkenin adresini verir.

int i;
int &j=i; // j ile i aynı adrese sahip
i=5;
j++; // i=6 oldu

Fonksiyonlara değişken parametre aktarımında kullanılır. Bunun için C’de kullanılan işaretçi ile aktarım yöntemi programın okunuşunu zorlaştırmaktadır.

void hesap(int j) {j=j*j/2;} // j degişmez , fonksiyon anlamsız
void main()
{
int i=5;
hesap(i); // i değişmez
}

İşaretçi (pointer ) kullanarak çözüm
void hesap(int *j) {
*j=*j**j/2;
}
void main()
{
int i=5;
hesap(&i);
}

C++’ta referans kullanarak çözüm
void hesap(int &j){ j=j*j/2;}
void main()
{
int i=5;
hesap(i);
}
Burada fonksiyonun parametreyi değişken olarak aldığı kullanıcı programa saydamdır.

Değişken Tanımlama Yerleri ve "scope" operatörü ::
Değişkenler gerekli oldukları yerlerde tanımlanabilirler. Bu özellik programın anlaşılırlığını artırır.
int a=0;
for (int i=0; i < 100; i++){ // kullanıldığı yerde tanımlama
a++;
...
int p=12;
... // p’nin kullanım yeri
}
int p=1; // farklı bir p
} // buradan sonra i tanımsız

! : For döngüsünden önce tanımlanan i değişkeni, tanımlandığı satırdan, for döngüsünü kapsayan bloğun sonuna kadar tanımlı kalır.

Scope operatörü :: ile örtülmüş global değişkenlere erişilebilir.
int x=1;
void f(){
int x=2; // Yerel x
::x++; // Dışarıdaki x
}

Sabit Tanımlama
C dilinde kullanılan #define yerine C++’ta const ile sabitler tanımlanabilir.

const int max=100; // Program içinde değiştirilemez

Const ile tanımlanan sabitler herhangi bir tipten (önceden tanımlanmış ya da kullanıcı tipi) olabilir. Herhangi bir değişken gibi const ile tanımlı sabitler de scope alanına sahiptir).

new ve delete Operatörleri
C’deki malloc, calloc, free gibi dinamik bellek ayırma ve iade etme fonksiyonları yerine, C++’ta new (bellek ayırma) ve delete (bellek iade etme) operatörleri kullanılır.

C:
struct ComplexT{ // Karmaşık sayıları tanımlayan yapı
float re,im; // gerçel ve sanal kısımlar
};
void main()
{
ComplexT *cp=(ComplexT*) malloc (sizeof(ComplexT));
:
free(cp);

C++:
ComplexT *cp=new ComplexT;
:
delete cp;

Dinamik bir dizi açmak için dizinin boyu belirtilmelidir.

ComplexT *cp = new ComplexT[10];

Fonksiyon İsimlerinin Yüklenmesi
Parametrelerinin tipleri, sayıları ve/veya diziliş sıraları farklı olmak koşulu ile değişik fonksiyonlar aynı ada sahip olabilirler.

struct ComplexT{
float re,im;
};

void print (float value){ // reel sayıları yazan print
printf("n val= %f", value);
}
void print (ComplexT c){ // Karmaşık sayıları yazan print
printf("n reel= %f im= %f", c.re,c.im);
}
void print (char c){ // Karakter yazan print
putchar(c);
}
void main(){
ComplexT z;
z.re=0.5;
z.im=1.2;
print(z);
print(4.2);
print('A');
}

Operatörlere Yeni İşevlerin Yüklenmesi
C++ ta operatörler birer fonksiyon gibi değerlendirilirler ve bu operatörlerle ilgili yeni fonksiyonlar yazılabilir.

Örnek: Karmaşık Sayıların Toplanması
struct ComplexT{
float re,im;
};
ComplexT operator+ (ComplexT v1, ComplexT v2){
ComplexT result;
result.re=v1.re+v2.re;
result.im=v1.im+v2.im;
return result;
}
void main(){
ComplexT c1,c2,c3;
c3=c1+c2;
}

NESNEYE DAYALI PROGRAMLAMA

* Problemi oluşturan somut ve/veya varlıklar (nesneler) belirlenir.
Grafik: nokta, çizgi, çember ...
Matematik: karmaşık sayılar, matrisler...
Personel Programı: işçi, müdür, genel müdür...
* Bu varlıklar ayrı ayrı modellenir.
* Ana programda bu nesneler canlandırılır.
Canlanan nesne aldığı mesaja göre bir davranışta bulunur, yeni bir duruma geçer, gerekiyorsa bir çıkış mesajı üretir ve yeni bir mesaj gelinceye kadar beklemeye devam eder.

Sınıf Yapısı ve Nesneler

Sınıf, birbiriyle ilişkili verilerin ve bu verileri kullanmayı sağlayacak yordamların bir arada bulundurulmasını sağlayan bir yapıdır. Veri ve yordamların sistemin kalanından ayrılmasını ve gerekliyse gizlenmesini sağlar. Bir sınıf yaratmak yeni bir veri tipi yaratmaktır. Hazır bir veri tipi üzerinde hangi işlemlerin yapılabileceği derleyici tarfından bilinmektedir. Yaratılan yeni veri tipi (soyut veri tipi) üzerinde yapılabilecek işlemler de derleyiciye, sınıfa üye yordamlar (metodlar) tarafından öğretilir.

Gerçek Dünya:
Nesne = Nitelikler + Davranışlar

Yazılım Ortamı:
Nesne = Veriler + Yordamlar
(Object = Data + Procedures)

Sınıf (Class)
Class nesneleri tanımlamak için kullanılan tip tanımıdır. Ortak özelliklere sahip nesnelere ait veri ve yordamlar bir sınıfın içinde toplanırlar. Bu sınıf yapısı kullanılarak program içinde nesneler tanımlanır.
Sınıf tanımı, veri tanımları ve üye yordamların bildirimlerinden oluşur. Yordamların gövdeleri sınıf tanımının dışında bulunur.

Örnek: Bir grafik programındaki nokta sınıfı
class nokta_sinifi{
int x,y; //x,y koordinatları NİTELİKLER
public:
void hareket(int,int); //yordamlar DAVRANIŞLAR
void ciz();
void sil();
};
Yordamların Gövdeleri:
void nokta_sinifi::hareket(int x_yeni, int y_yeni)
{
x=x_yeni;
y=y_yeni;
}
void nokta_sinifi::ciz()
{
putpixel(x,y,1);
setcolor(WHITE);
outtextxy(x+1,y+1,"NOKTA");
}
void nokta_sinifi::sil()
{
putpixel(x,y,0);
setcolor(BLACK);
outtextxy(x+1,y+1,"NOKTA");
}
Bir sınıftan nesne yaratmak, herhangi bir veri tipinden veri tanımlamak gibidir. Dışarıdan nesnenin yordamlarına ‘.’ ile erişilir.

Ana Program
void main()
{
nokta_sinifi nokta1; // nokta1 nesnesinin yaratılması
nokta1.hareket(50,50);
nokta1.ciz();
nokta1.sil();
nokta1.hareket(350,200);
nokta1.ciz();
nokta1.sil();
}
Nesne işaretçileri kullanarak:
void main()
{
nokta_sinifi *np = new nokta_sinifi; // np nesne işaretçisidir
np->hareket(50,50);
np->ciz();
p->sil();
}

Bir nesne iç durumu ve işlemleri ile tanımlanabilen bir varlıktır. İşlemleri yapan yordamlara metod, güncel yordam çağrılarına da mesaj adı verilir. Durum bir nesnenin kendine ait bilgileri hatırladığını ifade etmektedir. Bu nedenle metodlar, nesnenin içinde bulunduğu duruma göre her çağrıldıklarında farklı davranışlar gösterebilir.


Erişim Hakları
Özel (private) olarak tanımlanan verilere sadece o sınıfın üye fonksiyonları erişebilir. Sınıfın dışından erişim yapılması istenen veriler açık (public) olarak tanımlanmalıdır. Bu koruma yöntemleri ile verilerin istenmeyen değerler alması engellenmiş olur.

Normalde bir sınıfın bütün üyeleri özeldir. Açık olması istenen üyelerin tanımından önce public sözcüğü belirtilmelidir.

void nokta_sinifi::hareket(int x_yeni, int y_yeni)
{
if(x_yeni > 0 && x_yeni < getmaxx()
&& y_yeni > 0 && y_yeni < getmaxy())
{
x=x_yeni;
y=y_yeni;
}
}

nokta1.x = -10; // Derleme Hatası: Erişim Yasaklanmıştır

C++’ta arayüz (interface) ile gerçekleme (implementation) birbirinden belirgin şekilde ayrılmıştır. C++’ta arayüz, sınıf tanımıdır. Arayüz ile, bir nesnenin nasıl bir görünümü olduğu ve bu nesnenin metodlarının neler olduğu öğrenilir. Metodların nasıl çalıştıklarının ayrıntısı (yordam gövdeleri) sınıfta yeralmaz.

Gerçeklemede ise metodların nasıl çalıştığı yeralır, burada tüm üye yordamların gövdeleri bulunur. Metodların gövdelerinde değişiklik yapılsa bile arayüz aynı kalabilir.
Bu özellik sayesinde programın tasarımı sadece arayüz tasarımı yapılarak tamamlanabilir. Metodlar bir defa belirlendikten sonra, gövdelerinin yazılması, sınıfı kullanan programın tasarımı için gerekli değildir ve tüm programın link aşamasına kadar bekletilebilir.

Arkadaşlık İlişkisi
Bir sınıf arkadaşı olduğu sınıfın tüm erişim haklarına sahiptir.
class A{
friend class B; // B sınıfı, A sınıfının arkadaşı
int i;
float f;
public:
void fonk1(char *c);
};
class B{
int j;
public:
void fonk2(A s){printf("%d",s.i);} // B sınıfı A'nın elemanına erişiyor
};

Fonksiyonlar da bir sınıfın arkadaşı olabilirler.
class ComplexT{
friend void print(ComplexT); // print foksiyonu bu sınıfın arkadaşıdır
float re,im;
:
};
void print(ComplexT z)
{
printf("n reel=%f im=%f",z.re , z.im);
}
Özel veri ve yordamlarına erişim hakkını veren sınıf, diğer yordam ya da sınıflara arkadaşlık hakkını vermede kontrol sahibidir. Bu nedenle hangi yordam ya da sınıfların kendi üyelerine erişebileceği bilgisi bu sınıfın tanımında yeralır. Böylece sınıfın arayüzü incelendiğinde, üyeler ve yordamlardan başka, hangi yordam ya da sınıfların o sınıfın verilerine müdahale edebileceği hemen görülebilir.

Sınıf İşaretçisi "this"
Bir sınıfın üye fonksiyonu yürütülürken this işaretçisi o fonksiyonun ait olduğu sınıfa işaret eder.
Örnek: Çift bağlantılı liste
class dlink{
dlink *once;
dlink *sonra;
public:
void ekle(dlink *);
};
void dlink::ekle(dlink * p)
{
p->sonra=sonra;
p->once=this;
sonra->once=p;
sonra=p;
}
:
dlink dl1,dl2;
:
dl1.ekle(&dl2);

Operatörlere Yeni İşlevlerin Yüklenmesi
C++, sınıf yapısı yardımıyla dile yeni bir veri tipi eklenmesini sağlar. Dildeki tanımlı veri tipleri üzerinde operatörler ile bazı işlemler yapılabilir. Aynı operatörleri yeni tanımlanan veri tipleri ile de kullanabilmek için, operatörlere yeni işlevlerin yüklenebilmesi gereklidir. Bu yetenek ile, yeni tanımlanan bir veri tipi dile tümüyle entegre edilebilir.

#include
class ComplexT{ // Kompleks Sayıları tanımalayan Sınıf
float re,im;
public:
void set(float re_in,float im_in){re=re_in;im=im_in;}
ComplexT operator+(ComplexT&); // + operatörünün fonksiyonu
void operator()(); // () operatörünün fonksiyonu
};

/** + operatörünün işlevini tanımlayan fonksiyon **/
ComplexT ComplexT::operator+(ComplexT& z)
{
ComplexT result;
result.re = re + z.re;
result.im = im + z.im;
return result;
}
/** () operatörünün işlevini tanımlayan fonksiyon **/
void ComplexT::operator()()
{
printf("n (%f , %f)",re,im);
}

void main()
{
ComplexT z1,z2,z3,z4;
z1.set(0.5,-3);
z2.set(2,1.5);
z3=z1+z2; // + operatörüne ilişkin fonksiyon canlanır
z3(); // () operatörüne ilişkin fonksiyon canlanır
z4=z1+z2+z3; // Önce result = z1 + z2 ardından z4 = result + z3
z4(); // () operatörüne ilişkin fonksiyon canlanır
}

Kurucu Fonksiyonlar (Constructor)
Hazır bir veri tipinden bir örnek yaratıldığında, derleyici bu değişken için bellekte yer ayırır. Yaratılan değişkene bir başlangıç değeri atanması istenirse derleyici bunu da yapabilir. Bu şekilde derleyici değişkeni kurar. Değişkenin erişim alanının dışına çıkıldığında, derleyici değişken için ayrılan bellek alanını geri vererek değişkeni yokeder.

C++’ta kullanıcının tanımladığı veri tiplerinin (sınıf) mümkün olduğu kadar hazır veri tiplerine yakın olması amaçlanmaktadır. Derleyici kullanıcının tanımladığı veri tiplerini kurmak ve yoketmek için ne yapması gerektiğini bilemeyeceğinden, kendisine yol gösteren yordamlara gerek duyar.
Sınıfın kurucu fonksiyonları sınıf ile aynı adı taşırlar ve sınıftan bir nesne tanımlandığı anda kendiliğinden canlanırlar. Kurucu fonksiyonlar nesnelere başlangıç değeri atamak için ve gerektiğinde verilere bellekte yer ayırmak için kullanılırlar.

class ComplexT{
float re,im;
public:
ComplexT(){ // Kurucu Fonksiyon
re=0;
im=0;
}
};
Burada üye bir fonksiyonun, daha önce görüldüğünün aksine, gövdesinin de sınıf tanımı içinde yeraldığı görülmektedir. C++’ta bu şekilde yazılan fonksiyonlar inline olarak değerlendirilir.
void main()
{
ComplexT z1,z2; // Kurucu fonksiyon 2 defa canlanır
ComplexT *zp = new ComplexT; // Kurucu fonksiyon 1 defa canlanır
}
Bir sınıfta değişik tipte ve sayıda parametreye sahip birden fazla kurucu fonksiyon olabilir.

class ComplexT{
float re,im;
public:
ComplexT(float re_in){re=re_in; im=0;}
ComplexT(float re_in,float im_in){re=re_in; im=im_in;}
: // Diger Fonksiyonlar....
};

void main()
{
ComplexT z1(0.3);
ComplexT z2(0.5 , 1.2);
ComplexT *zp=new ComplexT(0.4);
ComplexT z3; // HATA Parametresiz kurucu yok
}


Sınıflara Başlangıç Değerlerinin Atanması
Eğer bir sınıf kurucu fonksiyona sahip değilse ve tüm üyeleri ‘public’ olarak tanımlanmışsa, üyelerine ilk değerlerini atamak için başlangıç değer dizisi kullanılabilir. Bu dizi ‘{ }’ parantezleri içinde ‘ , ’ ile ayrılmış sabit değerlerden oluşur. Dizideki her sabit değer nesne içindeki üyelere tanımlandıkları sırada atanır.


class X {
public:
float a , b;
// yordamlar ....
};

X n = {1.1 , 2.2}; // n.a=1.1 n.b=2.2 olur.

Nesne Dizilerine Başlangıç Değerlerinin Atanması
Bir sınıftan nesne dizisi tanımlandığında o sınıfın parametre almayan bir kurucu fonksiyonu varsa, bu fonksiyon dizideki her eleman için bir kez çalışır.
Bir nesne dizisi yaratmak ve aynı zamanda parametre alan bir kurucu fonksiyon çalıştırarak başlangıç değerleri atamak istendiğinde başlangıç değerleri listesinden yararlanılır.

class ComplexT{
float re, im;
public:
ComplexT(float, float);
};
ComplexT::ComplexT(float d1, float d2=1){
re = d1; im = d2;
}

void main(){
ComplexT s[ ]={ {1.1}, {3.3}, ComplexT(4.4,1.1)};
}

Bu örnekte 3 elemanlı bir s dizisi tanımlandığından kurucu fonksiyon 3 defa canlanır. Birden fazla parametre alan bir kurucu fonksiyonu canlandırmak için bu fonksiyon adı yazılarak çağırılmalıdır.
Aşağıdaki örnekte ise 5 elemanlı bir dizi tanımlanmış, fakat sadece ilk üç elemanın başlangıç değeri verilmiştir. Bu durumda son iki eleman için parametre almayan bir kurucu fonksiyon gereklidir. Eğer sınıfta böyle bir kurucu fonksiyon yazılmamışsa derleme hatası oluşur.

ComplexT s[5]={ {1.1}, {3.3}, ComplexT(4.4,1.1)};
Yok Edici Fonksiyonlar (Destructor)
Yok edici fonksiyon ait olduğu sınıfla aynı adı taşır ve bu adın başına '~' işareti gelir. Yok edici fonksiyon nesnenin tanımlı olduğu bölgeden çıkılırken kendiliğinden canlanır. Her sınfta en fazla bir tane yok edici fonksiyon olabilir. Bir sınıfın kurucu fonksiyonu olsa bile eğer gerek duyulmuyorsa yok edici fonksiyonu olmayabilir. Yok edici fonksiyonlar parametre almazlar.

Örnek: Yığın yapısı tanımlayan sınıf
class stack{
int *top; // Yığın işaretçisi
int *bottom;
int num; // Yığındaki eleman sayısı
public:
stack(){top=bottom=new int[100];num=0;} // Kurucu
void push(int i)
{
if(num<100) {*top++=i;num++;} else printf("n Yigin Dolu");
}
int pop()
{
if(num>0) {num--; return *--top;} else printf("n Yigin Bos");
}
~stack(){delete bottom;} //Yok edici fonksiyon
};
void main()
{
stack s1,s2;
int a,b;
s1.push(5);
s1.push(8);
s2.push(4);
a=s1.pop();
b=s1.pop();
a=s2.pop();
:
}

Bir Sınıfın Başka Bir Sınıfa Üye Olması
Nesneye dayalı programlamanın amaçlarından biri, daha önce yazılmış bir program kodunun yeniden kullanılmasını kolaylaştırmaktır. Önceden yazılmış bir program kodunu yeni yazılan programa adepte etmenin çeşitli zorlukları (kodun anlaşılır olmayışı, program düzeninin farklılığı, modüller arası bağımlılık, vs.) vardır. Nesneye dayalı programlamanın doğal yapısı bu mantıkla yazılmış olan eski kodun yeni programa uyarlanmasını kolaylaştırmaktadır. Bunun için iki yöntem kullanılmaktadır. Bunların ilki bir sınıfın başka bir sınıfa üye yapılmasıdır. İkinci olanak ise ileride ayrıntılı olarak incelenecek olan, daha esnek bir programlama olanağı sağlayan kalıtım özelliğidir.
C++’ta, daha önce tanımlanmış olan bir sınıf, başka bir sınıfın içinde üye eleman olarak yer alabilir.

class kesir{ // Kesir yapısı tanımlayan sınıf
int pay,payda;
public:
kesir(int py=0, int pyd=1){
pay=py;
payda=pyd;
}
:
};
class ComplexKes{ // Karmaşık sayıları tanımlayan sınıf
kesir re,im; // kesir sınıfı tipinden iki veri
public:
ComplexKes(int re_in=0,int im_in=0):re(re_in),im(im_in)
{
: // Gerekl islemler
}
}
Ana programda aşağıdaki tanımlama yapıldığında önce ComplexKes kurucu fonksiyonu canlanacaktır. Ancak bu fonksiyona ait işlemler gerçekleştirilmeden önce üye sınıflara (kesir sınıfı) ait kurucu fonksiyonlar yürütülecektir. Ardından asıl kurucu fonksiyona ait işlemler gerçekleştirilecektir.
ComplexKes c(8,3);

Örnekte görüldüğü gibi, bir sınıfa üye nesne yaratırken kullanılan yazılım, normalde bir sınıftan bir nesne yaratırken kullanılandan biraz farklıdır. Normalde yaratılan nesneye başlangıç değeri atanacaksa, bu değer nesnenin adının yanına yazılarak kurucu fonksiyona aktarılır. Ancak üye nesneler için bu yöntem kullanılamaz. Üye nesnelerin sadece bildirimi yapılır. Başlangıç değerleri ancak, üyeyi kapsayan sınıfın kurucu fonksiyonu çağrıldıktan sonra verilebilir.
ComplexKes(int re_in=0,int im_in=0)
{ // Deişkenler 'private' olduğundan aşağıdaki erişimler yasaktır.
re.pay=re_in;
re.payda=1;
im.pay=im_in;
im.payda=1;
}

Sabit Nesneler ve Sabit Fonksiyonlar
Sabit (const) olarak tanımlanan nesnelerin üye verileri program içinde değiştirilemez. Sabit fonksiyonlar ise hiç bir veri üzerinde değişiklik yapmayan fonksiyonlardır. Sabit olarak tanımlanmış olan nesnelerin, program içinde sadece sabit üye fonksiyonları çağırılabilir. Nesne sabit olmasa bile sabit üye fonksiyonları varsa çağırılabilir. Üye veriler üzerinde değişiklik yapan fonksiyonlar sabit olarak tanımlanamaz. Bu tip fonksiyonlar, sabit bir üye fonksiyon tarafından çağrılamaz.

class ComplexT{
float re,im;
public:
ComplexT(float re_in=0,float im_in=0){
re=re_in;
im=im_in;
}
void print() const{ // Sabit fonksiyon
printf("n sayi=%f , %f",re,im);
}
void sifirla(){re=im=0;} // Sabit olmayan fonksiyon
};
void main()
{
const ComplexT I(0,1); // Sabit nesne
ComplexT z(1.2,0.5) // Sabit olmayan nesne
I.print(); // Doğru
I.sifirla(); // HATA
z.sifirla(); // Doğru
}


'static' Üyeler
Static sözcüğünün C dilinde 2 farklı anlamı vardır. Fonksiyon içinde tanımlanan yerel bir değişkenin değerinin ardarda fonksiyon çağrıları arasında hatırlanması isteniyorsa değişken static olarak tanımlanır. İkinci bir kullanım ise bir değişken ya da fonksiyonun program dosyasının dışında tanımsız olmasını sağlamaktır.

C++’ta static sözcüğüne üçüncü bir kullanım şekli getirilmiştir. Bir sınıfın static olarak tanımlanan üyeleri o sınıftan oluşturulan tüm nesneler tarafından ortak değişken olarak paylaşılırlar.

Normalde bir sınıftan nesneler yaratılırken, her nesne için sınıftaki üye veriler tekrarlanır. Her nesnenin kendine ait üyeleri bulunur ve aynı sınıftan tanımlanmış diğer nesnelerin üyelerinden bağımsızdırlar. Yalnızca static olarak tanımlanan üye veriler bu şekilde tekrarlanmaz. Static bir üye verinin yalnızca bir kopyası bulunur ve tüm nesneler bu kopyaya erişir. Static üyeler genellikle aynı tipten nesneler arasında haberleşme için kullanılır.

Static bir üye veriye başlangıç değeri bildirim anında verilemez. Bunun için üye bir fonksiyon kullanılmalıdır.

class A{
char c;
static int i;
: // diğer üyeler
};
void main()
{
A p,q,r;
:
}

Static değişkenlere başlangıç değeri hiç bir nesne yaratılmadan önce verilmelidir. Bu değişkenlere başlangıç değeri atayacak fonksiyonlar da static olarak tanımlanmalıdır.

class A{
char c;
static int sayi; // A sınıfından yaratılan nesne sayısı
public:
static void baslangic(){sayi=0;}
A(){sayi++;} // Constructor
~A(){sayi--;} // Destructor
};

int A::sayi; // Bellekte yer ayırılıyor

void main()
{
A::baslangic(); // sayi=0 'static' fonksiyon çağırıldı
A a,b,c; // sayi=3; a,b,c nesnelerinin kurucuları çalışır
:
{
A d,e; // sayi=5 d,e nesnelerinin kurucuları çalışır
:
} // d,e nesnelerinin yok edicileri çalışır
: // sayi=3
} // a,b,c nesnelerinin yok edicileri çalışır

Static bir üye fonksiyon da, static üye veri gibi, nesnenin bir parçası olmaktan çok sınıfa aittir. Static üye fonksiyon herhangi bir nesne ile bağlantılı olmadan çağırılır. Bu fonksiyonlar yalnızca sınıfın tüm nesneleri tarafından paylaşılan verileri (static üye veriler ve global veriler) değiştirebilir. Static fonksiyonlar diğer üyeler ile aynı erişim haklarına sahip olmalarına rağmen, static olmayan üye verilere ve fonksiyonlara erişemezler. Çünkü üye bir fonksiyon içinde normalde nesnenin başlangıcına işaret etmesi gereken this işaretçisi, static bir fonksiyon içinde herhangi bir adrese işaret etmez.


..... lar alt çizgi olcak

Son Düzenleme: Eniqma ~ 16 Ağustos 2006 01:57
theironman
16-08-2006, 09:51   |  #2  
theironman avatarı
Genel Denetmen
Teşekkür Sayısı: 63
8,347 mesaj
Kayıt Tarihi:Kayıt: Oca 2004

arkadaşım sağol ancak C++ adlı bir bölümümüz hali hazırda vardı zaten; oraya koysaydın.