C++ Dilinde Operator Overloading
- Yusuf Hançar
- Oct 11, 2023
- 4 min read
Updated: Jan 18, 2024
C++ dilinde bu yazıya kadar sınıf tasarımı, özel üye fonksiyonlar, sınıf nesnelerinin oluşturulma ve kullanım senaryolarından bahsettik. Sınıf türünden oluşturulan nesneler üzerinde birtakım işlemler yapabilmek için kullanılan yapılardan bahsedeceğiz.
Operatör overloading tanımını, kullanım senaryolarını ve nerelerde ihtiyaç duyulduğundan bahsetmeden önce overloading kelimesini tanımlamaya çalışalım. Overloading, aşırı yükleme olarak çokça duyduğumuz ve aynı isimden birden fazla işlev ve/veya operatör tanımlamamıza olanak tanıyan yapıdır. Temel olarak operator overloading ve fonksiyon overloading olarak iki ana başlıkta incelenmektedir. Bizim bu yazıda ele alacağımız operator overloading olacaktır. Bu yapıları kullanırken doğal olarak bazı kurallara uymak zorunda kalacağız.
operator overloading için operator anahtar sözcüğü kullanılması şarttır.
Kullanıldığı durumda ek run-time maliyeti olmayan yapılardır.
Sadece sınıf türleri için kullanılabilirler.
Kullanılan operatörün operandlarından en az bir tanesi sınıf türünden olmalıdır. Primitive(int, double...) türler için geçerli değildir.
Global ya da non-statice member olarak tanımlanan fonksiyonlara da uygulanabilirler.
Olmayan bir operator overload edilemez. (@ operatörü gibi)
Bir sınıfın static üye fonksiyonu overload edilemez. Static üye fonksiyonlar sınıfa ait instance ile değil sınıfın kendisiyle ilişkilendirilmesidir. Çağrı yapılırken sınıfın ismi kullanıldığı için derleyici tarafından overload edilmesi durumu kabul edilmeyecektir.
C++ dilinin kuralları gereği variadic fonksiyonlar overload edilemezler. Overload kuralları gereği değişken sayıda argüman ile bunu sağlamak mümkün değildir. Modern C++ ile gelen özelliklerle buna gerek kalmadan tasarım yapabilmekteyiz.(visit, tuple, variant...)
Bazı operatörler üye operatör ile overload edilmek zorundadır. Bunlar; atama(=), index([]), ve fonksiyon çağrı operatörü(()) gibi operatörlerdir.
Operatörlerin operand sayısı değiştirilemez.
Operatörlerin öncelik seviyesi ve öncelik yönü değiştirilemez.
Operatör fonksiyonları default argument alamazlar.
Temel kurallar bu şekilde sıralanabilir. Şimdi bunları örneklendirerek pekiştirmeye çalışalım...
#include <string>
#include <iostream>
using namespace std;
int main ()
{
string s1{"smart"}, s2{ "code" };
s1 > s2;
s1 == s2;
cout << s1 << endl;
s1[0] = 'S';
cout << s1;
}
*****************************
AÇIKLAMA: string nesnesinin cout ile çıkış akımına yazdırılabilmesini sağlayan basic_ostreanm ve basic_istream yazılmasıdır. Aynı şekilde [], ==
ve > operatorleri de overload edildiği için bunu yazdırmamıza olanak tanınır.
*****************************
CEVAP:
*****************************
<string> başlık dosyasında yer alan string sınıfına ait ostream ve istream operator overload yapıları : " https://en.cppreference.com/w/cpp/string/basic_string/operator_cmp "
template<class CharT, class Traits, class Allocator>
std::basic_ostream<CharT, Traits>&operator<<(std::basic_ostream<CharT, Traits>& os,
const std::basic_string<CharT, Traits, Allocator>& str );
template<class CharT, class Traits, class Allocator>
std::basic_istream<CharT, Traits>&operator>>(std::basic_istream<CharT, Traits>& is,
std::basic_string<CharT, Traits, Allocator>& str );
Aynısı bir sınıf nesnesi olsaydı <<, +, - gibi operatörleri overload yazmadan kullanamazdık.
#include <iostream>
class SmartCode {
public:
SmartCode(int val) : m_data(val) {}
private:
int m_data;
};
int main()
{
SmartCode sc(23);
std::cout << sc << std::endl;
return 0;
}
*****************************
AÇIKLAMA: sc bir sınıf nesnesi olduğu için ve << operatörü için overload'ı olmadığı için hata verecektir.
*****************************
CEVAP: no match for operator<< ...
*****************************
<< operatörü için bu şekilde overload yazarsak geçerli olacaktır.
friend std::ostream& operator<<(std::ostream& out, const SmartCode& obj)
{
out << obj.m_data;
return out;
}
Sınıf içerisinde kullanılabilecek operatörler ve ilgili temel fonksiyonlarına ait örnekler :
#include <iostream>
using namespace std;
class SmartCode {
private :
int mx;
public :
SmartCode() = default;
explicit SmartCode (int);
SmartCode& operator++(); //prefix
SmartCode& operator++(int); //postfix
SmartCode& operator--(); //prefix
SmartCode& operator--(int); //postfix
bool operator!()const;
//işaret operatoru + ve -
SmartCode operator+()const;
SmartCode operator-()const;
//işlemli atama operator fonksiyonları
SmartCode& operator+=(const SmartCode&);
SmartCode& operator-=(const SmartCode&);
SmartCode& operator*=(const SmartCode&);
SmartCode& operator/=(const SmartCode&);
SmartCode& operator%=(const SmartCode&);
//karşılaştırma operator fonksiyonları(global fonksiyonlar)
friend bool operator<(const SmartCode&, const SmartCode&);
friend bool operator<=(const SmartCode&, const SmartCode&);
friend bool operator>(const SmartCode&, const SmartCode&);
friend bool operator>=(const SmartCode&, const SmartCode&);
friend bool operator==(const SmartCode&, const SmartCode&);
friend bool operator!=(const SmartCode&, const SmartCode&);
//aritmetik operatorler
friend SmartCode operator+(const SmartCode&, const SmartCode&);
friend SmartCode operator-(const SmartCode&, const SmartCode&);
friend SmartCode operator*(const SmartCode&, const SmartCode&);
friend SmartCode operator/(const SmartCode&, const SmartCode&);
friend SmartCode operator%(const SmartCode&, const SmartCode&);
};
int main ()
{
return 0;
}
post ve prefix ile ilgili kullanım senaryosu aşağıdaki tabloda ifade edilmiştir.
type | declaration | return | result |
prefix | SmartCode& operator&++() | *this | bir fazlası |
postfix | SmartCode& operator&++(int) | SmartCode | kendisi |
C++ dilinde öncelikli olan operatörler vardır. Bunlardan en öncelikli olanı == operatörüdür. == operatörünün de sırasıyla; >, <, >= ve <= operatörlerine göre önceliği vardır.
#include <iostream>
int main()
{
int a = 1;
int b = 2;
int c = 1;
bool result = a == b < c;
std::cout << boolalpha << "result : " << result << std::endl;
}
*****************************
AÇIKLAMA:
*****************************
CEVAP: true
*****************************
C++ dilinde sınıfın üye fonksiyonu olan tüm atama operatör fonksiyonları sınıf türünden reference döndürür. Yani *this döndürür.
class SmartCode {
public:
int sc;
SmartCode(int val) : sc(val) {}
SmartCode& operator+=(const SmartCode& oth)
{
sc += oth.sc;
return *this;
}
};
int main()
{
SmartCode a(3);
SmartCode b(1);
a += b;
std::cout << "a: " << a.sc << std::endl;
return 0;
}
*****************************
AÇIKLAMA: *this döndürür yani this->mx anlamındadır.
*****************************
CEVAP: 4
*****************************
#include <iostream>
class SmartCode {
public:
int sc;
SmartCode(int val) : sc(val) {}
SmartCode& operator+=(const SmartCode& oth)
{
sc += oth.sc;
return *this;
}
};
inline SmartCode operator+(const SmartCode& a, const SmartCode& b)
{
SmartCode tmp{ a };
tmp += b;
return tmp;
}
int main()
{
SmartCode a(3);
SmartCode b(1);
SmartCode c = a + b;
std::cout << "c: " << c.sc << std::endl;
return 0;
}
*****************************
AÇIKLAMA:
*****************************
CEVAP:
*****************************
Buradaki geçici nesneye isim vermeden de fonksiyondan döndürebiliriz.
inline SmartCode operator+(const SmartCode& a, const SmartCode& b)
{
return SmartCode{ a } += b;
}
operatör << ve operatör >> kullanımı :
#include <iostream>
using namespace std;
class SmartCode {
private :
int m_month, m_day, m_year;
public:
SmartCode(int month, int day, int year)
{
m_month = month;
m_day = day;
m_year = year;
}
friend ostream& operator<<(ostream& os, const SmartCode& dt);
friend istream& operator>>(istream& is, SmartCode& dt);
};
ostream& operator<<(ostream& os, const SmartCode& oth)
{
os << oth.m_month << '/' << oth.m_day << '/' << oth.m_year;
return os;
}
istream& operator>>(istream& is, SmartCode& ith)
{
is >> ith.m_month >> ith.m_day >> ith.m_year;
return is;
}
int main()
{
SmartCode date(29, 5, 94);
cout << date;
}
*****************************
AÇIKLAMA:
*****************************
CEVAP:
*****************************
() operatörünün overload edilmesi :
class SmartCode {
public:
int operator()(int x, int y)
{
return x + y;
}
};
int main()
{
SmartCode add;
int res = add(3, 5);
return 0;
}
*****************************
AÇIKLAMA: sınıf nesnelerinin () operatörüyle çağırılması için...
*****************************
CEVAP:
*****************************
class SmartCode {
public:
int operator()(int idx)
{
return arr[idx];
}
private:
std::array<int, 5> arr{1, 2, 3, 4, 5};
};
int main()
{
SmartCode sc;
int res = sc(2);
return 0;
}
*****************************
AÇIKLAMA:
*****************************
CEVAP:
*****************************
Son olarak operatorlerdeki önceliklerle ilgili bilgi amaçlı cpp reference sitesindeki önceliklendirme tablosuna da göz atmak faydalı olacaktır. " https://en.cppreference.com/w/cpp/language/operator_precedence "

Comments