2010-12-19 11 views
5

Benim şu anki atama adım adım elde listesini yazıyor. Liste, yineleyici sınıfı oluşturmak kadar çok sorun oluşturmuyor.anlamsal - listelerinde> operatör (ve genel C++) ile

Birkaç kaynaktan, yineleyici sınıfımda tanımlamak için iki operatörün olduğunu gördüm: operator* ve operator->.

Şimdiye kadar harika! Benim yineleyici yapısını düşünürsek ListElem

// Nested struct of List 
struct ListElem 
{ 
    T data; 

    ListElem *next; 
    ListElem *prev; 
}; 

olmak öylesine

// Nested class of List 
class _Iter 
{ 
private: 
    ListElem *pCurr; 
    const List *pList; 

public: 
    _Iter(ListElem *pCurr, const List *list) 
     : pCurr_(pCurr), pList(list) 
    {} 

    T& operator*() { return pCurr_->data; } 
    T* operator->() { return &**this; } 
}; 

olduğunu ben & (* pCurr _-> verilerine yol açacak bu çifte dereferencing olarak (kitlesel yanlış bir şey yapıyorum görebilirsiniz (bu, kabul edilemez)

Asıl problemim, aslında bu durumda ne yapması gerektiğini anlamak değil, kullanıcı ListElem sınıfına erişim izni vermeli mi? sadece

yaz
ListElem *operator->() { return pCurr_; } 

yerine bir işaretçi döndürmek?

operator*() // Return data pointed to by iterator; pCurr_->data; 
operator->() // Grant access to data-holding structure; pCurr; 

bu doğru mu, yoksa ne almıyorum: listemde (ve umarım STL listeleri) kullanılan bu iki operatörlerin Benim anlayış bu? (Ve ->, uygun bir ada sahip mi?)

cevap

5

Ne yaparsanız yapın, (*something).somethingElsesomething->somethingElse denk olmalıdır. İkincisi, eski için kısa bir sözdizimi. *this sadece tip _Iter* değil _Iter, hiçbir operator*() çağrı yapılır sahiptir this dereferences çünkü nedenle,

T& operator*() { return pCurr_->data; } 
T* operator->() { return &**this; } 

gayet iyi.Sonra *this dereferans, böylece pCurr->data olsun, sonra adresini alırsınız, böylece & pCurr-> veri alırsınız. Ama sadece yazmak için çok daha net olacaktır: operator*() döner T&, operator->() T* dönmesi gerekir, o ne için tasarlanmıştır çünkü Şimdi
T& operator*() { return pCurr_->data; } 
T* operator->() { return &pCurr->data; } 

, bu

ListElem *operator->() { return pCurr_; } 

yanlıştır. ListIt yerine kendi verilerinin yerine veriyi vermek istiyorsanız (ki bu tasarıma göre anlam kazanabilir ya da olmayabilir, fakat sizin durumunuza benzemiyorsa), bunu elde etmek için operator*()'u da yeniden tanımlamanız gerekir:

ListElem& operator*() { return *pCurr_; } 
ListElem *operator->() { return pCurr_; } 

Bu, bir dil gereksinimi olmadığını unutmayın, aynı zamanda, sınıfınızı kafa karıştırıcı arabirimden kaçınmak için nasıl tasarladığınızdır.

+0

Gerçekten de, bu 'aslında' bir işaretçi olduğunu unutuyorum. Çok sinir bozucu: D – IAE

1

operator->, yineleyici tarafından gösterilen nesneye bir işaretçi verir, bu durumda (görünüşte) pCurr_->data.

T *operator->() { return &(pCurr_->data); } 

bir değer veya referans olarak operator*() tarafından döndürülen nesnenin adresine döndürmelidir.

T &operator*() { return pCurr_->data; } 
// or 
T &operator*() { return *operator->(); } 

operator->() ve operator* değeri yerine referans ile bir nesne, geri dönmek için gereklidir (işaretçiler için olan davranış) ile adım adım elde -> uygulamaktır. Eğer gerekli işlevselliği elde etmek Yineleyici içinde List bir işaretçi saklamak gerekmez

Not.

+1

Sorunu ListElem yapısıyla güncelledim. Ve aaaah, Foo'ya bir işaretçi vererek, şimdi tüm Foos yöntemlerini kullanabiliriz! Bu yüzden ListElem'in kendisini iade etmiyorum, ancak Foo veri üyesinin işlevselliğini kullanıcıya aktarıyorum! Bu mantıklı. – IAE

+0

@SoulBeaver: cevabımı güncelledi. –

+0

Evet, kullanılacak istemcinin temel verilerini döndürüyorsunuz. Yineleyicilerin göstericilerin genelleştirilmesi olduğunu ve benzer şekilde bir veri maddesine işaret ettiklerini (bazen çok dolaylı olarak; çok sayıda yineleyici türü bulunduran polimorfik nesneler için işaretçileri tutan bir yineleyici tasarladım) unutmayın. –

1

Kişisel Birinci kural

(*iter).hello(); 
iter->hello(); 

de aynı şeyi yapması gerektiğini olmalıdır. Bu kullanıcının beklediği şey. Geri dönen ListElem kullanıcıya hiçbir şey vermez. Kullanıcı, ListElem uygulamasının ayrıntılarını bile bilmemelidir.