Bu Sayfayı Paylaş:

Bilgi/Açıklama

C++'a Giriş

C++ HAKKINDA

C++ dili, C dilindeki çeşitli geliştirmeler sonucunda oluşmuştur. Elbette C dili de zaman içinde gelişmiştir. Ancak bazı eklemelerin C dilinin temel mantığından çok faklı olması nedeniyle dil yavaş yavaş bir dönüşüm yaşamış; en sonunda klasik C ile son eklenenleri ayırmak için yeni özelliklere C++ denmiştir. C dilini geliştirmek için eklenen özellikler dışında C++ diline C dilinin standart kütüphanelerinin, C++ mantığına uygun sürümleri yazılmış ve böylelikle C++ dilinin, hiç C kodu yazmadan tek başına bir dil olarak kullanılabilmesi sağlanmıştır.

Nesneye Yönelik Programlama

C diline önce işlev ve değişkenlerin bir arada tutulduğu sınıf (class) kavramı eklenmiştir. Daha sonra bir sınıfın diğer sınıfın işlev ve değişkenlerini alabilmesini sağlayan kalıtım (inheritance) kavramı gelmiştir. C dili, işlevsel (functional), yani işlevler yazma ve işlevlerin birbirlerini çağırması esasına dayanan bir programlama diliyken; C++ sınıflar yazılması ve sınıfların birbirlerini kullanması ve kalıtması esasına dayanmaktadır. Sınıf, gerçek dünyadaki bir nesnenin veya kavramın cinsine karşılık gelir. O yüzden sınıflarla çalışma tekniğine nesneye yönelik programlama (object-oriented programming) denir. Her sınıfın somut bir üyesine örnek (instance) adı verilir. Bir C++ uygulaması bir sınıftan bir örnek oluşturmak, o örneğin işlevlerini çeşitli parametrelerle çağırmak ve sonuçları almak biçiminde yazılır.

Çeşitli Eklemeler

C++ dili nesneye yönelik programlama dışında, bir sınıfın sabit tiplerle değil de değişik tipler için çalışabilmesini sağlayan şablon (template); bir programda hata çıkması durumunda, hatanın çıktığı işlevde değil de o işlevi doğrudan veya dolaylı olarak çağıran, hataya karşılık bir eylem yapma olanağı olan diğer bir işlevde işlem yapılmasını sağlayan kuraldışılık (exception); göstericiler gibi adreslerle çalışan ancak programcının göstericinin sözdizimi ve aritmetiğiyle uğraşmaktan kurtaran başvuru (reference) gibi yenilikler de içermektedir.

C ile Uyumluluk

C++ dili tamamen yeni bir dil, tamamen yeni bir programlama yaklaşımı içerdiği halde C dilini destekler ve C dilinin temel yapısını içinde barındırır. C ve C++ dili özellikleri bir arada kullanılabilir veya bir yazılımın bir parçası C++ diliyle diğeri C ile yapılabilir. Bazı durumlarda aynı konuda C ile C++ dilinin yaklaşımları farklı olabilir. Yalnızca C dilini destekleyen derleyici ve ortamlarda bazı C++ özellikleri çalışmayabilir. Ancak genellikle hem derleyici hem de geliştirme ortamları hem C hem de C++ dilini desteklemektedir. Hatta C ve C++ tek bir dili gibi C/C++ olarak adlandırılmaktadır. Bir çok program yazarı hangi özelliğin C dilinden hangi özelliğin C++'dan geldiğini bilmeksizin kod yazabilmektedir.

Nesne (Object)

Sınıf (Class)

İçinde değişken (variable) ve işlev (function) barındıran yazılım birimine sınıf (class) denir. Bir sınıfın içindeki değişkene üye değişken (member variable) veya alan (field) adı verilir. Bir sınıfın içindeki işlev de üye işlev (member function) veya yöntem (method) diye adlandırılır. Değişken ve üye dışında bir sınıfta işleç (operator) tanımı da yapılabilir.
Örneğin dikdörtgen diye bir sınıf yapılıp genişlik ve yükseklik diye iki değişken tanımlanabilir. Bu sınıfa, alanı ver ve çevreyi ver diye iki işlev eklenebilir. İki dikdörtgenin bileşim kümesini vermesi için '+' işleci, bir dikdörtgenin diğerinden farkını vermesi için '-' işleci tanımlanabilir.

Örnek (Instance)

Sınıf, soyut ve genel bir kavramdır. Soyut kavramın somut belli bir numunesinden bahsediliyorsa buna örnek (instance) denir. Örneğin dikdörtgen bir sınıftır, A ve B diye iki dikdörtgen tanımlanırsa bunlar birer örnek olur. Çeşitli anlatımlarda nesne (object) sözcüğü hem sınıf için hem de örnek için kullanılabilmekle birlikte genellikle örnek olarak algılanır.

Aduzayı (Namespace)

Bir veya daha fazla sınıfı barındıran gruba aduzayı (namespace) denir. Her sınıfın ait olduğu bir aduzayı olması gerektiği kabul edilir. C++ kütüphaneleri bir veya daha fazla isim uzayına ait sınıflar içerirler. Hiçbir özel kütüphaneye ait olmayan standart sınıflar da std isim uzayına ait kabul edilirler.

Kalıtım (Inheritance)

Bir sınıfın diğer bir sınıfa ait değişken ve işlevleri almasına kalıtım (inheritance) denir. Bu şekilde birden çok sınıfta ortak olan değişken ve işlevler tekrar tekrar yazılmak zorunda kalınmaz. Ortak üyeler bir taban sınıf (base class) adı verilen bir sınıfta tanımlanır ve o taban sınıftan miras alarak oluşturulmuş, istendiği kadar alt sınıf (subclass) yazılabilir. Bir sınıfın birden fazla sınıftan kalıtım yapması çoklu kalıtım (multiple inheritance) denir.

Kaplama (Encapsulation)

Bir sınıfın içinde bazı değişken ve işlevlere, başka sınıf ve işlevlerin erişmesi sınırlanabilir. Bir sınıfın herhangi bir üyesi eğer herkes tarafından erişiliyorsa kamusal (public); yalnızca o sınıf tarafından kullanılması gerekiyorsa özel (private); o sınıf ve kendisini genişleten sınıflar tarafından erişiliyorsa korumalı (protected) olarak belirlenir.

Standart Giriş/Çıkış (I/O)

C++ dilinde konsola metin basmak için iostream (input output stream - girdi çıktı akımı) kütüphanesindeki çeşitli sınıflar kullanılmaktadır. Ekrana yazı basmak için cout sınıfı, ekrandan veri okumak için de cin sınıfı kullanılır. Bu sınıflar << ve >> gibi işleçler içerdiğinden özel kullanım biçimlerine sahiptir. Ancak değişik kullanımları olsa da temelde iostream kütüphanesi stdio kütüphanesindeki işlevlerle aynı işlemleri yapar.

Standart Çıktı

C++'da konsola metin basmak için iostream kütüphanesindeki cout (console output - konsol çıktısı) sınıfı kullanılır. Bu sınıfta çıktı almak için << işleci tanımlanmıştır. Örneğin ekrana 'Hello C++' yazmak için
#include <iostream>
void main(){
	cout<<"Merhaba Godoro";
}
şeklindeki bir kod parçası yazılır. Burada cout sınıfının << işleci çağrılmaktadır. Yeni satıra geçmek için '\n' karakteri
cout<<"Merhaba Godoro\n";
biçiminde kullanılabileceği gibi iostream kütüphanesinde yeni satır karakter için tanımlanmış endl sabiti de kullanılabilir:
cout<<"Merhaba Godoro"<<endl;
Elbette bir değişkenin değerini ekrana basmak için de aynı işleç kullanılabilir:
int number=400;
cout<<number<<endl;
Konsola karakter basmak için cout sınıfının '<<' işleci kullanıldığı zaman biçimlendirme (formatting) karakterleri kullanmaya pek gerek olmaz. Her ne kadar cout kullanarak biçimlendirme yapmak mümkünse de hiçbirini kullanmadan çıktı biçime uygun oluşturulabilir. Örneğin bir değişkenin bir metin içinde geçmesi durumunda printf() ile
printf("Sizin %d lira borcunuz var.\n",number);
şeklinde bir kod yazılırken cout ile
cout<<"Sizin "<<number
	<<" lira borcunuz var."<<endl;
şeklinde bir kod yazılabilir.
Çıktı konularını içeren bütün bir örnek aşağıdaki gibi yapılabilir:
#include <iostream>
using namespace std;
int main(){
	cout<<"Merhaba Godoro"<<endl;
	int number=400;
	cout<<number<<endl;
	cout<<"Sizin "<<number
        <<" lira borcunuz var."<<endl;
	return 0;
}
Ekran çıktısı:
Merhaba Godoro
400
Sizin 400 lira borcunuz var.

Standart Girdi

Ekrandan veri okumak için iostream kütüphanesindeki cin (console input - konsol girdi) sınıfı kullanılır. Okuma işlemini >> işleci gerçekleştirir. Örneğin bir değişkeni ekrandan okumak için
#include <iostream>
void main(){
	int i;
	cin>>i;
}
şeklinde bir kod yazılır. Burada ekrandan okunan değerin i değişkenine atanması sağlanmaktadır. Birden fazla değişken de aynı biçimde okunabilir:
int x,y;
cin>>x>>y;
cout<<"Okunan : "<<x<<" ve "<< y <<endl;
Girdi konularını içeren bütün bir örnek:
#include <iostream>
using namespace std;
int main(){
	int i;
	cout<<"Bir tümsayı gir:";
	cin>>i;
	int x,y;
	cout<<"İki tümsayı gir:\n";
	cin>>x>>y;
   	cout<<"Okunan : "<<x<<" ve "<< y <<endl;
    	return 0;
}
Ekran çıktısı aşağıdaki gibidir. Kullanıcının girdikleri kalın olarak gösterilmiştir.
Bir tümsayı gir:1234
İki tümsayı gir:
56
78
Okunan : 56 ve 78

Standart Aduzayı

Girdi ve çıktı işlemlerine ilişkin çeşitli tanımlamalar içeren iostream sınıfında cout ve cin gibi sınıflar std aduzayına aittirler. Bazı derleyiciler bu isim uzayının adını anmadan da cout ve cin gibi sınıfları kullanmaya izin verir ancak bazı durumlarda bu isim uzayını özellikle belirtmek gerekir. Örneğin kurallara tam uyulması durumunda ekranda bir metin yazan örnek
#include <iostream>
using namespace std;
void main(){
  cout<<"Merhaba Godoro";
}
şeklinde yazılmalıdır

Varsayılan Değer (Default Value)

C++ dilinde bir yöntemin birden çok sürümü, yüklenme (overloading) yöntemiyle gerçekleştirilebilir. Ancak kimi durumlarda bir yöntem ötekinin, yalnızca parametrelerinden bir bölümünün belli bir değer almış biçimi olabilir. Bu durumda çok sayıda yöntem yazılması yerine varsayılan değer (default value) adı verilen özellik kullanılır. Buna göre bir işlev
void myfunction(int myparameter=1234){
}
biçiminde, parametrelere belli değerler verilerek tanımlanabilir. Böyle bir işlevin çağrılışı
myfunction(5678);
biçiminde, parametre değeri verilerek yapılabildiği gibi
myfunction();
biçiminde, parametre değeri vermeden de yapılabilir. İkinci durumda parametrenin değeri varsayılan, örnekteki 1234 değerine eşit olur. Bu biçimde parametre girişini isteğe bağlı yaparak geliştiriciye kolaylık sağlanmış olur.
Parametrelerine varsayılan değerler verilmiş bir işlev ve bu işlevin kullanımına ilişkin bütün bir örnek aşağıdaki gibi yapılabilir:
#include <iostream>
using namespace std;
void f(int x=1,int y=1,int z=1){
	cout<<x<<" , "<<y<<" , "<<z<<"\n";
}
int main(){
	f(3,4,5);
	f(3,4);
	f(3);
	f();
	return 0;
}
Yukarıda üç parametre alan bir işlev, her bir parametreye varsayılan değer olarak 1 verilmek yoluyla tanımlanmıştır. Ana işlevde işlev çağırmanın üç parametrelisinden, hiç parametre kullanamayan sürümüne kadar tüm olasılıklar gösterilmiştir.
Ekran çıktısı:
3 , 4 , 5
3 , 4 , 1
3 , 1 , 1
1 , 1 , 1

Sınıf (Class) Kavramı

Sınıf Kullanımı

Sınıf, değişken ve işlevlerden oluşan bir bütündür. Örneğin bir dikdörtgen (rectangle) sınıfı, içinde genişlik (width) ve yükselik (height) biçiminde iki üye değişken (member variable) ya da alan (field); alan (area) ve çevre (perimeter) hesaplamak iki üye işlev (member function) ya da yöntem (method) olacak biçiminde yazılmak istenirse
class rectangle{
public :
	double width;
	double height;
	double get_area();
	double get_perimeter();
};
şeklinde bir bildirim yapılır. Burada width ve height alanları ve get_area() ve get_perimeter() işlevleri bildirilmektedir. Bu işlevlerin içi sınıf bildiriminden ayrı bir yerde
double rectangle::get_area(){
	return width*height;
}
double rectangle::get_perimeter(){
	return 2*(width+height);
} 
biçiminde yapılır. Burada iki adet iki nokta üst üste ('::') simgesi sınıf üyesi (class member) işlecidir. Sınıfı ismi ve erişim işleci dışında işlev tanımı C dilindeki tanımla aynı şekilde yapılmaktadır. Tanımlanan sınıfa ait bir örnek oluşturmak ve kullanmak için
rectangle r;
r.width=4;
r.height=5;
double a=r.get_area();
cout<<"Alan : "<<a<<endl;
double p=r.get_perimeter();
cout<<"Çevre : "<<p<<endl;
şeklinde bir kod parçası yazılabilir. Burada rectangle sınıfına ait r adlı bir örnek bir değişken olarak tanımlanmakta, width ve height alanları atanmakta ve get_area() ve get_perimter() yöntemleri çağrılarak sırasıyla alan ve çevre hesaplanmaktadır.
Örneğin tümü aşağıdaki gibidir:
#include <iostream>
using namespace std;
class rectangle{
public :
	double width;
	double height;
	double get_area();
	double get_perimeter();
};
double rectangle::get_area(){
	return width*height;
}
double rectangle::get_perimeter(){
	return 2*(width+height);
}
int main(){
	rectangle r;
	r.width=4;
	r.height=5;
	double a=r.get_area();
	cout<<"Alan : "<<a<<"\n";
	double p=r.get_perimeter();
	cout<<"Çevre : "<<p<<"\n";
	return 0;
}
Ekran çıktısı:
Alan : 20
Çevre : 18

Sınıf Tanımında Örnekler

Bir sınıfın tanımının ardında o sınıfa ait örnekler oluşturulabilir. Örneğin
class rectangle{
public :
	double width;
	double height;
	double get_area();
	double get_perimeter();
}a,b,c;
biçimindeki kodda sınıf tanımın kapatan kıvırcık ayraçla, demeci sonlandıran noktalı virgül arasında belirtilen değişkenler, bu sınıfa ait örneklerdir. Burada a, b ve c adlı değişkenler, birer dikdörtgen örneği oluşturmaktadırlar.

Kaplama (Encapsulation)

Sınıflarla kaplama (encapsulation) işlemi uygulanabilir. Buna göre sınıfların bazı üyeleri özel (private) tutularak dışarıdan erişim engellenebilir. Aksi söylenmedikçe üyeler özel sayılır. O yüzden kamusal (public) üyeleri 'public :' şeklinde belirtmek gerekir. Örneğin kare (square) diye bir sınıf yapıp içinde özel bir kenar (edge) alanı eklemek için
class square{
	double edge;
public :
	void set_edge(double e);
	double get_edge();
	double get_area();
};
void square::set_edge(double e){
	if(e>=0){
		edge=e;
	}else{
		edge=-e;
	}
}
double square::get_edge(){
	return edge;
}
double square::get_area(){
	return edge*edge;
}
biçiminde bir sınıf yazılabilir. Burada edge özelliği özel tutulmuş, ancak erişim için kamusal get_edge() ve set_edge() yöntemleri yazılmıştır.
Alanın özel tutulup erişim için işlevlerin kamusal tutulması kaplama mantığına aykırı değildir. Çünkü bu durum, alan veya yöntemi kamusal tutmaktan farklıdır. Zira alan yine koruma altındadır. Örnekteki set_edge() yöntemi verilen değerin eksi işaretli olması durumunda işareti tersine çevirmekte ve alanın değerinin eksi olmasını engellemiş olmaktadır. Eğer alanın kendisi kamusal olsaydı böyle bir koruma sağlanamayacaktı. Kare sınıfın kullanımına örnek olarak
square s;
s.set_edge(3); 
double e=s.get_edge();
cout<<"Edge : "<<e<<"\n";
double a=s.get_area();
cout<<"Area : "<<a<<"\n";
biçiminde bir kod yazılabilir. Burada square sınıfına ait s adlı bir örnek değişken tanımlanmakta ve onun alanı hesaplanıp ekrana basılmaktadır. Buradaki square sınıfının
s.edge=3;
s.edge=-3;
biçimde doğrudan edge alanına erişim yapılmaya çalışılırsa derleyici alanın özel olduğu gerekçesiyle hata verir. Öte yandan
s.set_edge(-3);
şeklinde bir kod parçası hem derleyici açısından sorun oluşturmaz hem de kenarın eksi olması yöntem içinde engellendiği için eksi değer sorunu oluşmaz.
Anahtar sözcük olarak private kullanımı zorunlu olmasa da üyelerin özel olduğunu vurgulamak için bazı programcılar tarafından yazılır. Örneğin
class square{
private :
	double edge;
public :
	void set_edge(double e);
	double get_edge();
	double get_area();
};
Kaplama işlemlerini içeren bütün bir örnek aşağıdaki gibidir:
#include <iostream>
using namespace std;
class square{
	double edge;
public :
	void set_edge(double e);
	double get_edge();
	double get_area();
};
void square::set_edge(double e){
	edge=e;
}
double square::get_edge(){
	return edge;
}
double square::get_area(){
	return edge*edge;
}
int main(){
	square s;
	// s.edge=3; // Yanlış! Alan özel!
	s.set_edge(3);
	double e=s.get_edge();
	cout<<"Ayrıt : "<<e<<"\n";
	double a=s.get_area();
	cout<<"Alan : "<<a<<"\n";
	return 0;
}
Ekran çıktısı:
Ayrıt : 3
Alan : 9

Arkadaş (Friend)

Bir sınıfın özel üyelerine başka bir sınıfın veya başka bir işlevin erişebilmesi için friend (arkadaş) anahtar sözcüğü kullanılır. Bir sınıfın içinde arkadaş olarak tanıtılmış işlev ve sınıflar, o sınıfın özel üyelerine de herhangi bir sınırlama olmadan erişebilirler. Örneğin
class my_host_class{
private :
	int x;
public :
	void set_x(int xx){
		x=xx;
	}
	int get_x(){
		return x;
	}
	friend my_host_class  	my_guest_function(my_host_class host);
	friend class my_guest_class;	
};
biçiminde bir sınıf tanımında my_guest_function işlevi ve my_guest_class sınıfları bu sınıfın 'arkadaşı' olarak bildirilmiştir. Burada arkadaş işlevin tanımı işlevin kendi tanımının başına friend sözcüğü eklenmesiyle oluşturulmuştur. Sınıfların arkadaş olarak tanımlanması için sınıf adının önünde friend class şeklinde anahtar sözcükler bulunmaktadır. Arkadaş işlev, dost olmasıyla ilgili herhangi özel bir özel ifade olmadan
my_host_class my_guest_function(
    my_host_class host)
{
	host.x=2;
	return host;
}
biçiminde tanımlanabilir. Burada my_host_class sınıfına ait host parametresinin x alanı özel olmasına rağmen arkadaş işlev içinde değiştirilebilmektedir. Paralel bir biçimde arkadaş sınıf tanımı arkadaşlıkla ilgili herhangi bir ifade içermeden
class my_guest_class{
public :
	my_host_class my_guest_method(
         my_host_class host)
     {
		host.x=3;
		return host;
	}
};
biçiminde tanımlanabilir. Burada my_guest_method yöntemi my_host_class sınıfına ait host örneğinin x alanına özel olmasına rağmen ait olduğu sınıfın parametredeki sınıfta arkadaş olarak tanımlanması nedeniyle erişebilmektedir. Arkadaş işlev ve sınıfların kullanımı
my_host_class host;
host.set_x(1);
cout<<"Arkadaş işlevlerden önce, x : "
        <<host.get_x()<<endl;
host=my_guest_function(host);
cout<<"Arkadaş işlevlerden sonra, x : "
        <<host.get_x()<<endl;
my_guest_class guest;
host=guest.my_guest_method(host);
cout<<"Konuk sınıftan sonra, x : "
        <<host.get_x()<<endl;
biçiminde olabilir. Burda my_host_class sınıfının host adlı örneğinin değeri belli bir değerdeyken arkadaş işlev ve sınıf tarafından değiştirilebilmektedir.
Arkadaş işlemlerini içeren örneğin bütünü:
#include <iostream>
using namespace std;
class my_host_class{
private :
	int x;
public :
	void set_x(int xx){
		x=xx;
	}
	int get_x(){
		return x;
	}
	friend my_host_class 
       my_guest_function(
         my_host_class host);
	friend class my_guest_class;
};
my_host_class my_guest_function(
    my_host_class host)
{
	host.x=2;
	return host;
}
class my_guest_class{
public :
	my_host_class my_guest_method(
         my_host_class host)
     {
		host.x=3;
		return host;
	}
};
int main(){
     my_host_class host;
	host.set_x(1);
	cout<<"Arkadaş işlevlerden önce, x : "
         <<host.get_x()<<endl;
	host=my_guest_function(host);
	cout<<"Arkadaş işlevlerden sonra, x : "
         <<host.get_x()<<endl;
	my_guest_class guest;
	host=guest.my_guest_method(host);
	cout<<"Konuk sınıftan sonra, x : "
         <<host.get_x()<<endl;
    return 0;
}
Ekran çıktısı:
Arkadaş işlevlerden önce, x : 1
Arkadaş işlevlerden sonra, x : 2
Konuk sınıftan sonra, x : 3

Dize İçi (Inline) Bildirim

Bir sınıfın yöntemleri sınıf bildiriminin dışında :: ile tanımlama yerine; sınıfın içinde, sınıfın bildirildiği ana bölümde tanımlanabilir. Bu biçimde tanımlamaya dize içi (inline) denir. Ancak bu biçimde tanımlama yalnızca kısa, değişken atamalarından veya küçük bazı işlemlerden oluşan kodlar için yapılır. Zira dizeiçi tanımlama C dilindeki makrolar gibi, derleme aşamasında çağrıldıkları yere aynen kopyalanan kod parçalarıdır. Dizeiçi yöntemleri kullanımı dizeiçi olmayan yani dize dışı (out of line) yöntemlerinkiyle aynıdır.
Örnek olarak daire (circle) diye yarıçap (radius) alanını içeren bir sınıfın erişim yöntemleri, alan ve çevre hesaplama yöntemleri
class circle{
	double radius;
public :
	void set_radius(double r){
		radius=r;
	}
	double get_radius(){
		return radius;
	}
	double get_area(){	
		return 3.14*radius*radius;
	}
	double get_perimeter(){	
		return 2*3.14*radius;
	}
};
şeklinde tanımlanabilir. Bu sınıftaki yöntemler dize içi olmayan işlevlerdeki gibi
circle c;
c.set_radius(3);
cout<<"Yarıçap : "<<c.get_radius()<<endl;
cout<<"Alan : "<< c.get_area()<<endl;
cout<<"Çevre : "<< c.get_perimeter()<<endl;
biçiminde çağrılabilir.
Sınıfın dışında tanımlanan bir işlev de dizeiçi olabilir. Bunun için işlevin başına inline sözcüğü konmalıdır. Örneğin
inline double rectangle::get_area(){ 
  return 3.14*radius*radius;
}
Dizeiçi konusunu içeren örneğin bütünü aşağıdaki gibidir:
#include <iostream>
using namespace std;
class circle
{
    double radius;
public :
    void set_radius(double r){
        radius=r;
    }
    double get_radius(){
        return radius;
    }
    double get_area(){
        return 3.14*radius*radius;
    }
    double get_perimeter(){
        return 2*3.14*radius;
    }
};
int main(){
    circle c;
    c.set_radius(3);
    cout<<"Yarıçap : "<<c.get_radius()<<endl;
    cout<<"Alan : "<< c.get_area()<<endl;
    cout<<"Çevre : "<< c.get_perimeter()<<endl;
    return 0;
}
Ekran çıktısı:
Yarıçap : 3
Alan : 28.26
Çevre : 18.84

Yapıcı (Constructor) ve Yıkıcı (Destructor)

Bir sınıfın örneği oluşturulurken yapılması gerekenler yapıcı (constructor) adı verilen özel bir yöntemle belirtilir. Yapıcı, sınıfla aynı adı taşıyan, sonuç döndürmeyen bir işlev gibi bildirilir. Kurucularda genellikle bellekte yer ayırma, dizilerin boyutlarını belirleme gibi işlemler gerçekleştirilir. Bir sınıfa ait örnek kullanım dışı olduğunda bellekten silinirken yapılması gerekenler de yıkıcı (destructor) adı verilen özel yöntemle bildirilir. Yıkıcılarda bellekte ayrılan alanların serbest bırakılması gibi işlemler gerçekleştirilir. Kurucu yöntem, sınıf isminin başına tilde ('~') konarak tanımlanır.
Örneğin, aldığı parametreye göre bellekte yer ayıran devingen dizi (dynamic array) işlevi gören bir sınıf
class dynamic_array {
	int length;
	double *data;
public :
	dynamic_array(int n);
	~dynamic_array();
	double get(int i);
	void set(int i,double d);
};
dynamic_array::dynamic_array(int n){
	length=n;
	data=(double *)malloc(
         length*sizeof(double));
	cout<<"Kuruldu.."<<"\n";
}
dynamic_array::~dynamic_array(){
	free(data);
	cout<<"Yıkıldı.."<<"\n";
}
void dynamic_array::set(int i,double d){
	data[i]=d;
}
double dynamic_array::get(int i){
	return data[i];
}
biçiminde bildirilebilir. Kurucu işlevde data dizisi için bellek ayrılması işlemi yapılmaktadır. Buna karşılık bellek alanının serbest bırakılması yıkıcı işlevde belirtilmektedir. Bu sınıfın kullanımı
dynamic_array a(4);
a.set(1,9);
cout<<"Değer a[1] : "<<a.get(1)<<"\n";
biçiminde bir kod parçasıyla yapılabilir. Burada set yöntemiyle dizinin 2. elemanının değer 9 olarak atanmakta; daha sonra bu değer get yöntemiyle alınıp ekrana basılmaktadır. Bu sınıf oluşturulurken kurucu ve yok edilirken de yıkıcı yöntemlerin çalıştığı ekrana basılan ifadelerden anlaşılabilir.

Birden Çok Kurucu

Bir sınıfa ait farklı tipte parametreler alan birden çok kurucu olabilir. Örneğin dynamic_array sınıfı iki değer vererek iki elemanlı oluşturan bir kurucu
dynamic_array(int x,int y);
biçiminde sınıf içinde bildirilip 
dynamic_array::dynamic_array(int x,int y){
	length=2;
	data=(double *)malloc(
         length*sizeof(double));
	data[0]=x;
	data[1]=y;
	cout<<"Kuruldu.."<<"\n";
}
biçiminde tanımlanabilir. Bu örnek iki elemanlı diziyi oluşturmakta ve ilk iki elemanını gelen parametrelerle atamaktadır.

Kurucunun Kurucuyu Çağırması

Bir kurucu diğer bir kurucuyu çağırabilir. Bu şekilde bir kurucuda yapılan işlerin diğerinde tekrarlanması engellenmiş olur. Genellikle asıl işlemi yapan bir kurucu yapılır ve diğer kurucular asıl işlemin yanı sıra bazı faydalı ek işlemler yaparlar. Örnek olarak iç elemanı parametre olarak alıp diziyi oluşturulan bir kurucu
dynamic_array(int x,int y,int z);
biçiminde bildirilip 
dynamic_array::dynamic_array(int x,int y,int z)
	dynamic_array(3);
{
	data[0]=x;
	data[1]=y;
	data[2]=z;
}
biçiminde tanımlanabilir. Burada kurucunun ilk satırında tek parametre alan ve aldığı parametre kadar diziye yer ayıran kurucu çağrılmaktadır. Bu kurucu bu işleme ek olarak yalnızca ilk üç elemanı atamaktadır.
Kurucu ve yıkıcı içeren örneğin tümü:
#include <iostream>
#include <cstdlib>
using namespace std;
class dynamic_array {
	int length;
	double *data;
public :
	dynamic_array(int n);
	dynamic_array(double x,double y);
	dynamic_array(double x,double y,double z);
	~dynamic_array();
	double get(int i);
	void set(int i,double d);
};
dynamic_array::dynamic_array(int n){
	length=n;
	data=(double *)malloc(
         length*sizeof(double));
	cout<<"Kuruldu.."<<"\n";
}
dynamic_array::dynamic_array(double x,double y){
	length=2;
	data=(double *)malloc(
         length*sizeof(double));
	data[0]=x;
	data[1]=y;
	cout<<"Kuruldu.."<<"\n";
}
dynamic_array::dynamic_array(
    double x,double y,double z)
  :dynamic_array(3)
{
	data[0]=x;
	data[1]=y;
	data[2]=z;
}
dynamic_array::~dynamic_array(){
	free(data);
	cout<<"Yıkıldı.."<<"\n";
}
void dynamic_array::set(int i,double d){
	data[i]=d;
}
double dynamic_array::get(int i){
	return data[i];
}
int main(){
    dynamic_array a1(4);
    a1.set(1,9);
    cout<<"Değer : a1[1] : "<<a1.get(1)<<"\n";
    dynamic_array a2(5,6);
    cout<<"Değer : a2[1] : "<<a2.get(1)<<"\n";
    dynamic_array a3(7,8,9);
    cout<<"Değer : a3[1] : "<<a3.get(1)<<"\n";
    return 0;
}
Ekran çıktısı:
Kuruldu..
Değer : a1[1] : 9
Kuruldu..
Değer : a2[1] : 6
Kuruldu..
Değer : a3[1] : 8
Yıkıldı..
Yıkıldı..
Yıkıldı..

Kurucuda Alanların İlklenmesi

Kurucuda alınan değerlerle bir sınıfın alanlarının değerlerine atama yapmak için ilkleme dizelgesi (initialization list) adı verilen bir yapı kullanılabilir. Buna göre
rectangle(int w,int h){
	width=w;
	height=h;
}
yerine
myclass(int w,int h):width(x), height(h){
}
biçiminde bir ilkleme yapılabilir. Bu tür kullanımda alanların ilkleme listesindeki sırası ile bildirim sırası aynı olmalıdır.

Aduzayı (Namespace)

C++ dilinde aduzayı (namespace), bir değişkenin, bir işlevin veya bir sınıfın ait olduğu grubu temsil eder. Normal şartlarda aynı isimde değişken, işlev ve sınıf tanımlanamaz. Ancak ayrı isim uzaylarında aynı ismi farklı biçimlerde kullanmak mümkündür. Bu durumda değişkenlere erişim için '::' erişim işleci kullanılır.
Aynı ismi taşıyan iki değişken iki ayrı aduzayında
namespace space_one{
	int my_variable=3;
}
namespace space_two{
	double my_variable=3.5;
}
biçiminde tanımlanabilir. Bu değişkenlere space_one::my_variable ve space_two::my_variable biçiminde erişilir :
void main(){
	cout<<"Uzay Bir - Değişken : "
         <<space_one::my_variable<<endl;
	cout<<"Uzay İki - Değişken : "
         <<space_two::my_variable<<endl;
}
Buradaki değişkenler aynı ismi taşımalarına rağmen farklı türlerde tanımlanmıştır. Ayrı ad uzaylarında oldukları için derleyici bu iki değişkeni birbirine karıştırmaz. Ancak ad uzayının değişken isminden önce belirtilmesi gerekir.
Bir ad uzayından çok sayıda değişken işlev veya sınıf kullanılacaksa kodun başında using (kullanıyor) yapısıyla aduzayı bir kez tanıtılır ve bir daha aduzayını önek olarak kullanmak gerekmez. Örnek:
using namespace space_one;
void main(){
	cout<<"Uzay Bir - Değişken : "
         <<my_variable<<endl;
}
Ad uzaylarında işlevler de tanımlanabilir. Örneğin
namespace space_one{
	int my_function(int x,int y){
		return x+y;
	}
}
namespace space_two{
	double my_function(double x,double y){
		return x*y;
	}
}
biçiminde iki aduzayında iki işlev aynı isimde tanımlanabilir. Bunlar
cout<<"Uzay Bir - İşlev : "
    <<space_one::my_function(3,4)<<endl;
cout<<"Uzay İki - İşlev : "
    <<space_two::my_function(3,4)<<endl;
biçiminde aduzayı önekiyle veya using sözcüğüyle ad uzayı öneki olmadan kullanılabilir.
Ad uzaylarında sınıflar da tanımlanabilir. Örneğin
namespace space_one{
	class my_class{
	public:
		int my_int;
		int my_method(int my_parameter){
			return my_int-my_parameter;
		}
	};
}
namespace space_two{
	class my_class{
	public:
		double my_double;
		double my_method(double my_parameter){
			return my_double/my_parameter;
		}	
	};
}
biçiminde iki ad uzayında iki sınıf aynı isimle tanımlanabilir. Kullanımları
space_one::my_class object_one;
object_one.my_int=8;
cout<<"Uzay Bir - Tarla : "
    <<object_one.my_int<<endl;
cout<<"Uzay Bir - Yöntem : "
    <<object_one.my_method(2)<<endl;
space_two::my_class object_two;
object_two.my_double=8;
cout<<"Uzay İki - Tarla : "
    <<object_two.my_double<<endl;
cout<<"Uzay İki - Yöntem : "
    <<object_two.my_method(2)<<endl;
biçimindedir. Yalnızca örnek tanımında sınıfın öneki olarak aduzayı (spaceone::my_class biçiminde) kullanılır, değişkeni kullanırken (object_one.my_int biçiminde olduğu gibi) aduzayı kullanılmaz.
Aduzayıyla ilgili konuları içeren bütün bir örnek aşağıdaki gibi yapılabilir:
#include <iostream>
using namespace std;
namespace space_one{
	int my_variable=3;
	int my_function(int x,int y){
		return x+y;
	}
	class my_class{
	public:
		int my_int;
		int my_method(int my_parameter){
			return my_int-my_parameter;
		}
	};
}
namespace space_two{
	double my_variable=3.5;
	double my_function(double x,double y){
		return x*y;
	}
	class my_class{
	public:
		double my_double;
		double my_method(double my_parameter){
			return my_double/my_parameter;
		}
	};
}
using namespace space_one;
int main(){
     cout<<"Uzay Bir - Değişken : "
         	<<my_variable<<endl;
	cout<<"Uzay İki - Değişken : "
         <<space_two::my_variable<<endl;
    	cout<<"Uzay Bir - İşlev : "
	    	<<my_function(3,4)<<endl;
     cout<<"Uzay İki - İşlev : "
	    	<<space_two::my_function(3,4)<<endl;
     my_class object_one;
     object_one.my_int=8;
     cout<<"Uzay Bir - Tarla : "
        	<<object_one.my_int<<endl;
     cout<<"Uzay Bir - Yöntem : "
        	<<object_one.my_method(2)<<endl;
     space_two::my_class object_two;
     object_two.my_double=8;
     cout<<"Uzay İki - Tarla : "
        	<<object_two.my_double<<endl;
     cout<<"Uzay İki - Yöntem : "
     	<<object_two.my_method(2)<<endl;
     return 0;
}
Ekran çıktısı:
Uzay Bir - Değişken : 3
Uzay İki - Değişken : 3.5
Uzay Bir - İşlev : 7
Uzay İki - İşlev : 12
Uzay Bir - Tarla : 8
Uzay Bir - Yöntem : 6
Uzay İki - Tarla : 8
Uzay İki - Yöntem : 4

Bilgi/Açıklama

Kalıtım (Inheritance)

Kalıtım Kavramı

Bir sınıfın, diğer bir sınıftaki alan ve işlevlerini almasına kalıtım (inheritance) denir. Bu şekilde birden çok sınıfın ortak özellikleri bir taban sınıfta toplanır ve bu sınıftan, daha özel durumlar için kullanılan sınıflar türetilir. Örneğin 'bilgisayar' bir taban sınıfı 'masaüstü' ve 'dizüstü' ondan türetilmiş sınıflar olabilir. Bir sınıfın türetildiği sınıfa ata-ana (parent), taban (base) veya üst (super) sınıf gibi isimler verilirken; türetilen sınıf için çocuk (child), türemiş (derived) veya alt (sub) gibi adlar kullanılır. Bir sınıfın türetildiği sınıf da başka bir sınıftan türetilmiş olabilir. Örneğin 'masaüstü' ve 'dizüstü' bilgisayarların türetildiği 'bilgisayar' sınıfı da elektronik 'aygıt' sınıfından türetilmiş olabilir.
Kalıtım özelliğinin C++ dilinde bulunmasının en önemli nedeni; birbirine benzeyen, ortak noktaları çok olan bir çok sınıfta, aynı alanların ve yöntemlerin tekrar tekrar tanımlanmasından kurtulunması ve daha az kod yazarak yazılım geliştirilebilmesine olanak sağlanmasıdır. Ancak kalıtım yalnızca daha az kod yazmak için ortaya atılmış bir kavram değildir. Bir kod parçası, sınıfların ortak özelliklerini tanımlandığı bir üst sınıf için yazılır ve daha sonra üst sınıftan türeyen alt sınıfların, düzende kendinden olarak tanımlanması sağlanır. Örneğin bir bilgisayarı açan, bir işlem yapan ve sonra da kapatan bir süreç, bilgisayar için yazıldığında masaüstü için de dizüstü için de geçerli olur. Daha sonra 'avuç içi' diye bir sınıf bilgisayar sınıfından türetilirse aynı işlemler onun için de geçerli olur.
Bir veya daha fazla sınıfın türetildiği, ancak tek başına somut bir anlam içermeyen sınıflara soyut (abstract) sınıflar denir. Üst sınıflarda tanımlanan işlevler alt sınıfta yeniden tanımlanabilir. Buna ezme (override) adı verilir. Üst sınıfın, ezilmesine olanak verilen yöntemlerine sanal (virtual) denir. Soyut sınıfların bazı yöntemleri bildirilip tanımlanmayabilir. Yani üst sınıfta bir yöntemin yalnızca adı, giriş parametreleri ve dönüş tipi bildirilir. Alt sınıflarda bu yöntemlerin içi, yani kod bloğu yazılır. Üst sınıfta yalnızca bildirimi olan, alt sınıfların içini doldurduğu işlevlere arı sanal (pure virtual) işlevler denir. Kalıtımla birlikte gelen bir başka konu da çok biçimlilik (polymorphism) kavramıdır. Çok biçimlilik, bir işlevin üst sınıfta aynı biçimde bildirilip alt sınıflarda farklı biçimlerde gerçekleştirilmesi ve bu sınıfları kullanan kodların her sınıfın ayrı gerçekleştirmeleri ile ilgilenmeden standart olarak, aynı biçimde erişmeleridir.

Kaplama

Kaplama Sözcükleri

Bir sınıfın üye değişken ve işlevleri ya özel (private), ya kamusal (public) ya de korumalı (protected) olabilir. Bir sınıftaki özel üyeler yalnızca o sınıf tarafından erişilir, kamusal üyeler her yerden erişilebilir. Bir sınıfın korumalı üyeleri ise sınıfın içinden ve o sınıftan türetilen sınıflar tarafından erişilebilir.

Özel ve Kamusal Kalıtım

Bir sınıfın diğerinden türetilmesi durumunda üst sınıfın özel, korumalı ve kamusal üyelerine alt sınıf için özel mi korumalı mı kamusal mı olacağını belirlemek için türetmenin özel ve kamusal olması söz konusudur. Bir sınıfın diğerinden türetilmesi özel (private) olarak yapılırsa üst sınıfın üyelere özel de olsalar, korumalı veya kamusal da olsalar alt sınıf için özel kabul edilir. Eğer türetme kamusal (public) yapılırsa üst sınıfta gizleme düzeyi neyse alt sınıfta da o olur. Yani üst sınıfta özel olan alt sınıfta da özeldir, korumalı olan alt sınıfta da korumalıdır, kamusal olan alt sınıfta da kamusaldır.

Türetme (Derivation)

Bir sınıf diğer bir sınıftan türetildiği zaman, başka bir deyişle sınıflar arasında türetme (derivation) ilişkisi olduğunda, o sınıfın bütün üyelerine sahip olur. Örnek olarak 'kuş' (bird) diye bir üst sınıf ve bu sınıftan türetilmiş 'güvercin' diye bir sınıf yapılmak istenirse, ismini gösteren bir alan ve uçmasını sağlayan bir yöntem içeren kuş sınıfı
class bird{
public:
	char *name;
	void fly(){
		cout<<name<<" uçuyor"<<endl;
	}
};
biçiminde yazılabilir. Bundan kamusal olarak türetilen bir güvercin sınıfı
class pigeon : public bird{
	
};
biçiminde yazılabilir. Burada pigeon sınıfı bird sınıfından kamusal olarak türetilmiştir, yani ondaki bütün üyeleri almaktadır. Bu pigeon sınıfını kullanırken kendisinden tanımlı olmayan, üst sınıfı bird sınıfından aldığı alan ve işlevleri kullanılabilir:
pigeon p;
p.name="Ak Güvercin";
p.fly();
Görüldüğü gibi name alanı ve fly() yöntemi, pigeon sınıfında tanımlı olmadığı halde, bird sınıfından türetildiği için pigeon sınıfının üyeleri olarak kullanılabilmektedir. Bir sınıfa ait bir alan veya yöntem kullanıldığı zaman derleyici öncellikle üyeyi belirtilen sınıfta arar; orada bulamazsa türetildiği bir üst sınıfta arar, orada da bulamazsa daha üstünde, nihayet en üstteki sınıfta arar. Burada kalıtım kamusal olmayıp özel olsaydı, pigeon sınıfı içinde herhangi bir yöntemde kalıtılan üyeler kullanılabilirdi ancak dışarıdan bir kod parçası bunlara erişemezdi.
Bir sınıftan bir çok sınıf türetilebilir. Örneğin bird sınıfından pigeon dışında bir falcon (doğan) sınıfı da türetilebilir :
class falcon : public bird{
};
Buradaki falcon sınıfı da üst sınıfı bird sınıfının üyelerine sahip olmuş bulunmaktadır:
falcon f;
f.name="Kara Doğan";
f.fly();

Ezme(Overriding)

Bir sınıf, türetildiği sınıftan aldığı bazı yöntemlere aynen sahip olabilir. Ancak bazı durumlarda alt sınıf üst sınıfın bir yöntemini yeniden yazması gerekebilir. Buna ezme (override) denir. Örneğin pigeon sınıfı türetildiği bird sınıfındaki fly() yöntemini
class pigeon : public bird{
public :
	void fly(){
		cout<<name<<" uçuyor"<<endl;
		cout<<" güzelce"<<endl;
	}		
};
biçiminde ezebilir. Bu durumda bu yöntemi çağıran kodda herhangi bir değişiklik olmaz. Yani
pigeon p;
p.name="Ak Güvercin";
p.fly();
şeklindeki kop parçasında fly() yöntemi, ezme olmaması durumunda bird sınıfındaki fly() yöntemini çağırırken, ezme durumunda pigeon sınıfındaki fly() yöntemini çağırır.

Ezmede Üst Sınıfın Yöntemini Kullanma

Bazı durumlarda alt sınıf üstündeki yöntemi ezmek isterken üst sınıfın yönteminin de çalışmasını isteyebilir. Bu durum alt sınıfın üst sınıftaki yöntem çağrılmadan bazı denetimler yapması veya alt sınıfın üst sınıftaki işleve bazı eklemeler yapması hallerinde ortaya çıkar. Örneğin falcon sınıfı bird sınıfının fly() yöntemini hem ezer hem de kullanırsa
class falcon : public bird{
public :
	void fly(){
		bird::fly();
		cout<<"  yüksekte"<<endl;
	}	
};
biçiminde bir kod yazılır. Burada üst sınıfın yönteminden bahsedildiğini göstermek için bird::fly() denmektedir. Eğer işlevin başındaki sınıf konmazsa
void fly(){
	fly();
	cout<<" yüksekte"<<endl;
}
şeklinde bir kod yazılır, bu da üst sınıfın yöntemini değil kendisini, (recursive) bir biçimde yineleyen çağırır. Derlerken sorun çıkmaz ama kod çalışırken sonsuza kadar kendisini çağırmaya çalışır ve en sonunda bellek yetersizliği nedeniyle program kilitlenir. Kimi derleyiciler bu sorunu anlayıp yanlışlık bildirimi yaparlar.

Alt Sınıfla Üst Sınıf Bildirimi

Bir alt sınıf aynı zamanda üst sınıfın bütün özelliklerini taşıdığı için, alt sınıfa ait bir örneğe tür olarak üst sınıf bildirilebilir. Örneğin
pigeon p;
bird b=p;
b.name="Taban Güvercin";
b.fly();
Bu sınıflardan pigeon sınıfı bird sınıfından türediği için derleyici açısından bir hata oluşmaz. Ancak bu durumda fly() işlevi bird sınıfındaki işlevi çağırır, pigeon sınıfındakini değil.

Kalıtımda Göstericiler (Pointers in Inheritance)

C++ dilinde gösterici (pointer) özelliği sınıflar için kullanıldığında kalıtım kuralları geçerlidir. Yani bir sınıfa ait göstericiyle üst sınıftan alınan üyelere erişim yapılabilir. Örneğin pigeon sınıfına ait bir gösterici
pigeon *pp;
pp=new pigeon();
pp->name="Gösterici Güvercin";
pp->fly();
biçiminde kullanılabilir. Üst sınıflara ait göstericiler alt sınıfları göstermek için kullanılabilir. Örneğin
bird *bp;
bp=new pigeon();
bp->name="Taban Gösterici Güvercin";
bp->fly();
biçimindeki kod parçasında göstericinin tipi bird olarak bildiriliyor ancak örnek pigeon türünde oluşturuluyor.

Sanal Yıkıcı (Virtual Destructor)

Kurucular genellikle sanal bırakılmaz. Çünkü alt sınıfın kurucuları üst sınıfınkini çoktan ezmiş sayılır. Alt sınıfın kurucusu çağrıldığında üst sınıfın da kurucusu kendinden çağrılır. Öte yandan yıkıcıların sanal olarak tanımlanması çoğu kez gerekli olur. Çünkü tersi durumda alt sınıfın yıkıcısı çağrıldığında üst sınıfın yıkıcısı çağrılmaz. Üst sınıfta bir takım kaynakların salındığı, gerekli temizliklerin yapıldığı koşullarda bu durum bir sakınca oluşturabilir. Bu nedenle sanal yıkıcı (virtual destructor) tanımlamak yararlıdır. Örnek:
class BaseClass
{
public:
    BaseClass();
    virtual ~BaseClass();
}

Sanal (Virtual) İşlevler

Bir alt sınıf üst sınıfın bir işlevini ezdiği zaman alt sınıftan oluşan örneklerde ezen işlev geçerli hale gelir. Ancak üst sınıfa ait göstericiler alt sınıflar için kullanıldığında üst sınıftaki işlev geçerli olur. Bu durumu değiştirmek için, yani göstericinin türü alt sınıf olmasına rağmen çağrılan işlevin örnek oluşturulan türdeki alt sınıfa ait olmasını sağlamak için üst sınıfın işlevi virtual (sanal) olarak işaretlenir. Örneğin bird sınıfındaki fly() işlevi
class bird{
public:
	char *name;
	virtual void fly(){
		cout<<name<<" is flying";
	}
};
biçimindeki kodda sanal olarak işaretlenir. Alt sınıfta sanal işlevler için herhangi bir işlem yapmaya gerek yoktur, ezme işlemi olağan biçimde yapılabilir :
class pigeon : public bird{
public :
	void fly(){
		cout<<name<<" is flying nice "<<endl;
	}
};
Ancak bu durumda gösterici kullanılması durumunda çağrılan işlev alt sınıfa ait işlev olacaktır. Örneğin
bird *bp;
bp=new pigeon();
bp->name="Base Pointer Pigeon";
bp->fly();
şeklindeki kod parçasında fly() yöntemi gösterici bird türünde tanımlı dahi olsa örneğin fly() yöntemi çağrılır. Başka bir deyişle, bir işlevi virtual yapmak bütün durumlarda alt sınıfların ezme yapan işlevlerinin geçerli olduğunu belirtmek demektir.

Arı Sanal (Pure Virtual)

Arı Sanal (Pure Virtual) İşlevler

Bazı durumlarda taban sınıfta bir işlevin olması gerekir fakat işlevin içini oluşturan kod parçası her alt sınıf için değişik olduğundan üst sınıfta yazılamaz. Örneği 'balık' (fish) için 'yüzme' işlevi tanımlanmalıdır. Ancak diyelim ki her balık kendine özgü bir tarzda yüzmektedir ve hiçbir şekilde ortak bir kod yazılamaz. Bu durumda üst sınıfa swim() diye bir yöntem koymamak da doğru olmaz. Zira her balık faklı biçimlerde de olsa yüzer. Üst sınıfta bildirilen, ancak alt sınıfta gerçekleştiren kodun yazıldığı işlevler arı sanal (pure virtual) olarak nitelendirilir. Bunların işlev adı, giriş parametreleri ve dönüş tipi belirtilir ancak kod bloğu yazılmaz. Örneğin balık fish diye bir sınıf
class fish{
public :
	char *name;
	virtual void swim()=0;
};
biçiminde yazılır. Burada swim() diye bir yöntem bildirilmektedir ancak devamında kıvırcık ayraçlar ('{' ve '}') kullanarak kod yazılmaz, yerine boş olduğunu göstermek için '=0' yazılır ve noktalı virgül (';') ile ifade bildirim bitirilir. Bu sınıftan türeyen sınıflar fly() yöntemlerinin içini yazarlar. Örneğin hamsi (anchovy) ve uskumru (mackarel) sınıfları yapalım. Bunlardan anchovy sınıfı aşağıdaki gibi yapılabilir:
class anchovy : public fish{
public :
	void swim(){
		cout<<name<<" yüzüyor.."<<endl;
	}
};
Ve mackerel sınıfı aşağıdaki gibi yapılabilir:
class mackerel : public fish{
public :
	void swim(){
		cout<<name<<" yüzüyor.."<<endl;
	}
};

Soyut Sınıf (Abstract Class)

Bir veya daha fazla saf sanal işlevi bulunan sınıflara soyut (abstract) sınıf denir. Karşıtı olan somut (concrete) sınıfların aksine, bu sınıflar yalnızca türetilmek için yapılmışlardır. Soyut sınıflara ait örnekler oluşturulamaz. Örneğin
fish f;
biçiminde bir bildirim derleyici hatasına yol açar. Çünkü fish sınıfı soyuttur. Başka bir deyişle bir balık kesinlikle hamsi (anchovy), uskumru (mackerel) veya balık sınıfından türeyen somut bir sınıf olmalıdır.
Soyut bir sınıftan türeyen ancak arı sanal işlevlerini yazmayan sınıflar da soyut olur. Örneğin mackerel sınıfında swim() yöntemi yazılmazsa bunun anlamı bu sınıfında soyut olduğu, bu sınıftan türeyen başka bir sınıfın bu swim() yöntemini yazacağı anlamına gelir.

Çokbiçimlilik (Polymorphism)

Sanal işlevlerin kullanılmasıyla çok biçimlilik (polymorphism) kavramı ortaya çıkar. Bunun anlamı bir işleve dışarıdan aynı isimle ve parametrelerle erişilirken aslında içeride farklı bir kod parçasının çalışmasıdır. Örneğin fish sınıfından türetilmiş acnchovy ve mackerel sınıfılarına, göstericiler kullanılarak erişen bir kod parçası
fish *fp1;
fp1=new anchovy();
fp1->name="Black Sea Anchovy";
fp1->swim();
fish *fp2;
fp2=new mackerel();
fp2->name="Karadeniz Uskumrusu";
fp2->swim();
biçiminde yazılabilir. Burada iki ayrı sınıfa ait iki ayrı örnekle çalışıldığı halde fly() yöntem çağrısı aynı biçimde yapılmaktadır. Ancak iki örnekteki yöntem aynı biçimde çağrılsa da farklı işlevler, yani örnek hangi sınıftansa o sınıfta tanımlanmış işlevler çalışmaktadır.
Kalıtım, soyut sınıflar ve çok biçimlilik gibi konular sayesinde, bir yazılım düzenin üst sınıflar için tanımlanması ve daha sonra türetilecek sınıflar için altyapı oluşturulması olanaklı olur. Örneğin içinde belirtildiği kadar balık olan bir havuzu temsil eden pool (havuz) diye bir sınıf
class pool{
public :
	fish **fishes;
	int count;
	pool(int n){
		count=n;	
		fishes=new fish*[count];
	}
	void set_fish(int i,fish *f){
		fishes[i]=f;
	}
	fish *get_fish(int i){
		return fishes[i];
	}
	void swim_all(){
		cout<<"Havuzda yüzenler : "<<endl;
		for(int i=0;i<count;i++){
			get_fish(i)->swim();
		}		
	}
};
biçiminde yazılabilir. Burada fish sınıfına ait fishes adında göstericiler dizisi bildirilmekte ve kurucuda parametreyle aktarılan miktarda balık için yer ayrılmaktadır. Belli bir dizinindeki balığa erişmek için get_fish() ve set_fish() yöntemleri tanımlanmıştır. Havuzdaki bütün balıkların yüzmesi için de swim_all() yöntemi bulunmaktadır. Bu sınıf tamamen soyut olan fish sınıfına göre tanımlanmaktadır. Yani fish sınıfından türetilen herhangi bir sınıfa ait örnekler bu sınıfta kullanılabilir. Bu çeşit yazılım yapmanın yararı, daha sonra yazılacak sınıfların da bu tür çok biçimli sınıflarda kullanılabilir olmasıdır.
Yukarıdaki pool sınıfı aşağıdaki gibi kullanılabilir:
pool p(2);
p.set_fish(0,fp1);
p.set_fish(1,fp2);
p.swim_all();

Burada iki balıklık havuz tanımlanmakta, iki balık havuza konmakta ve yüzdürülmektedir.



Bu Sayfayı Paylaş:

İletişim/Bize Yazın   mh@fibiler.com   Google+   Facebook   Twitter   fibiler@googlegroups.com
Her Hakkı Saklıdır
Bu sitede yayınlanan tüm bilgi ve fikirlerin kullanımından fibiler.com sorumlu değildir.
Bu sitede üretilmiş , derlenmiş içerikleri, fibiler.com'u kaynak göstermek koşuluyla kendi sitenizde kullanılabilirsiniz. Ancak telif hakkı olan içeriklerin hakları sahiplerine aittir