Menu

C++ Operatör Aşırı Yükleme: Özel +, == ve << Operatörleri

C++ operatör aşırı yükleme, kendi türlerinizin +, == ve << gibi yerleşik operatörlerle çalışmasını sağlar. Üye ve üye olmayan fonksiyon kurallarını, karşılaştırma ve akış operatörlerini nasıl aşırı yükleyeceğinizi ve dönüş türleri ile atama operatörü etrafındaki tuzakları öğrenin.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Türlerinizi Yerleşik Gibi Hissettirin

std::string türünün birleştirme için a + b ve yazdırma için cout << s yazmanıza izin verdiğini zaten biliyorsunuz. Bunlar özel derleyici hileleri değildir - tuhaf adlara sahip sıradan fonksiyonlardır. Operatör aşırı yükleme, sizin sınıflarınızın aynı söz dizimine bağlanmasını sağlayan özelliktir; böylece bir Vector2 veya Money türü tam olarak bir int gibi toplanabilir, karşılaştırılabilir ve yazdırılabilir.

Mekanizma bir kez gördüğünüzde basittir: a + b gibi bir ifade bir kısaltmadır. Derleyici bunu operator+ adlı bir fonksiyona yapılan çağrı olarak yeniden yazar ve işlenen türleriyle eşleşen birini arar. Bu fonksiyonu sınıfınız için tanımlayın ve a + b aniden çalışmaya başlar. Bu aslında özelleşmiş bir fonksiyon aşırı yükleme biçimidir - oradaki aynı ad çözümleme kuralları geçerlidir, sadece operatör biçimli adlarla.

Fonksiyonun her iki işleneni de const& ile aldığına dikkat edin: aritmetik, girdilerini değiştirmemelidir ve referanslar kopyalamayı önler. Yeni bir Vector2 değer olarak döndürür - p + q, tıpkı 2 + 3'ün 2'yi değiştirmemesi gibi, p veya q'ya dokunmadan taze bir sonuç üretmelidir.

Üye vs Üye Olmayan

Bir operatörü tanımlayabileceğiniz iki yer vardır: sınıfın bir üyesi olarak veya serbest (üye olmayan) fonksiyon olarak. Üye olarak, sol işlenen örtük this'tir, dolayısıyla ikili bir operatör yalnızca bir açık parametre alır:

Parametre listesinden sonraki const önemlidir: a + b, a'yı değiştirmemelidir, bu yüzden üye const olarak işaretlenir. Doğası gereği sol işlenene bağlı olan ve onun üzerinde dönüşüme ihtiyaç duymayan operatörler için üye biçimini kullanın - +=, [], (), -> ve -x veya ++x gibi tekli operatörler.

Üyelerdeki sorun: sol işlenen dönüştürülemez. Yukarıdaki üye operator+ ile a + 50 çalışır (50, sağ taraf için Money'ye dönüşür), ancak 50 + a derlenemez - sol işlenen 50 bir int'tir ve int'e bir üye fonksiyon ekleyemezsiniz. Üye olmayan bir operatör bunu düzeltir, çünkü işlenenlerin ikisi de açık parametredir ve ikisi de dönüştürülebilir:

Pratik kural: simetrik ikili operatörleri (+, ==, *) üye olmayan yapın ki dönüşümler her iki tarafta da çalışsın; sol işleneni değiştirmesi gereken veya ona bağlı olan operatörleri (+=, [], =) üye yapın.

Akış Operatörünü Aşırı Yükleme

Açık ara en sık aşırı yüklenen operatör, yazdırma için kullanılan <<'dir. Bunu sınıfınızın bir üyesi yapamazsınız, çünkü sol işlenen sizin türünüz değil bir std::ostream'dir (cout gibi) ve ostream'in sahibi siz değilsiniz. Bu yüzden o her zaman, akışı sabit olmayan referansla alıp geri döndüren üye olmayan bir fonksiyondur:

Bunu işe yarar kılan iki ayrıntı vardır. Akış referansla (ostream&) geçirilir ve döndürülür - akışlar kopyalanamaz ve aynı akışı döndürmek, cout << "p = " << p << "\n" ifadesini zincirlemenizi sağlayan şeydir. Her <<, bir sonraki <<'in bağlanacağı bir şeyi olsun diye akışı döndürür. return os; ifadesini unutursanız zincirleme bozulur.

Karşılaştırma Operatörleri

Nesnelerinizi ==, < ve benzerleriyle karşılaştırmak için karşılaştırma operatörlerini aşırı yükleyin. C++20'den önce her birini elle yazardınız; ana tuzak, operator<'in bir bool döndürmesi ve tutarlı bir sıralama tanımlaması gerektiğidir:

Altı karşılaştırmanın (==, !=, <, <=, >, >=) tümünü elle yazmak sıkıcı ve hataya açıktır. C++20, üç yönlü karşılaştırma operatörü <=>'i ("uzay gemisi") ekledi. Bunu == ile birlikte varsayılana ayarlamak, tüm karşılaştırmaları sizin için üretir:

= default, derleyiciye üyeleri bildirim sırasına göre karşılaştırmasını söyler ki bu da tam olarak elle yazacağınız sözlüksel sıralamadır. Modern derleyicilerde bunu tercih edin.

Atama Operatörü ve Tuzakları

operator= (kopya atama) özeldir: derleyici sizin için bir tane üretir ve basit sınıflar için bu varsayılan doğrudur. Yalnızca sınıfınız bir kaynağı - ham bellek, bir dosya tutamacı - yönettiğinde ve üye üye kopyalamanın yanlış olacağı durumda kendinizinkini yazmanız gerekir. Standart imza, atamaların zincirlenebilmesi için (a = b = c) *this'i referansla döndürür:

Bu kısa fonksiyonda iki tuzak yaşar. Birincisi, kendine atama kontrolü if (this == &other): o olmadan a = a, delete[] data yapar ve ardından az önce serbest bırakılan other.data'dan okur - tanımsız davranış. İkincisi, sıra önemlidir - elle yazılmış bir sürümde, yenisini güvenle kopyalamadan önce eski tamponu silmemelisiniz (gerçek bir uygulama genellikle önce bellek ayırır veya copy-and-swap deyimini kullanır, böylece başarısız bir bellek ayırma nesneyi bozulmamış bırakır).

Daha geniş bir tuzak: operatörleri şaşırtıcı şekillerde aşırı yüklemeyin. Sol işlenenini gizlice değiştiren bir operator+ veya simetrik olmayan bir operator==, her okuyucunun kafasını karıştırır ve olağan anlamları varsayan standart kütüphane kodunu bozar. Operatörleri yalnızca işlem, türünüz için gerçekten "toplama benzeri" veya "eşitlik benzeri" olduğunda aşırı yükleyin.

Sıradaki: Erişim Belirteçleri

Her örneğin veri üyelerini private tutup davranışı küçük bir genel yüzey - yapıcılar, operatörler ve birkaç metot - aracılığıyla nasıl açığa çıkardığına dikkat edin. Dış dünyaya görünür olan ile sınıfın içinde gizli kalan arasındaki bu sınır, erişim belirteçleri ile denetlenir: public, private ve protected. Sırada her birinin tam olarak neye izin verdiğine, genel metotlu private verinin neden iyi kapsülleme için varsayılan olduğuna ve protected'in kalıtıma nasıl uyduğuna bakacağız.

Sıkça Sorulan Sorular

C++'ta operatör aşırı yükleme nedir?

Operatör aşırı yükleme, +, == veya << gibi yerleşik operatörlerin kendi türleriniz için ne anlama geldiğini tanımlamanıza olanak tanır. Özel adlı bir fonksiyon yazarsınız - operator+, operator== vb. - ve operatör sizin sınıfınızın işlenenleriyle göründüğünde derleyici bunu çağırır. string + string ifadesinin birleştirme yapması ve cout << obj ifadesinin özel bir nesneyi yazdırması bu sayededir.

C++'ta operatörler üye fonksiyon mu yoksa üye olmayan (friend) fonksiyon mu olmalı?

Sol işlenen kendi sınıfınız olduğunda ve dönüşüm gerekmediğinde bir üye fonksiyon kullanın (ör. +=, [], ()). Sol işlenen yerleşik bir tür olabildiğinde veya her iki tarafta da simetrik dönüşümler istediğinizde bir üye olmayan fonksiyon (genellikle friend) kullanın; operator<< için bu zorunludur, çünkü sol işlenen sizin sınıfınız değil bir std::ostream'dir.

Hangi C++ operatörleri aşırı yüklenemez?

:: (kapsam çözümleme), . (üye erişimi), .* (üye işaretçisi erişimi), ?: (üçlü) ve sizeof operatörlerini aşırı yükleyemezsiniz. Ayrıca tamamen yeni operatörler icat edemez veya bir operatörün işlenen sayısını ya da önceliğini değiştiremezsiniz - + ister int toplasın ister sizin Vector2 türünüzü, her zaman aynı öncelikli ikili bir operatördür.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA