Operatör aşırı yükleme: üye işlevi mi üye olmayan işlev mi?


121

Üye işlevi olarak tanımlanan aşırı yüklenmiş bir operatörün asimetrik olduğunu okudum, çünkü yalnızca bir parametreye sahip olabilir ve otomatik olarak geçirilen diğer parametre thisişaretçi. Dolayısıyla bunları karşılaştırmak için bir standart yok. Öte yandan, aşırı operatörü olarak ilan friendolduğunu simetrik biz aynı türden iki argüman geçmek ve dolayısıyla, bunlar karşılaştırılabilir çünkü.

Sorum şu ki, bir işaretçinin değerini bir referansla hala karşılaştırabildiğimde, neden arkadaşlar tercih edilir? (asimetrik bir sürüm kullanmak simetrik ile aynı sonuçları verir) Neden STL algoritmaları yalnızca simetrik sürümleri kullanır?


11
Sorunuz gerçekten sadece ikili operatörler hakkında. Tüm aşırı yüklenmiş operatörler tek bir parametre ile sınırlı değildir. () Operatörü herhangi bir sayıda parametre alabilir. Öte yandan, tekli operatörler herhangi bir parametreye sahip olamaz.
Charles Salvia


Yanıtlar:


148

Eğer üye fonksiyonu olarak operatörünüz aşırı işlevi tanımlarsanız, o zaman derleyici gibi ifadeler çevirir s1 + s2içine s1.operator+(s2). Bu, operatör aşırı yüklenmiş üye işlevinin ilk işlenen üzerinde çağrıldığı anlamına gelir. Üye fonksiyonları böyle çalışır!

Peki ya ilk işlenen bir sınıf değilse? Örneğin, birinci işlenenin bir sınıf türü olmadığı bir operatörü aşırı yüklemek istiyorsak büyük bir sorun var double. Yani böyle yazamazsın 10.0 + s2. Ancak, gibi ifadeler için operatör aşırı yüklenmiş üye işlevi yazabilirsiniz s1 + 10.0.

Bu sıralama problemini çözmek için , operatör aşırı yüklenmiş işlevi üyelere frienderişmesi gerekiyorsa EĞER olarak tanımlarız private. SADECE özel üyelere erişmesi gerektiğinde bunu yapın friend. Aksi takdirde, kapsüllemeyi iyileştirmek için basitçe arkadaş olmayan üye olmayan işlevi yapın !

class Sample
{
 public:
    Sample operator + (const Sample& op2); //works with s1 + s2
    Sample operator + (double op2); //works with s1 + 10.0

   //Make it `friend` only when it needs to access private members. 
   //Otherwise simply make it **non-friend non-member** function.
    friend Sample operator + (double op1, const Sample& op2); //works with 10.0 + s2
}

Bunları okuyun:
İşlenenlerde küçük bir sıralama sorunu
Üye Olmayan İşlevler Kapsüllemeyi Nasıl İyileştirir?


2
" friendSadece özel
üyelere erişmesi gerektiğinde ve

4
@Abhi: Seçiminizi seçin: Geliştirilmiş Kapsülleme ve Tembel yazma alışkanlığı!
Nawaz

6
@matthias, tüm operatörler değişmeli değildir. Basit bir örnek a/b.
edA-qa mort-ora-y

3
Üye olmayan operatörlerinizi zorunlu kılmaktan kaçınmanın yaygın bir yolu, friendonları operasyon atama operatörleri açısından uygulamaktır (ki bu neredeyse kesinlikle kamu üyeleri olacaktır). Örneğin, T T::operator+=(const T &rhs)üye T operator(T lhs, const T &rhs)olarak tanımlayabilir ve ardından üye olmayan'ı olarak tanımlayabilirsiniz return lhs += rhs;. Üye olmayan işlev, sınıfla aynı ad alanında tanımlanmalıdır.
Adrian McCarthy

2
@ricky: Ama eğer lhs bir kopya ise (benim yorumumda olduğu gibi), o zaman lhs'nin değişmesi gerçeği önemli değil.
Adrian McCarthy

20

Mutlaka arasında bir ayrım değil friendo arasındadır olarak operatör aşırı ve üye fonksiyon operatör aşırı küresel operatör aşırı ve üye fonksiyon operatör aşırı yükleme.

Global operatör aşırı yüklemesini tercih etmenin bir nedeni , sınıf türünün ikili operatörün sağ tarafında göründüğü ifadelere izin vermek istemenizdir . Örneğin:

Foo f = 100;
int x = 10;
cout << x + f;

Bu, yalnızca aşağıdakiler için genel bir operatör aşırı yüklemesi varsa çalışır.

Foo operatörü + (int x, const Foo & f);

Global operatör aşırı yükünün mutlaka bir friendişlev olması gerekmediğini unutmayın . Bu, yalnızca özel üyelerine erişmesi gerektiğinde gereklidir Foo, ancak bu her zaman böyle değildir.

Ne olursa olsun, Foosadece bir üye işlevi operatörü aşırı yüklemesi olsaydı, örneğin:

class Foo
{
  ...
  Foo operator + (int x);
  ...
};

... o zaman sadece artı operatörünün solunda bir Fooörneğin göründüğü ifadelere sahip olabilirdik .


3
Üye ve arkadaş işlevleri yerine üye işlevler ile üye olmayan işlevler arasında ayrım yapmak için +1. Sanırım bugün "küresel veya ad alanı kapsamı" derdik.
Adrian McCarthy
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.