Üye erişim operatörlerini aşırı yükleme ->,. *


130

Ben, üye erişim operatörler haricinde çoğu operatör aşırı yüklenmesini anlıyorum ->, .*, ->*vb

Özellikle, bu operatör işlevlerine ne aktarılır ve ne döndürülmelidir?

Operatör işlevi (örneğin operator->(...)) hangi üyeye başvurulduğunu nasıl biliyor? Bilebilir mi Bilmesi bile gerekiyor mu?

Son olarak, dikkate alınması gereken sabit hususlar var mı? Örneğin, böyle bir şeyi aşırı yüklerken operator[], genellikle hem const hem de const olmayan bir sürüme ihtiyacınız olacaktır. Üye erişim operatörleri const ve const olmayan sürümler gerektirir mi?


1
Sanırım yukarıdaki C ++ - SSS, yukarıdaki
S'de

constve constsürüm olmayan sürümler gereklioperator-> değildir , ancak her ikisinin de sağlanması yararlı olabilir.
Fred Foo


9
@Als: SSS nasıl aşırı yükleneceğini ->*ve .*. Aslında onlardan bahsetmiyor bile! Sıkça Sorulan Sorularda bulunabileceklerini sanmıyorum, ancak bu soruyu SSS'den memnuniyetle bağlayabilirim. Lütfen bunu SSS'nin bir kopyası olarak kapatmayın!
sbi

@sbi, bu soruya (harika) SSS sayfasından bir bağlantı bulamadım ve yinelenen bir soru sormaya başladım. Daha açık hale getirebilir misin? (zaten açıksa özür dilerim).
P i

Yanıtlar:


145

->

Bu gerçekten zor olan tek şey. Statik olmayan bir üye işlevi olmalıdır ve hiçbir argüman almaz. Dönüş değeri üye aramasını gerçekleştirmek için kullanılır.

Dönüş değeri bir işaretçi değil, sınıf türünün başka bir nesnesiyse, sonraki üye araması da bir operator->işlev tarafından işlenir . Buna "detaya inme davranışı" denir. Dil operator->, sonuncusu bir işaretçi döndürene kadar çağrıları birbirine zincirler .

struct client
    { int a; };

struct proxy {
    client *target;
    client *operator->() const
        { return target; }
};

struct proxy2 {
    proxy *target;
    proxy &operator->() const
        { return * target; }
};

void f() {
    client x = { 3 };
    proxy y = { & x };
    proxy2 z = { & y };

    std::cout << x.a << y->a << z->a; // print "333"
}

->*

Bu, özel bir şey olmadığı için sadece aldatıcıdır. Olmayan aşırı sürümü sınıf sol taraftaki tipi ve sağdaki elemanı türüne ibrenin bir nesneye işaretçi bir nesne gerektirir. Ancak aşırı yüklediğinizde, istediğiniz argümanları alabilir ve istediğiniz her şeyi iade edebilirsiniz. Statik olmayan bir üye olmasına bile gerek yok.

Başka bir deyişle, bu sadece gibi normal ikili operatörüdür +, -ve /. Ayrıca bkz: özgür operatör -> * kötülüklüdür?

.* ve .

Bunlar aşırı yüklenemez. Sol taraf sınıf türünde olduğunda zaten yerleşik bir anlam vardır. Belki onları sol taraftaki bir işaretçi olarak tanımlayabilmek biraz mantıklı olabilirdi, ancak dil tasarım komitesi bunun yararlı olmaktan çok kafa karıştırıcı olacağına karar verdi.

Aşırı yükleme ->, ->*, .ve .*bir ifade tanımsız olacaktır nerede sadece durumlarda doldurabilir, bu aşırı yük olmaması ile geçerli olacak bir ifadenin anlamını asla değiştiremezsin.


2
Son ifadeniz tamamen doğru değil. Örneğin, aşırı yüklenmediğinde newbile geçerli olsa bile operatörü aşırı yükleyebilirsiniz .
Matt

6
@Matt iyi, newher zaman aşırı yüklenmiştir veya aşırı yükleme kuralları buna gerçekten uygulanmaz (13.5 / 5: Tahsis ve serbest bırakma işlevleri, operatör yeni, operatör yeni [], operatör silme ve operatör silme [], 3.7'de tamamen açıklanmıştır. 0,4. Bu alt geri kalanı bulunan özellikler ve kısıtlamalar. açıkça 3.7.4 belirtilmediği sürece kendileri için geçerli) Ama tekli aşırı olmayan &veya ikili &&, ||ya ,, veya aşırı yükleri ekleyerek operator=veya bir unscoped için her şey sadece aşırı numaralandırma türü, bir ifadenin anlamını değiştirebilir. Açıklama netleştirildi, teşekkürler!
Potatoswatter

41

Operatör -> özeldir.

"Ek, atipik kısıtlamalara sahiptir: Aynı zamanda bir işaretçi referans operatörüne sahip bir nesneyi (veya bir nesneye başvuruyu) döndürmeli veya işaretçi yönlendirme operatör okunun işaret ettiği şeyi seçmek için kullanılabilecek bir işaretçi döndürmelidir. " Bruce Eckel: Düşünme CPP Cilt-bir: operatör->

Ekstra işlevsellik kolaylık sağlamak için sağlanmıştır, böylece aramanıza gerek kalmaz

a->->func();

Şunları yapabilirsiniz:

a->func();

Bu, operatörü -> diğer operatör aşırı yüklerinden farklı kılar.


3
Bu cevap daha fazla övgüyü hak ediyor, Eckel'in kitabını bu bağlantıdan indirebilirsiniz ve bilgiler birinci cildin 12. bölümünde.
P i

26

Üye erişimini aşırı yükleyemezsiniz .(yani ne yaptığının ikinci kısmı ->). Bununla birlikte, tekli referans alma operatörünü *(yani ne yaptığının ilk kısmı ->) aşırı yükleyebilirsiniz .

C ++ ->operatörü temelde iki adımın birleşimidir ve bunun x->yeşdeğer olduğunu düşünüyorsanız bu açıktır (*x).y. C ++, sınıfınızın bir örneği (*x)olduğunda parça ile ne yapacağınızı özelleştirmenize olanak tanır x.

->Aşırı yükleme için anlambilim biraz gariptir çünkü C ++ normal bir işaretçi döndürmenize (sivri uçlu nesneyi bulmak için kullanılacaktır) veya bu sınıf aynı zamanda bir ->operatör sağlıyorsa başka bir sınıfın bir örneğini döndürmenize izin verir . Bu ikinci durumda, başvurulan nesnenin aranması bu yeni örnekten devam eder.


2
Harika açıklama! Sanırım bu ->*, formuna eşdeğer olduğu için aynı anlama geliyor (*x).*?
Bingo

10

->İşaret ediliyor ne üye bilmez operatör, sadece gerçek üye erişimini gerçekleştirmek için bir nesne sağlar.

Ek olarak, const ve const olmayan sürümler sağlayamamanız için hiçbir neden göremiyorum.


7

-> () operatörünü aşırı yüklediğinizde (burada hiçbir argüman aktarılmaz), derleyicinin aslında yaptığı şey -> bir türe gerçek bir işaretçi döndürene kadar özyinelemeli olarak çağırmaktır. Daha sonra doğru üyeyi / yöntemi kullanır.

Bu, örneğin, gerçek işaretçiyi kapsayan bir akıllı işaretçi sınıfı oluşturmak için kullanışlıdır. Aşırı yüklenmiş operatör-> çağrılır, ne yaparsa yapsın (örneğin, iş parçacığı güvenliği için kilitleme), dahili göstericiyi döndürür ve sonra derleyici bu dahili işaretçi için -> çağırır.

Sabitliğe gelince - yorumlarda ve diğer cevaplarda cevaplandı (her ikisini de yapabilirsiniz ve sağlamalısınız).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.