Ana sayfa C++ Çok biçimlilik
Gönderi
İptal

C++ Çok biçimlilik

Çok biçimlilik hakkında

Çok biçimlilik sözlük anlamı olarak birden fazla şekilde varlık gösterebilen nesne ya da kavramları ifade etmektedir. Nesneye yönelik programlamada ise, çok biçimlilik fonksiyon ve işlemcilerin birden fazla görev için kullanılmaları ile kalıtım ve sanal fonksiyonların kullanılmasını içerir.

C++’da, iki tür çok biçimlilik özelliği vardır:

  • Derleme zamanı çok biçimliliği: Statik veya erken bağlama olarak bilinir.
  • Çalışma zamanı çok biçimliliği: Dinamik veya geç bağlama olarak bilinir.

C++’da, çok biçimlilik kavramını aşağıda gösterilen dört farklı yöntemle uygulayabiliriz:

  • Fonksiyonlara çoklu görev tanımlama (Overloading) işlemi
  • İşlemcilere çoklu görev tanımlama (Overloading) işlemi
  • Sınıf fonksiyonlarını doğrudan yeniden tanımlama (Overriding)
  • Sınıf fonksiyonlarını sanal yöntemle (virtual) yeniden tanımlama (Overriding)

Fonksiyonlara çoklu görev tanımlama (Overloading) işlemi

C++’da, fonksiyon çoklu görev tanımlama işlemi yapılırken çok biçimlilik özelliği kullanılır. Birden fazla fonksiyon, farklı veri türündeki ve/veya farklı sayıda parametrelerle bildirimleri yapıldığında, aynı adı kullanır ve program içinden farklı parametreler ve aynı ad ile çağrılırlarsa, fonksiyon çoklu görev tanımlama işlemi gerçekleştirilmiş olur. Böylece, program içinde tek bir isim kullanarak birden fazla fonksiyona erişim sağlanabilir. Burada kullanılan çoklu görev tanımlama ifadesi birden fazla fonksiyonun aynı isim ile çağrılarak kullanılmasını gösterir. Böyle bir fonksiyon çağırıldığında, çağrı fonksiyon çağrısında kullanılan parametre sayısı ve tiplerine uygun olarak ilgili fonksiyona yönlendirilir. Fonksiyon çoklu görev tanımlama işlemi için bir ana sınıftan bir sınıf türetilmesine ihtiyaç yoktur.

Fonksiyon çoklu görev tanımlama işlemini normal fonksiyonlara ve sınıflar içinde yer alan üye fonksiyonlara uyglayabiliriz. Bu özelliği bir örnek üzerinde incelemeye çalışalım:

Örnek

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>

using namespace std;

class sinif {
  private:
    int priid;
    int prifd;
  public:
	sinif() { priid=0; prifd=0.00f; };

	// Çoklu görev tanımlama işlemi uygulanmış fonksiyonlar
	void topla(int id1, int id2) { priid = id1+id2; };
	void topla(float fd1, float fd2) { priid = fd1+fd2; };
	void topla(int id1, int id2, int id3) { priid = id1+id2+id3; };

	void deger_goster()
	{
	  cout << "priid değişken değeri: " << priid << "\n";
	  cout << "prifd değişken değeri: " << prifd << "\n";
	};
};

int main(void)
{
  sinif nes; // Nesne oluşturma

  nes.topla(21, 35);
  nes.deger_goster();

  nes.topla(21, 35, 58);
  nes.deger_goster();

  nes.topla(17.35F, 45.54F);
  nes.deger_goster();

  return 0;
}


Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

1
2
3
4
5
6
7
8
priid değişken değeri: 56
prifd değişken değeri: 0
priid değişken değeri: 114
prifd değişken değeri: 0
priid değişken değeri: 62
prifd değişken değeri: 0

Program, priid adlı int ve prifd adlı float veri türündne olmak üzere iki adet değişken, değişkenlere ilk değer vermede kullanılan bir constructor fonksiyonu, ilki iki adet int parametre, ikincisi iki adet float parametre ve üçüncüsü üç adet int parametre alan üç adet toplama işlemi yapan topla() adlı fonksiyon ve sınıf içindeki değişken değerlerini ekranda gösteren deger_goster() adlı bir fonksiyon içeren bir sınıf bildirimi yapar. sinif türünden oluşturduğu nes adlı nesne yoluyla, topla() fonksiyonunu farklı parametrelerle çağırır ve sonuçları ekana yazar.

İşlemcilere çoklu görev tanımlama (Overloading) işlemi

C++’da, işlemci çoklu görev tanımlama işlemi yapılırken de çok biçimlilik özelliği kullanılır. Bir işlemci için çoklu görev tanımlama işlemi yapıldığında, sahip olduğu özelliklerin yanı sıra, bir sınıfa bağlı olarak ek işlem yapma özelliği kazanır. Bir işlemci için çoklu görev tanımlama işlemi yapıldığında yani birden fazla işlem yapma kapasitesi kazandırıldığında, işlemcinin orjinal fonksiyonu ortadan kalkmaz. İşlemcilere çoklu görev tanımlama işlemi yapmak için işlemci fonksiyonları oluşturulur. Bir işlemci fonksiyonu, çoklu görev tanımlama uygulanan işlemcinin bağlı olduğu sınıfa göre gerçekleştireceği işlemleri tanımlar. İşlemci fonksiyonu operator anahtar kelimesi kullanılarak oluşturulur. İşlemci fonksiyonları, bir sınıfın üyesi olabilir veya olmayabilir. Üye olmayan işlemci fonksiyonları, sınıf için friend fonksiyon olarak tanımlanır. İşlemci fonksiyonlarının yapısı sınıf üyesi olma ve olmama durumuna göre farklılık gösterir. İşlemci çoklu görev tanımlama işlemi için bir ana sınıftan bir sınıf türetilmesine ihtiyaç yoktur.

C++’da işlemci çoklu görev tanımlama işlemi yapılırken de çok biçimlilik özelliği kullanılır. Bir işlemci için çoklu görev tanımlama işlemi yapıldığında, işlemci sahip olduğu özelliklerin yanı sıra, bir sınıfa bağlı olarak ek işlem yapma özelliği kazanır.

Bir işlemci için çoklu görev tanımlama işlemi yapıldığında yani birden fazla işlem yapma kapasitesi kazandırıldığında, işlemcinin orjinal fonksiyonu ortadan kalkmaz.

İşlemcilere çoklu görev tanımlama işlemi yapmak için işlemci fonksiyonları oluşturulur. Bir işlemci fonksiyonu, çoklu görev tanımlama uygulanan işlemcinin bağlı olduğu sınıfa göre gerçekleştireceği işlemleri tanımlar.

İşlemci fonksiyonu operator anahtar kelimesi kullanılarak oluşturulur. İşlemci fonksiyonları, bir sınıfın üyesi olabilir veya olmayabilir. Üye olmayan işlemci fonksiyonları, sınıf için friend fonksiyon olarak tanımlanır. İşlemci fonksiyonlarının yapısı sınıf üyesi olma ve olmama durumuna göre farklılık gösterir.

Sınıf üyesi olarak tanımlanan işlemci çoklu görev tanımlama fonksiyonları Sınıf üyesi olarak tanımlanan ve çoklu görev tanımlama işlemi uygulanan işlemci fonksiyonunun genel yapısı aşağıda gösterilmektedir:

1
2
3
4
5
6
veri-türü sınıf-adı::operatorişlemci(parametreler)
{
  // Kod bloğu
}

İşlemci fonksiyonları herhangi bir geçerli veri türü döndürebilmesine rağmen, genellikle ilgili oldukları sınıf cinsinden bir nesne geri döndürür. Çoklu görev tanımlama yapılacak olan işlemci operator anahtar kelimesinin hemen sağında yer alan “işlemci” ifadesinin yerine konacaktır.

Tek değere işlem yapan bir işlemciye çoklu görev tanımlama işlemi uygularsak, parametre listesi boş olacak, iki değere işlem yapan bir işlemciye çoklu görev tanımlama işlemi uygularsak, parametre listesinde tek bir parametre yer alacaktır.

Şimdi, + işlemcisine üye fonksiyon ile çoklu görev tanımlama işlemi uygulamasını bir örnek üzerinde incelemeye çalışalım:

Örnek

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>

using namespace std;

class sinif {
  private:
    int id;
  public:
	// Çoklu görev tanımlama işlemi uygulanmış constructor fonksiyonları
	sinif();        // Parametresiz constructor fonksiyonu
	sinif(int pid); // Parametreli constructor fonksiyonu

	void deger_goster(void);
	
	// Sınıf üyesi olarak tanımlanmış + işlemcisi fonksiyonu 
	sinif operator+(sinif nes);
};

// Çoklu görev tanımlama işlemi uygulanmış constructor fonksiyonları ana yapısı
sinif::sinif()
{
  id = 0;
  cout << "İlk değer ataması yapmadan nesne oluşturma!" << endl;
}

sinif::sinif(int pid)
{
  id = pid;
  cout << "İlk değer ataması ile nesne oluşturma: " << id << endl;
}

// Sınıf üyesi olarak tanımlanmış + işlemcisi fonksiyonu 
sinif sinif::operator+(sinif nes)
{
  sinif lnes;
  // id değişken değeri işlemcinin sol tarafında yer alan
  // nesneye ait olup this işaretçisi ile erişim sağlanır.
  lnes.id = nes.id + id;

  return lnes;
}

void sinif::deger_goster(void)
{
  cout << "id değişken değeri: " << id << endl;
}

int main(void)
{
  sinif nes01(21);             // Parametreli constructor fonksiyonu ile nesne oluşturma
  sinif nes02(17);             // Parametreli constructor fonksiyonu ile nesne oluşturma
  
  sinif nes03 = nes01 + nes02; // Çoklu görev tanımlamad işlemi uygulanmış + işlemcisinin kullanımı

  nes01.deger_goster();
  nes02.deger_goster();
  nes03.deger_goster();

  return 0;
}


Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

1
2
3
4
5
6
7
8
İlk değer ataması ile nesne oluşturma: 21
İlk değer ataması ile nesne oluşturma: 17
İlk değer ataması yapmadan nesne oluşturma!
id değişken değeri: 21
id değişken değeri: 17
id değişken değeri: 38

Program, parametre atayarak nes01 ve nes02 adlı iki adet nesne oluşturur. Üçüncü nesne olan nes03 nesnesini oluştururken değer atamak yerine çoklu görev tanımlama işlemi uygulanmış + işlemcisinin fonksiyonunu kullanarak ilk iki nesnenin id değişken değerlerini toplayarak nes03 nesnesinin id değişkenine atar. Bütün nesneler yoluyla id değişken değerlerini ekrana yazar.

Burada, + işlemcisi sol tarafında yer alan nes01 nesnesi işlemci fonksiyonuna this işaretçisi yoluyla, nes02 nesnesi ise parametre olarak geçirilir. Fonksiyonun sonunda sinif cinsinden bir nesne geri döndürülür.

Sınıf fonksiyonlarını doğrudan yeniden tanımlama (Overriding)

Bir ana sınıftan bir sınıf türetildiğinde, ana sınıfta yer alan tüm veri ve metotlar türetilen sınıf tarafından kullanılabileceği gibi, türetilen sınıf içinde de yeni veri ve metotlar tanımlanabilir. Eğer ihtiyaç duyulursa, ana sınıftan devralınan metotlar geçersiz hale getirilir ve aynı isim altında farklı kodlar yazılır. Fonksiyonların yeniden tanımlanması (Overriding) işlemi için bir ana sınıftan bir sınıf türetilmesine ihtiyaç vardır.

Sınıf fonksiyonları için doğrudan yeniden tanımlama (Overriding) işlemi için mutlaka bir ana sınıftan türetilmiş olan en az bir adet sınıf bildirimi yapılmış olmalıdır.

Sınıf üye fonksiyonlarını yeniden tanımlama işlemi yaparken, ana sınıf içinde tanımlanan bir fonksiyon ile aynı isme sahip bir fonksiyon ana sınıftan türetilmiş bir sınıf içinde tanımlanır ve kod içeriği yeniden yazılır. Bu durumda, ana sınıf ve bu sınıf içinde aynı isme sahip iki fonksiyon oluşturulur. Bu fonksiyonlara ana sınıf ve türetilmiş sınıftan oluşturulan işaretçi ve nesneler yoluyla yapılan erişimler aşağıda gösterilen esaslara göre yapılmaktadır:

  1. Türetilen sınıf içinde yeniden tanımlanan fonksiyon ile aynı isme sahip ana sınıf içindeki fonksiyona ana sınıf nesnesi ile erişim sağlanır.
  2. Türetilen sınıf içinde yeniden tanımlanan fonksiyona türetilen sınıf nesnesi ile erişim erişim sağlanır.
  3. Türetilen sınıf içinde yeniden tanımlanan ana sınıf fonksiyonlarına türetilen sınıf nesnesi ile erişim sağlamak aşağıdaki ifadeyi kullanabiliriz: türetilen-sınıf-nesnesi.ana-sınıf-adı::fonksiyon-adı
  4. Ana sınıf işaretçisine türetilen sınıf nesnesinin adresini atandığında, bu işaretçi yoluyla türetilen sınıf içinde yeniden tanımlanan fonksiyon ile aynı isme sahip ana sınıf içindeki fonksiyona eriğşim sağlanır.
  5. Türetilen sınıf içinde yeniden tanımlanan fonksiyon içinden aşağıdaki ifade kullanıldığında, aynı isme sahip ana sınıf içindeki fonksiyona erişim sağlanır. ana-sınıf-adı::fonksiyon-adı

Şimdi, bu uygulamaları bir örnek üzerinde incelemeye çalışalım:

Örnek

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>

using namespace std;

class sinifana {
  private:
    int priidana;
  public:
    void deger_ata(int pid) {
        priidana = pid;
        cout << "priidana değişkenine değer atama!" << "\n";
    };
    void deger_goster(void)
    {
      cout << "priidana değişken değeri: " << priidana << "\n\n";
    }
};

class siniftur : public sinifana {
  private:
    int priidtur;
  public:
    void deger_ata(int pid) {
        priidtur = pid;
        cout << "priidtur değişkenine değer atama!" << "\n";

    };
    void deger_goster(void)
    {
      cout << "priidtur değişken değeri: " << priidtur << "\n\n";
    }
};

int main(void)
{
  sinifana *pnes;
  sinifana nes_ana;
  siniftur nes_tur;

  // Türetilen sınıf içinde yeniden tanımlanan fonksiyonlar ile aynı
  // isme sahip ana sınıf içindeki fonksiyonlara erişim sağlanır.
  nes_ana.deger_ata(154);
  nes_ana.deger_goster();

  // Türetilen sınıf içinde yeniden tanımlanan fonksiyonlara türetilen
  // sınıf nesnesi ile erişim erişim sağlanır.
  nes_tur.deger_ata(21);
  nes_tur.deger_goster();

  // Türetilen sınıf içinde yeniden tanımlanan ana sınıf
  // fonksiyonlarına türetilen sınıf nesnesi ile erişim
  nes_tur.sinifana::deger_ata(35);
  nes_tur.sinifana::deger_goster();

  // Ana sınıf işaretçisine türetilen sınıf nesnesinin
  // adresini atayarak ana sınıf fonksiyonlarına erişim
  pnes = &nes_tur;
  pnes->deger_ata(47);
  pnes->deger_goster();

  return 0;
}


Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

1
2
3
4
5
6
7
8
9
10
11
12
13
priidana değişkenine değer atama!
priidana değişken değeri: 154

priidtur değişkenine değer atama!
priidtur değişken değeri: 21

priidana değişkenine değer atama!
priidana değişken değeri: 35

priidana değişkenine değer atama!
priidana değişken değeri: 47

Program, priidana adlı private int bir değişken, bu değişkene değer atayan deger_ata() adlı bir fonksiyon ve bu değişken değerini ekrana yazan deger_goster() adlı bir fonksiyon içeren sinifana adlı bir ana sınıf bildirimi yapar. Sonra, priidtur adlı private int bir değişken, bu değişkene değer atayan deger_ata() adlı bir fonksiyon ve bu değişken değerini ekrana yazan deger_goster() adlı bir fonksiyon içeren ve sinifana adlı sınıftan türetilen siniftur adlı bir sınıf bildirimi yapar. Ana sınıf ve türetilen sınıf içinde yer alan fonksiyonlar aynı isme sahip olduklarından, yeniden tanımlanmış fonksiyonlardır.

Program, sinifana sınıfından pnes adlı bir işaretçi ile nes_ana adlı bir nesne ile siniftur adlı sınıftan nes_tur adlı bir nesne bildirimi yapar. nes_ana nesnesini kullanarak, ana sınıf içindeki fonksiyonlar yoluyla, priidana değişkenine 154 değerini atar ve değişken değerini ekrana yazar. Böylece, türetilen sınıf içinde yeniden tanımlanan fonksiyon ile aynı isme sahip ana sınıf içindeki fonksiyonlar erişim sağlanır. nes_tur nesnesini kullanarak, türetilen sınıf içindeki fonksiyonlar yoluyla, priidtur değişkenine 21 değerini atar ve değişken değerini ekrana yazar. Böylece, türetilen sınıf içinde yeniden tanımlanan fonksiyonlara türetilen sınıf nesnesi ile erişim sağlanır. nes_tur nesnesini ana sınıf adı ve :: işlemcisi ile birlikte kullanarak, ana sınıf içindeki fonksiyonlar yoluyla, priidana değişkenine 35 değerini atar ve değişken değerini ekrana yazar. Böylece, nes_tur nesnesi ile ana sınıf fonksiyonlarına erişim sağlanır. pnes adlı ana sınıf işaretçisine nes_tur adlı türetilen sınıf nesnesinin adresi atar. Bu işaretçi yoluyla ana sınıf fonksiyonlarını kullanarak, priidana değişkenine 47 değerini atar ve değişken değerini ekrana yazar. Böylece, bu işaretçi yoluyla türetilen sınıf içinde yeniden tanımlanan fonksiyonlar ile aynı isme sahip ana sınıf içindeki fonksiyonlara erişim sağlanır.

Programın çalışma şeklini gösteren şekil aşağıdadır:

Şimdi, türetilen sınıf içinde yeniden tanımlanan fonksiyon içinde ana sınıf adı ile birlikte :: işlemcisini kullanarak, ana sınıf içindeki aynı isme sahip fonksiyona erişim sağlanmasını bir örnek üzerinde incelemeye çalışalım:

Örnek

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>

using namespace std;

class sinifana {
  private:
    int priidana;
  public:
    void deger_ata(int pid) {
        priidana = pid;
        cout << "priidana değişkenine değer atama!" << "\n";
    };
    void deger_goster(void)
    {
      cout << "priidana değişken değeri: " << priidana << "\n";
    }
};

class siniftur : public sinifana {
  private:
    int priidtur;
  public:
    void deger_ata(int pid1, int pid2) {
        priidtur = pid1;
        cout << "priidtur değişkenine değer atama!" << "\n";
        sinifana::deger_ata(pid2);
    };
    void deger_goster(void)
    {
      cout << "priidtur değişken değeri: " << priidtur << "\n";
      sinifana::deger_goster();
    }
};

int main(void)
{
  siniftur nes_tur;

  nes_tur.deger_ata(27,35);
  nes_tur.deger_goster();

  return 0;
}


Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

1
2
3
4
5
6
priidtur değişkenine değer atama!
priidana değişkenine değer atama!
priidtur değişken değeri: 27
priidana değişken değeri: 35

Program, priidana adlı private int bir değişken, bu değişkene değer atayan deger_ata() adlı bir fonksiyon ve bu değişken değerini ekrana yazan deger_goster() adlı bir fonksiyon içeren sinifana adlı bir ana sınıf bildirimi yapar. Sonra, priidtur adlı private int bir değişken, bu değişkene değer atayan deger_ata() adlı bir fonksiyon ve bu değişken değerini ekrana yazan deger_goster() adlı bir fonksiyon içeren ve sinifana adlı sınıftan türetilen siniftur adlı bir sınıf bildirimi yapar. Ana sınıf ve türetilen sınıf içinde yer alan fonksiyonlar aynı isme sahip olduklarından, yeniden tanımlanmış fonksiyonlardır. Türetilen sınıf içinde yeniden tanımlanan fonksiyonlar ana sınıf adı ile :: işlemcisini kullanarak, aynı isme sahip ana sınıf fonksiyonlarını çağırmaktadır.

Program, siniftur adlı sınıftan nes_tur adlı bir nesne bildirimi yapar. nes_tur nesnesini kullanarak, türetilen sınıf içindeki fonksiyonlar yoluyla, priidtur değişkenine 27 değerini ve priidana değişkenine 35 değerini atar ve değişken değerlerini ekrana yazar. Böylece, türetilen sınıf içinde yeniden tanımlanan fonksiyonlara türetilen sınıf nesnesi ile erişim sağlanırken aynı zamanda, fonksiyonlar içinden ana sınıf fonksiyonlarına da erişim sağlanır.

Sınıf fonksiyonlarını sanal yöntemle (virtual) yeniden tanımlama (Overriding)

Sanal fonksiyonlar, çalışma zamanı çok biçimlilik (Runtime Polymorphism) özelliği sağlar. Sanal bir fonksiyon oluşturmak için, ana sınıf içindeki fonksiyon bildiriminden önce virtual anahtar kelimesi kullanılır. Sanal fonksiyon içeren bir sınıftan yeni bir sınıf türetildiğinde, türetilen her sınıf içinde sanal fonksiyon, virtual anahtar kelimesi kullanılmadan, yeniden tanımlanır ve fonksiyon içeriği yeniden düzenlenir. Bu özellikle, virtual anahtar kelimesi derleyiciye fonksiyon bağlama işlemini derleme zamanında değil çalışma zamanında yapmasını bildirir. Sanal fonksiyon ile, aynı isme sahip bir fonksiyon her sınıf için ayrı bir işlem yapacak şekilde tanımlanabilmektedir. Bu durum nesneye yönelik programlamada çok biçimlilik (Polymorphism) özelliğinin bir sonucudur. İşaretçi kullanarak erişim sağlamak sanal fonksiyonları sınıf içindeki diğer fonksiyonlardan farklı hale getirir. Ana sınıf türünden oluşturulan bir işaretçi ana sınıf ve ana sınıftan türetilen tüm sınıflar içindeki sanal fonksiyonlara erişim sağlayabilir.

Sınıf fonksiyonları için sanal yöntemle (virtual) yeniden tanımlama (Overriding) işlemi için mutlaka bir ana sınıftan türetilmiş olan en az bir adet sınıf bildirimi yapılmış olmalıdır.

Sanal fonksiyonlar bir ana sınıf içinde bildirimi yapıldıktan sonra türetilen sınıf içinde tekrar tanımlanır. Sanal fonksiyon bildirimi için kullanılan genel yapı aşağıda gösterilmektedir:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ana-sınıf {
  public:
    virtual veri-türü fonk-adı(parametreler)
    {
      // kod bloğu   
    }
}

class türetilen-sınıf public: ana-sınıf {
  public:
    veri-türü fonk-adı(parametreler)
    {
      // kod bloğu   
    }
}

Sanal fonksiyonlar genel olarak ana sınıf işaretçisi kullanılarak çağrılır. Bu yöntemde, ana sınıftan ve türetilen sınıflardan oluşturulan nesnelerin adresleri ana sınıf türünden tanımlanan işaretçiye atanarak her bir sınıfta yer alan sanal fonksiyona çağrı yapılır.

Sanal fonksiyon tanımlamayı bir örnek üzerinde incelemeye çalışalım:

Örnek

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>

using namespace std;

class sinifana {
  private:
    int priidana;
  public:
    void deger_ata(int pid) {
        priidana = pid;
        cout << "priidana değişkenine değer atama!" << "\n";
    };
    void deger_goster(void)
    {
      cout << "priidana değişken değeri: " << priidana << "\n\n";
    }
};

class siniftur : public sinifana {
  private:
    int priidtur;
  public:
    void deger_ata(int pid) {
        priidtur = pid;
        cout << "priidtur değişkenine değer atama!" << "\n";

    };
    void deger_goster(void)
    {
      cout << "priidtur değişken değeri: " << priidtur << "\n\n";
    }
};

int main(void)
{
  sinifana *pnes;
  sinifana nes_ana;
  siniftur nes_tur;

  // Türetilen sınıf içinde yeniden tanımlanan fonksiyonlar ile aynı
  // isme sahip ana sınıf içindeki fonksiyonlara erişim sağlanır.
  nes_ana.deger_ata(154);
  nes_ana.deger_goster();

  // Türetilen sınıf içinde yeniden tanımlanan fonksiyonlara türetilen
  // sınıf nesnesi ile erişim erişim sağlanır.
  nes_tur.deger_ata(21);
  nes_tur.deger_goster();

  // Türetilen sınıf içinde yeniden tanımlanan ana sınıf
  // fonksiyonlarına türetilen sınıf nesnesi ile erişim
  nes_tur.sinifana::deger_ata(35);
  nes_tur.sinifana::deger_goster();

  // Ana sınıf işaretçisine türetilen sınıf nesnesinin
  // adresini atayarak ana sınıf fonksiyonlarına erişim
  pnes = &nes_tur;
  pnes->deger_ata(47);
  pnes->deger_goster();

  return 0;
}


Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

1
2
3
4
5
6
7
8
9
10
11
12
13
priidana değişkenine değer atama!
priidana değişken değeri: 154

priidtur değişkenine değer atama!
priidtur değişken değeri: 21

priidana değişkenine değer atama!
priidana değişken değeri: 35

priidtur değişkenine değer atama!
priidtur değişken değeri: 47

Program, priidana adlı private int bir değişken, bu değişkene değer atayan deger_ata() adlı ve bu değişken değerini ekrana yazan deger_goster() adlı iki adet sanal (virtual) fonksiyon içeren sinifana adlı bir ana sınıf bildirimi yapar. Sonra, priidtur adlı private int bir değişken, bu değişkene değer atayan deger_ata() adlı ve bu değişken değerini ekrana yazan deger_goster() adlı iki adet fonksiyon içeren ve sinifana adlı sınıftan türetilen siniftur adlı bir sınıf bildirimi yapar. Ana sınıf içindeki sanal fonksiyonlarla türetilen sınıf içinde yer alan fonksiyonlar aynı isme sahip olduklarından, yeniden tanımlanmış fonksiyonlardır.

Program, sinifana sınıfından pnes adlı bir işaretçi ile nes_ana adlı bir nesne ile siniftur adlı sınıftan nes_tur adlı bir nesne bildirimi yapar. nes_ana nesnesini kullanarak, ana sınıf içindeki fonksiyonlar yoluyla, priidana değişkenine 154 değerini atar ve değişken değerini ekrana yazar. Böylece, türetilen sınıf içinde yeniden tanımlanan fonksiyon ile aynı isme sahip ana sınıf içindeki fonksiyonlar erişim sağlanır. nes_tur nesnesini kullanarak, türetilen sınıf içindeki fonksiyonlar yoluyla, priidtur değişkenine 21 değerini atar ve değişken değerini ekrana yazar. Böylece, türetilen sınıf içinde yeniden tanımlanan fonksiyonlara türetilen sınıf nesnesi ile erişim sağlanır. nes_tur nesnesini ana sınıf adı ve :: işlemcisi ile birlikte kullanarak, ana sınıf içindeki fonksiyonlar yoluyla, priidana değişkenine 35 değerini atar ve değişken değerini ekrana yazar. Böylece, nes_tur nesnesi ile ana sınıf fonksiyonlarına erişim sağlanır.

pnes adlı ana sınıf işaretçisine nes_tur adlı türetilen sınıf nesnesinin adresi atar. Bu işaretçi yoluyla türetilen sınıf fonksiyonlarını kullanarak, priidtur değişkenine 47 değerini atar ve değişken değerini ekrana yazar. Böylece, bu işaretçi yoluyla türetilen sınıf içinde yeniden tanımlanan fonksiyonlara erişim sağlanır.

Programın çalışma şeklini gösteren şekil aşağıdadır:

Sınıf fonksiyonlarının doğrudan ve sanal yöntemle (virtual) yeniden tanımlanması arasındaki fark, doğrudan yeniden tanımlama yönteminde, ana sınıf işaretçisine türetilen sınıf nesnesinin adresi atandığında, ana sınıf işaretçisi ana sınıf içindeki fonksiyonlara erişim sağlarken, sanal yöntemle yeniden tanımlama yönteminde, türetilen sınıf içindeki fonksiyonlara erişim sağlamaktadır.

Bu gönderi CC BY 4.0 lisansı altındadır.

C++ Kalıtım

C++ Sınıf