C++ - Operator overloading (Nesne yönelimli programlama #3)

Selamlar herkese!

Bu yazımız nesne yönelimli programlama serisinin son yazısı olacak ve sizler için operator overloading'i (operatör aşırıyükleme) ele alacağım.

Nedir bu aşırı yükleme?

Operator overloading aslında ayrı bir fonksiyon adı düşünmek yerine, o işi fonksiyon yerine operatörler ile yapmamızı sağlar. Mesela şöyle bir kodunuz var diyelim:

[CODE lang="cpp" title="İlk kodumuz"]#include <iostream>
class SanalSayi{
double gercek_sayi, sanal_sayi;
public:
SanalSayi(double gercek, double sanal){
this->gercek_sayi = gercek;
this->sanal_sayi = sanal;
}
inline double get_gercek(){return gercek_sayi;}
inline double get_sanal(){return sanal_sayi;}
inline void set_gercek(double val){gercek_sayi = val;}
inline void set_sanal(double val){sanal_sayi = val;}
inline void cikti_ver(){std::cout<<gercek_sayi<<"+"<<sanal_sayi<<"i"<<std::endl;}
inline void sanal_sayi_kopyala(SanalSayi &kaynak, SanalSayi &hedef){
hedef.set_sanal(kaynak.get_sanal());
hedef.set_gercek(kaynak.get_gercek());
}
};
int main(){
SanalSayi sayi1(9,2);
SanalSayi sayi2(10,5);
sayi1.cikti_ver();
sayi2.cikti_ver();
}[/CODE]

Gördüğünüz gibi, kodumuz gayet nesne yönelimli programlamaya uygun yazılmış. Ama bir şey eksik sanırım... Operatörler ile işlem yapamıyoruz bu kodda. Evet evet! Mesela sayi3 = sayi1 + sayi2; diyemiyoruz.

İşte operator overloading burada devreye giriyor. Bir operatöre farklı bir işlev kazandırıyorsunuz, sizin sınıfınızı operatör bilemez ki eğer overload olmadıysa! Belki de sizin sınıfınız sanal sayılar hakkında değil de matematik ile pek alakalı olmayan bir konuyla alakalı olacak... Her neyse, bu kodun üzerine hemen bir ekleme yapalım:

[CODE lang="cpp" title="Yeni versiyonumuz"]#include <iostream>
class SanalSayi{
double gercek_sayi, sanal_sayi;
public:
SanalSayi(){}
SanalSayi(double gercek, double sanal){
this->gercek_sayi = gercek;
this->sanal_sayi = sanal;
}

//inline void cikti_ver(){std::cout<<gercek_sayi<<"+"<<sanal_sayi<<"i"<<std::endl;} Bu fonksiyonu << operatörü ile değiştireceğiz.
/*inline void sanal_sayi_kopyala(SanalSayi &kaynak, SanalSayi &hedef){
hedef.set_sanal(kaynak.get_sanal());
hedef.set_gercek(kaynak.get_gercek());
}
Kopyalama fonksiyonumuzu = operatörü ile değiştireceğiz.
*/
inline friend std::eek:stream& operator<<(std::eek:stream& output_stream, SanalSayi sayi){
return output_stream<<sayi.gercek_sayi<<"+"<<sayi.sanal_sayi<<"i";
}
inline friend SanalSayi operator+(SanalSayi sayi1, SanalSayi sayi2){
SanalSayi temp;
temp.gercek_sayi = sayi1.gercek_sayi+sayi2.gercek_sayi;
temp.sanal_sayi = sayi1.sanal_sayi+sayi2.sanal_sayi;
return temp;
}
inline void operator=(SanalSayi &sayi1){
sayi1.gercek_sayi = this->gercek_sayi;
sayi1.sanal_sayi = this->sanal_sayi;
}
};
int main(){
SanalSayi sayi1(9,2);
SanalSayi sayi2(10,5);
std::cout<<sayi1<<"\n"<<sayi2<<std::endl;
SanalSayi sayi3 = sayi1+sayi2;
sayi1 = sayi2;
std::cout<<sayi3<<std::endl;
}[/CODE]
Önceki bloglarımda bahsetmediğim "friend" isimli bir anahtar sözcük var. Bu anahtar sözcüğümüzün görevi, bir fonksiyonu "scope resolution" (A::B gibisinden) olmadan direkt olarak "yüklememizi" sağlar (void B şeklinde).
Örneğin, bir header dosyamız olsun:
[CODE lang="cpp" title="ornek_sinif.hpp"]#pragma once //Bu header dosyasını sadece 1 kez koda eklemesini talep ediyoruz önişlemciden, aksi takdirde linker veya compiler hataları ile karşılaşabiliriz.
#if 0 //Bunun içindeki kodlar derlenmez, merak etmeyin. Sadece yorum amaçlı. Fakat renklendirme devam etsin ve iki slash gibi özel karakterleri kullanabilelim diye.
Kod dosyalarında #pragma once yerine şu notasyon da kullanılabilir:
#ifndef KUTUPHANE_ADI
#define KUTUPHANE_ADI
//Ve kod buradan başlar...
#endif
#endif
class OrnekClass{
int test1, test2;
public:
void foo();
friend void bar();
};[/CODE]
Ve bu header dosyamızın içindeki metodları ise bir kaynak kod dosyasında aşırı yükleyelim:
[CODE lang="cpp" title="ornek_sinif.cpp"]#include "ornek_sinif.h"

void OrnekSinif::foo(){ //Friend olmayan bir fonksiyondu hatırlarsak.
//Kod
}
void bar(){ //Friend fonksiyon.
//Bu kodun direkt olarak nesne ile alakalı olmasına gerek yoktur.
}
int main(){
OrnekSinif obje;
obje.foo(); //Friend olmayan fonksiyonun çağırımı.
bar(); //Friend fonksiyonun çağırımı.
}[/CODE]
Görüldüğü gibi, hiçbir scope resolution vs. kullanmadan friend fonksiyonumuzu çağırabilir ve sınıfın private elemanına erişebiliriz.
Friend fonksiyonların operatör overloading ile çok kullanılma sebebini soracak olursanız, bir operatör çağırırken nesne erişimi kullanmanın saçma olmasından dolayıdır. :D
Örneğin, friend kullanılmasaydı C++ syntax'ına göre şöyle bir şey olurdu fonksiyon çağırımı:
obje.operator=(obje2);
Friend ile böyle bir kullanıma düşebiliyoruz:
obje = obje2;

Operatör fonksiyonlarının parametresi neden var?
Operator overloading'te fonksiyon parametresi, operatörün sağ kısmını belirtir. Çoğu zaman yaptığımız "1+2" işlemini düşünelim, burada "+ operatörünün" sağ kısmındaki 2 sayımız bizim operatör fonksiyonumuza parametre olarak verilen sayımızdır.

Özet
Bu konu ilk başta zor anlaşılabilir. Pratik yaptığınız zaman iyice alışırsınız, ben öyle alıştım. Ayrıca sizlere dolaylı yoldan çok fazla şey anlattığım için mutluyum. Başka bir yazıda görüşmek üzere!
  • Beğen
İfadeler: tirabzonun_kaymagi

Yorumlar

Gösterilecek yorum bulunamadı.

Blog girdisi detayları

Ekleyen
TerabyteForever
Okuma süresi
2 dakika okuma
Görüntüleme
1.509
Son güncelleme

Yazılım kategorisindeki diğer girdiler

TerabyteForever adlı kullanıcının diğer girdileri

Bu girdiyi paylaş

Geri
Yukarı