Fonksiyonlar üzerine bu konuda ne yazık ki yeterli bir Türkçe kaynak göremedim. Bu sebeple bu yazının birçok kişi tarafından faydalı bulunacağına inanıyorum. Fonksiyon oluştururken bahsedilen void veya veri türü belirtilmesi dışında apayrı bir işleve sahibiz. İnceleyelim..
Fonksiyon Şablonları
Fonksiyon şablonları, temelde belli olmayan veri türlerine sahip girdiler için kullanılırlar. Lakin bu girdiler mutlaktır ki bir yerde belirtilmek zorundalar. Fakat bu alanlar program içerisinde aynı işlemin yapılacağı fakat farklı veri türlerinin kullanılacağı yerler olabilir. Basit bir görselle ifade etmek gerekirse;
Aynı toplama işlemi içerisinde hem int hemde double veri türünü toplamamız gerekirse ne yapabiliriz? Bunu toplama işleminden bambaşka şekilerde de değerlendirebiliriz fakat en basit hali ile toplama işlemini ele alarak işe başlayalım. Öncelikle bu yapıya alışmalıyız. Yapıda standart fonksiyonlardan biraz farklı bir hava söz konusu;
template <class veriTuruAdi>
veriTuruAdi fonksiyonAdi(veriTuruAdi a, veriTuruAdi b) {
return a+b;
}
int main() {
cout << "INT: " << fonksiyonAdi<int>(5,6);
cout << endl;
cout << "DOUBLE: " << fonksiyonAdi<double>(3.2,4.5);
}
Şimdi üstte oluşturduğumuz yapımızı özelden genele inceleyelim;
1. Yepyeni bir kelime: template
template <class veriTuruAdi>
Bu satırın amacı aslında programa bir tasarım sınıfımızın olduğunu ve bu tasarım sınıfımızın adının veriTuruAdi olduğunu anlatmaya çalışıyoruz. Yani bizim artık bir veriTuruAdi adında bir sınıfımız var.
2. Bambaşka gibi gözüken ama aynı tip fonksiyon
veriTuruAdi fonksiyonAdi(veriTuruAdi a, veriTuruAdi b) {
return a+b;
}
Bu alanda ise biz normalde fonksiyona bir veri türü belirlerken int, double gibi ifadeleri kullanıyorduk. Fakat artık kendi oluşturduğumuz tasarım sınıfımızı buraya dahil edebiliriz. O halde oluşturduğumuz veriTuruAdi adındaki sınıfımızı standart fonksiyonlarımızda yer alan int, double gibi ifadelerin yerine yazabiliriz. Ee hal böyle olunca parantez içindeki ifadelerimizin veri türlerinin de artık bizim belirlediğimiz veri türleri olmamaları için hiçbir sebep yok. Süslü parantezlerimizin içinde yer alan komutlarımız ise standart C++ komutlarımızdan fazlası değil.
3. Çıktıyı nasıl alacağız?
cout << "INT: " << fonksiyonAdi<int>(5,6);
Çıktı alırken artık bir veri türü belirleyebiliyoruz. Yani girdilerimiz eğer int ise int gibi davranabilir, double ise double gibi davranabilir veya farklı her neyse o konumu dahil edebiliriz. (Mesela işi abartıp string kütüphanesini dahil ettikten sonra int veya double değilde bir string girebilir veya bir true/false değeri döndürmek adına bool ifadesine yer verebilirdik! Evet, tam olarak bunu yapamamamız için bir neden artık yok!)
Genel kuralımız tam olarak bu! Şimdi bir tane de örnek yapı oluşturalım.
template <class X, class Y>
bool esitMi(X a, Y b) {
return (a==b);
}
int main() {
if(esitMi<int,double>(5,5.0000)) {
cout << "Esit!";
} else {
cout << "Esit Degil!";
}
}
Örneğimizde bool operatörü ile gelen iki farklı veri türüne sahip değerin eşit olup olmadığını kontrol ettirdik.