[MAKALE] - Operator Overloading

OnurSorhan

Doçent
Katılım
17 Temmuz 2012
Mesajlar
808
Reaksiyon puanı
0
Puanları
16
Merhabalar,

Bu makalemde birlikte operator overloading'i inceleyeceğiz. Temel bilgilere sahip olduktan sonra yazılmış bir örnek üzerinden adım adım ilerleyerek konuyu daha rahat kavrayabileceğiz. Peki nedir bu Operator Overloading, nerelerde kullanılır, ne gibi avantajlar sağlar?. Şimdi bu soruların cevaplarını bulmaya çalışalım.

Tüm unary veya binary operatörlerin default tanımlanmış ve bizim programlarımızda kullandığımız implemantasyonları vardır. Operator Overloading bu default implemantasyonları kendi yazdığımız özel bir tipe,yapıya veya class'a göre yeniden yazmammızı ve tanımladığımız nesneler arasında bu operatörlerle özel işlemler yapmamızı sağlar. Ancak C# da tüm operatorler overload edilememektedir. Şimdi operatörleri sınıflandıralım ve hangilerinin overload edilebildiğini inceleyelim.

[TABLE="width: 100%"]
[TR]
[TD]Operatörler
[/TD]
[TD]Sınıflandırma
[/TD]
[TD]Overload Edilebilirlik
[/TD]
[/TR]
[TR]
[TD]+, -, *, /, %, &, |, <<, >>
[/TD]
[TD]Binary Operatörler
[/TD]
[TD]Tümü overload edilebilir
[/TD]
[/TR]
[TR]
[TD]+, -, !, ~, ++, --, true, false
[/TD]
[TD]Unary Operatörler
[/TD]
[TD]Tümü overload edilebilir
[/TD]
[/TR]
[TR]
[TD]==, !=, <, >, <= , >=
[/TD]
[TD]Relational (İlişkisel) Operatörler
[/TD]
[TD]Çiftler halinde overload edilebilir.
[/TD]
[/TR]
[TR]
[TD]&&, ||
[/TD]
[TD]Logical Operatörler
[/TD]
[TD]Overload Edilemez.
[/TD]
[/TR]
[TR]
[TD]()
[/TD]
[TD]Conversation Operatörler
[/TD]
[TD]Overload Edilemez.
[/TD]
[/TR]
[TR]
[TD]+=, -=, *=, /=, %=
[/TD]
[TD]Bileşik Atama Operatörleri
[/TD]
[TD]Overload Edilebilir. Binary operatörlerdeki
değişiklikler bu operatörlere yansır.
[/TD]
[/TR]
[TR]
[TD]=, . , ?:, ->, new, is, as, sizeof
[/TD]
[TD]
[/TD]
[TD]Overload Edilemez.
[/TD]
[/TR]
[/TABLE]

Operator Overload etmek için yazacağımız fonksiyona ait bazı kesin kurallar vardır. Bu kurallar fonksiyonun veya methodun public ve static tanımlanması,sadece value argument alabilmesi, ref ve out parametrelerinin desteklenmemesi ve argumanlardan en az birinin kullanıcı tanımlı tipte (örn. class) olmasıdır. Bu durumda genel bir syntax çıkartacak olursak bu syntax aşağıdaki gibi olacaktır.

public static donusTipi operator operatorTipi (arguman listesi)

Unary operatörlerin overloadında syntax public static donusTipi operator operatorTipi (tip t) { } şeklindedir. +, ~, ! gibi unary operatörler için dönüş tipi void dışında herhangi bir tip olabilirken ++,-- gibi fonksiyonlarda arguman olarak alınan tip ile aynı tipte olmalıdır. Ayrıca önemli bir nokta ise true operatörü overload edildiği zaman false operatörününde overload edilmesi gerekemesidir. Bu operatörlerden sadece biri overload edildiğinde hata verecek ve proje build edilmeyecektir.

Binary operatörlerin overloadında syntax public static donusTipi operator operatorTipi (Tip1 t1, Tip2 t2){ } şekilndedir. Overload edilmiş bir binary operatör 2 tane arguman almalıdır ve bunlardan biri mutlaka tanımlandığı class'ın tipiyle aynı olmalıdır. Dönüş tipi ise void dışında herhangi bir tip olabilir. ==, !=, <, >, <=, >= gibi binary operatörler sadece çiftler şeklinde overload edilebilir. Ayrıca bir binary matematiksel operatör overload edildiğinde buna bağlı atama operatörüde otomatikman overload edilir. (Örneğin - ve -=)

Operator overload genellikle matris işlemleri, karmaşık sayılarla işlemler gibi konularda kullanılır. Bu örnekte daha basite indirgenmiş bir uygulama ile bu konuyu inceğiz. Eminmki bu makaleden sonra benzer örnekleri sizde geliştirebileceksiniz. Örneğimize başlayalım.

Markette dolaşırken 2 tane bayan gördüğümüzü düşünelim ve sepetlerinde elma ve armutlar olsun. Burada sepet bizim classımız, içinde bulunan elma ve armutlar ise propertylerimiz olcak. Cevap bulmaya çalışacağımız sorular ise sepetlerin toplamı nedir?(elma ve armut sayılarının ayrı ayrı toplanması gerek), Sepetlerin farkı nedir?,Sepetler eşitmidir?. İlk sepete bir elma bir armut atarsa kaç elma kaç armut olur gibi sorulardır. Şimdi kodlamaya başlayalım ve Sepetimizi yaratalım.


[TABLE="width: 100%"]
[TR]
[TD]
Kod:
[TABLE]
[TR]
[TD]using System;
namespace OperatorOverloading
{
      public class Sepetim
      {
            private int mElmaSayisi;
            private int mArmutSayisi;
 
            public Sepetim()
            {
            }
            public Sepetim(int pElmaSayisi,int pArmutSayisi)
            {
                  this.ElmaSayisi=pElmaSayisi;
                  this.ArmutSayisi=pArmutSayisi;
            }
            public int ElmaSayisi{
                  get
                  {
                        return mElmaSayisi;
                  }
                  set
                  {
                        mElmaSayisi = value;
                }
            }
            public int ArmutSayisi
            {
                  get
                  {
                        return mArmutSayisi;
                  }
                  set
                  {
                        mArmutSayisi = value;
                  }
            }
[/TD]
[/TR]
[/TABLE]
[/TD]
[/TR]
[TR]
[TD]
Bu kısımda classımızı yaratıp ona ait propertyleri ve enCapsulationları oluşturuyoruz. Yani sepetimizde bulunacak elma veya armut sayısını artık belirleyebilir veya mevcut olan değeri istediğimiz zamanda öğrenebiliriz. Şimdi unary operatörlerimizden kullanacaklarımızı overload edelim.


[/TD]
[/TR]
[TR]
[TD]
Kod:
[TABLE]
[TR]
[TD]            public static Sepetim  operator - (Sepetim pSepetim)
            {
                  return new Sepetim(-pSepetim.ElmaSayisi,-pSepetim.ArmutSayisi);
            }
            public static Sepetim  operator ++ (Sepetim pSepetim1)
            {
                  return new Sepetim(pSepetim1.ElmaSayisi +1,pSepetim1.ArmutSayisi+1);
            }
            public static Sepetim  operator -- (Sepetim pSepetim1)
            {
                  return new Sepetim(pSepetim1.ElmaSayisi -1,pSepetim1.ArmutSayisi-1);
            }
[/TD]
[/TR]
[/TABLE]
[/TD]
[/TR]
[TR]
[TD]
Bu kısımda kendi sınıfımıza ait unary operatörlerimizden -,++,-- yı overload ediyoruz. Sepetimizi parametre olarak alan bu fonksiyonlarda sepetimizin içindeki elma ve armut sayılarında değişiklik yapılıp sepetimize benzer bir sepet geri döndürülüyor. - operatöründe sepette bulunan elma ve armut sayısı negatifize olurken ++ da bir artmakta ve -- de bir azalmaktadır. Şimdi binary operatörlerimizden kullanacaklarımızı overload edelim.

[/TD]
[/TR]
[TR]
[TD]
Kod:
[TABLE]
[TR]
[TD]public static Sepetim  operator + (Sepetim pSepetim1,Sepetim pSepetim2)
            {
                  return new Sepetim(pSepetim1.ElmaSayisi + pSepetim2.ElmaSayisi, pSepetim1.ArmutSayisi+pSepetim2.ArmutSayisi);
            }
            public static Sepetim  operator - (Sepetim pSepetim1,Sepetim pSepetim2)
            {
                  return new Sepetim(pSepetim1.ElmaSayisi - pSepetim2.ElmaSayisi,pSepetim1.ArmutSayisi-pSepetim2.ArmutSayisi);
            }
            public static bool operator ==(Sepetim pSepetim1,Sepetim pSepetim2)
            {
                  if(pSepetim1.ElmaSayisi==pSepetim2.ElmaSayisi && pSepetim1.ArmutSayisi==pSepetim2.ArmutSayisi)
                  {
                        return true;
                  }
                  else
                  {
                        return false;
                  }
            }
            public static bool operator !=(Sepetim pSepetim1,Sepetim pSepetim2)
            {
                  if(pSepetim1.ElmaSayisi!=pSepetim2.ElmaSayisi || pSepetim1.ArmutSayisi!=pSepetim2.ArmutSayisi)
                  {
                        return true;
                  }
                  else
                  {
                        return false;
                  }
            }

[/TD]
[/TR]
[/TABLE]
[/TD]
[/TR]
[TR]
[TD]
Bu kısımda ise classımıza ait binary operatörlerden +,-,= = ve ! = i overload ediyoruz. Bu kısımda ise artık fonksiyonlarımız iki tane sepet alıp bunları bir sepette birleştirmek,farklarını anlamak veya eşitliğini kontrol etmek gibi işlemler yapıyor. Bu fonksiyonlarda geri dönüş tipi herhangi bir değişken olabilmektedir. Unutmamalıyızki = = 'i overload ettiğimiz zaman != 'de overload etmeliyiz. ve aşağıda yer alan iki metoduda (Equals,GetHashCode) yazmalıyız.

[/TD]
[/TR]
[TR]
[TD]
Kod:
[TABLE]
[TR]
[TD]public override bool Equals(object obj)
            {
                  return base.Equals (obj);
            }
            public override int GetHashCode()
            {
                  return base.GetHashCode ();
            }

[/TD]
[/TR]
[/TABLE]
[/TD]
[/TR]
[TR]
[TD]
Bu iki fonksiyonuda yazdıktan sonra sırada bir çift olarak bulunana > ve < operatörlerini override etmek var.

[/TD]
[/TR]
[TR]
[TD]
Kod:
[TABLE]
[TR]
[TD]            public static bool operator >(Sepetim pSepetim1,Sepetim pSepetim2)
            {
                  if (pSepetim1.ElmaSayisi>pSepetim2.ElmaSayisi || pSepetim1.ArmutSayisi>pSepetim2.ArmutSayisi)
                  {
                        return true;
                  }
                  else
                  {
                        return false;
                  }
            }
            public static bool operator <(Sepetim pSepetim1,Sepetim pSepetim2)
            {
                  if (pSepetim1.ElmaSayisi>pSepetim2.ElmaSayisi || pSepetim1.ArmutSayisi>pSepetim2.ArmutSayisi)
                  {
                        return false;
                  }
                  else
                  {
                        return true;
                  }
            }
      }
}
[/TD]
[/TR]
[/TABLE]
[/TD]
[/TR]
[TR]
[TD]
Burada > operatörümüzü yazdıktan sonra < operatörümüzün içine uzun uzun yazmaktansa return ! pSepetim1>pSepetim2; şeklindeki kısa bir cümle ile daha genel bir yapı elde edebilirdik ama şu an için performansı düşündüğümüzden bu yöntemle ilerledik. Bu yöntemlerde herhangi bir propertynin diğerinden büyük veya küçük olması daha büyük veya daha küçük diyebilmemiz için yeterlidir. Buradaki mantık sadece uygulama örneği amaçlı olduğundan çokta sağlıklı olmasa bize eminimki sizler bu konularda daha başarılı fonksiyonlar yazabileceksiniz.
Bu noktada artık classımızı ve overload edebileceğimiz operatörlerimizi bitirdik ve bu classı kullanacak örnek bir uygulama yazıp bunun üzerinden operatörlerimizin çalıştığının ispatını yapmalıyız. Form dizaynımız ve dizayndaki butonlara ait kodlar aşağıdaki gibi olacaktır

1000000514_operatoroverloadingimga.jpg


Şimdi formumuzda bulunan button ları ve yaptıkları işlemleri inceleyelim.

[/TD]
[/TR]
[TR]
[TD]
Kod:
[TABLE]
[TR]
[TD]private void btnTopla_Click(object sender, System.EventArgs e)
            {
                   Sepetim iSepetim1=new  Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));
                   Sepetim iSepetim2=new  Sepetim(Convert.ToInt32(txtSepet2ElmaSayisi.Text),Convert.ToInt32(txtSepet2ArmutSayisi.Text));
                  Sepetim iSepetim3=new Sepetim();
                  iSepetim3=iSepetim1 + iSepetim2;
                  txtSonucElmaSayisi.Text=iSepetim3.ElmaSayisi.ToString();
                  txtSonucArmutSayisi.Text=iSepetim3.ArmutSayisi.ToString();
            }
 
            private void btnCikart_Click(object sender, System.EventArgs e)
            {
                   Sepetim iSepetim1=new  Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));
                   Sepetim iSepetim2=new  Sepetim(Convert.ToInt32(txtSepet2ElmaSayisi.Text),Convert.ToInt32(txtSepet2ArmutSayisi.Text));
                  Sepetim iSepetim3=new Sepetim();
                  iSepetim3=iSepetim1 - iSepetim2;
                  txtSonucElmaSayisi.Text=iSepetim3.ElmaSayisi.ToString();
                  txtSonucArmutSayisi.Text=iSepetim3.ArmutSayisi.ToString();
            }
 
            private void btnBirEkle_Click(object sender, System.EventArgs e)
            {
                   Sepetim iSepetim1=new  Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));
                  Sepetim iSepetim3= new Sepetim();
                  iSepetim1++;
                  iSepetim3=iSepetim1;
                  txtSonucElmaSayisi.Text=iSepetim3.ElmaSayisi.ToString();
                  txtSonucArmutSayisi.Text=iSepetim3.ArmutSayisi.ToString();
            }
 
            private void btnBirCikart_Click(object sender, System.EventArgs e)
            {
                   Sepetim iSepetim1=new  Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));
                  Sepetim iSepetim3= new Sepetim();
                  iSepetim1--;
                  iSepetim3=iSepetim1;
                  txtSonucElmaSayisi.Text=iSepetim3.ElmaSayisi.ToString();
                  txtSonucArmutSayisi.Text=iSepetim3.ArmutSayisi.ToString();
            }
 
            private void btnEsitmi_Click(object sender, System.EventArgs e)
            {
                   Sepetim iSepetim1=new  Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));
                   Sepetim iSepetim2=new  Sepetim(Convert.ToInt32(txtSepet2ElmaSayisi.Text),Convert.ToInt32(txtSepet2ArmutSayisi.Text));
                  if (iSepetim1==iSepetim2)
                  {
                        MessageBox.Show("Esit");
                  }
                  else
                  {
                        MessageBox.Show("Esit Degil");
                  }
            }
 
            private void Form1_Load(object sender, System.EventArgs e)
            {
           
            }
 
            private void btnBuyukmu_Click(object sender, System.EventArgs e)
            {
                   Sepetim iSepetim1=new  Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));
                   Sepetim iSepetim2=new  Sepetim(Convert.ToInt32(txtSepet2ElmaSayisi.Text),Convert.ToInt32(txtSepet2ArmutSayisi.Text));
                  if (iSepetim1>iSepetim2)
                  {
                        MessageBox.Show("Buyuk");
                  }
                  else
                  {
                        MessageBox.Show("Buyuk Degil");
                  }
            }
 
            private void btnKucukmu_Click(object sender, System.EventArgs e)
            {
                   Sepetim iSepetim1=new  Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));
                   Sepetim iSepetim2=new  Sepetim(Convert.ToInt32(txtSepet2ElmaSayisi.Text),Convert.ToInt32(txtSepet2ArmutSayisi.Text));
                  if (iSepetim1<iSepetim2)
                  {
                        MessageBox.Show("Kucuk");
                  }
                  else
                  {
                        MessageBox.Show("Kucuk Degil");
                  }
            }
 
            private void btnNegatifize_Click(object sender, System.EventArgs e)
            {
                   Sepetim iSepetim1=new  Sepetim(Convert.ToInt32(txtSepet1ElmaSayisi.Text),Convert.ToInt32(txtSepet1ArmutSayisi.Text));
                  Sepetim iSepetim3=new Sepetim();
                  iSepetim3=-iSepetim1;
                  txtSonucElmaSayisi.Text=iSepetim3.ElmaSayisi.ToString();
                  txtSonucArmutSayisi.Text=iSepetim3.ArmutSayisi.ToString();
            }

[/TD]
[/TR]
[/TABLE]
[/TD]
[/TR]
[TR]
[TD]
Kodlar uzun gibi gözüksede bu kodlarda yapılanlar sadece kendi sepetlerimizi yaratmak ve bazı yerlerde sepetlerimizi yaratırken sepetlerimizin içine elma ve armutlarımızı koymaktan ibarettir.[/TD]
[/TR]
[/TABLE]
Bu makalemde verdiğim örnekte hata yakalama fonksiyonları örnek makaleyi tamamlayıcı yapıda olduğu için kullanılmamıştır.
 

eSa

Dekan
Katılım
5 Kasım 2011
Mesajlar
9,782
Reaksiyon puanı
352
Puanları
263
Emeğine sağlık, güzel bir anlatım olmuş. C# ile ile ilgilenen arkadaşlara faydası olacağına inanıyorum.
 

ESERT

Öğrenci
Katılım
17 Mart 2012
Mesajlar
18
Reaksiyon puanı
0
Puanları
0
emeğine sağlık. Vb biliyorum ama c de öğrenmek istiyorum. Benim için çok faydalı olacak bi paylaşım tşkrlr.
 

aslanpayi

Doçent
Katılım
12 Ağustos 2009
Mesajlar
523
Reaksiyon puanı
1
Puanları
0
Başkasının yazdığı makalelerden copy/paste yöntemiyle paylaşımların altında nereden ve kimden aldığınızı belirtirseniz emek verene de haksızlık etmemiş olursunuz.
 

OnurSorhan

Doçent
Katılım
17 Temmuz 2012
Mesajlar
808
Reaksiyon puanı
0
Puanları
16
Amcamın Makaleleri ve Paylaşımları Oldugundan Gerek Duymadım
Ondan Öğrendiğim Şeylerle Şuan Programcılığğın İçindeyim
Ve Amcam Yapdığı Paylaşımlarda Adını Kullanmaz Teşkkürler :)
 
Üst