C ++ arkadaşına ya da arkadaşına değil


19

Bu dönem kolejde c ++ dersiyle nesne yönelimli bir programım var ve arkadaşlık fonksiyonlarını öğreniyorduk.

Kapsülleme ve Veri gizlemenin sağladığı güvenliği atlatma yeteneklerinden içgüdüsel olarak hoşlanmıyorum, internette birkaç makale okudum ve bazı insanlar bunun bazı meşru kullanımlarla iyi bir fikir olduğunu düşündüler.

Bir OOP uzmanı C ++ 'daki arkadaş işlevleri hakkında ne söylerdi? Sadece gözden geçirmeli miyim yoksa daha fazla öğrenmeli miyim?


@all: Müthiş cevaplar ve yorumlar, Bu öğrenmenin çok iyi bir yolu, bir ders kitabında bu tür detaylarda arkadaşlar hakkında bilgi edinmem mümkün değil.
nikhil

Yanıtlar:


13

Bu sınıfın C ++ sınıf üyeleriyle ilgili tüm işlevleri yapmak her zaman uygun değildir. Örneğin, skaler çarpımla vektör cebirinin bir uygulamasını düşünün. Yazmak istiyoruz:

 double a;
 Vector v, w;
 w = v * a;

Bunu bir üye işleviyle yapabiliriz:

public class Vector {
 ...
 Vector operator*(double a);
}

Ancak şunu da yazmak istiyoruz:

w = a * v

Bu, ücretsiz bir işlev gerektirir:

 Vector operator*(double a, Vector v)

friendAnahtar kelime, bu kullanımını desteklemek için C ++ eklenmiştir. Serbest işlev Vector sınıfı uygulamasının bir parçasıdır ve aynı üstbilgide bildirilmeli ve aynı kaynak dosyaya uygulanmalıdır.

Benzer şekilde friend, toplama ve yineleyici gibi sıkıca bağlı sınıfların uygulanmasını basitleştirmek için de kullanabiliriz . Yine, her iki sınıfı da aynı başlıkta bildirir ve aynı kaynak dosyaya uygularım.


3
Msgstr "Bu ücretsiz bir işlev gerektirir". Hayır inline Vector operator*(double a, Vector v) { return v*a; }. Aslında kanonik çözüm.
MSalters

1
@MSalters: İyi nokta. Kötü bir örnek seçtim. Satır içi işlevinizin tanım gereği ücretsiz bir işlev olduğunu düşünüyorum, ancak arkadaş beyanı gerekli değildir.
kevin cline

4
@ MSalters: Bu yalnızca * a ve v (x) 'e göre değişmeli olduğunda geçerlidir. Vektör bileşenleri
genelse

Bu oldukça teorik. Belki de değişmeyen tek yaygın vaka olabilir inline Vector operator*(double a, Vector v) { return -v*a; }ve bu yine de arkadaşlık gerektirmez.
MSalters

16

Arkadaş işlevleri kapsülleme açısından üye işlevlerinden farklı değildir. Bununla birlikte, özellikle şablonlar söz konusu olduğunda daha genel olma gibi başka avantajlar da sunabilirler. Ayrıca, bazı işleçler yalnızca serbest işlevler olarak belirtilebilir, bu nedenle üye erişimine sahip olmak istiyorsanız, yapmanız gerekir friend.

Bu daha iyidir friendortak olmak istemiyoruz şey yapmak zorunda daha tek işlevi. Bu, dünyanın tek bir işlev yerine onu kullanabileceği anlamına gelir.


Friend for +1 işlevleri kapsülleme açısından üye işlevlerinden farklı değildir. Bu sadece kamu üyesi işlevleri için geçerlidir.
TheFogger

1
@TheFogger: Muhtemelen, friendsadece tek bir TU'da bildirilen gibi "özel" bir işlev de olabilir .
DeadMG

5

Ne yaptığınız konusunda tutkuluysanız, C ++ hakkında her şeyi öğreniyor olacaksınız. Ne için kullanıldıklarını, nasıl kullanılacağını öğrenin ve sonra - ve ancak o zaman - kullanmamaya karar verin. En azından, C ++ 'nın bu yönünü kullanan başkasının kodunu okurken hazırlıklı olacaksınız.


5

" Bir OOP uzmanı ne derdi ... " Çoğunlukla C ++ 'da ne kadar uzman olduğuna, yani kendi spesifikasyonuna göre, saflık için bir dil değildir (ve olmak istemez).

OOP Zealotlar C ++ kullanmazlar (Smalltalk'i tercih ederler ve Java gibi).

Fonksiyonel programlama zeloları C ++ kullanmazlar (LISP ve ardıllarını tercih ederler)

OOP uzmanlarının çoğu arkadaş işlevinden hoşlanmaz, çünkü C ++ 'ın OOP bölümünün Smalltalk gibi davranmasını isterler. Ancak C ++ Smalltalk değildir ve sınıfın istemediği sürece bir işlevin sınıfınızın arkadaşı olamamasının çok basit bir nedeni olarak arkadaşınızın kapsüllemeyi kırmadığını bile anlayamazlar .

Arasındaki Ve "işlevsellik" dan, gelin durmak a.fn(b)ve fn(a,b)fark (burada olduğu fntarafların aynıdır: bir arkadaş). Basitçe, bir sözdizimi diğerinden daha uygun olabilir: fn ilişkin değişmeli ise ave b, fn(a,b)o zaman muhtemelen daha uygundur a.fn(b)(. Nerede "özel rol" o, aslında, öyle değil sahip bir görünüm)


1
Java'yı seven “OOP zealotları” OOP'u anlamadı. Alıcılar? Setters? Kapaklar için basit bir sözdizimi yok mu? Alan Kay'ı yorumlamak için, OOP'u böyle hayal etmedi.
Konrad Rudolph

@Konrad: zealotlar üstün sınırsız settir. Her zaman belirli bir zealottan daha fazla bir zealot vardır.
Emilio Garavaglia

Kaldırıldığımı söylemeliyim çünkü son paragrafı gerçekten beğendim. Çok mantıklı.
julealgon


2

C ++ SSS özlü geçerli:

Mümkün olduğunda bir üye ve gerektiğinde bir arkadaş kullanın.

SSS, arkadaşlık hakkında daha yararlı düşünme yollarından birini sunar:

Birçok kişi bir arkadaşın işlevini sınıf dışında bir şey olarak düşünür. Bunun yerine, bir arkadaşın işlevini sınıfın genel arayüzünün bir parçası olarak düşünmeyi deneyin. Sınıf bildirimindeki bir arkadaş işlevi, bir genel üye işlevinin kapsüllemeyi ihlal etmesinden daha fazla kapsüllemeyi ihlal etmez: her ikisi de sınıfın halka açık olmayan bölümlerine erişim konusunda tamamen aynı yetkiye sahiptir.

Belki de arkadaş fonksiyonlarının en yaygın kullanımı I / O için << aşırı yüklenmesidir.


0

Arkadaş işlevleri en iyi kullanıcı tanımlı operatör tanımları için kullanılır. Diğer durumlarda yararlıdırlar, ancak kendinizi sık sık arkadaş sınıfları belirttiğinizde bir tasarım yolunda olabilirsiniz (kod yazarken kullanmak için sadece iyi bir kendi kendine kontrol).

Orijinal sorudaki "güvenlik" ifadesine dikkat edin. Erişim değiştiricileri, tıpkı derleyici gibi bir kazada kötü kod yazmanızı önlemek için vardır. Erişim değiştiriciler arabirimi sınırlar ve sınıfı kullanmak için hangi işlevlerin önemli olduğunu (genel ve korumalı) ve sınıfın koruyucular için (özel) daha güzel hale getirilmesinin bir parçası olarak hangi işlevleri oluşturduğunu bildirir. Değiştiriciler güvenlik oluşturmaz, çünkü özel verilere ulaşmanın birçok yolu vardır. Örneğin, sınıfa ve büyüklüğüne bir işaretçi alın ve balığa çıkın.


-2

C ++ arkadaş işlevleri aşağıdaki işlevlerle yakından ilişkilidir:

  1. ücretsiz fonksiyonlar
  2. statik fonksiyonlar
  3. arkadaş fonksiyonları

Bu, bu işaretçiye sahip olmadıkları ve dolayısıyla sınıfın / nesnenin dışında oldukları anlamına gelir. Öte yandan, onları tekrar sınıfa ait yapan parametreler alırlar. İşte bağlantıyı açıklayan bazı örnekler:

class B;
class A {
public:
    friend void f(A &a, B &b);
private:
    int m_a;
};
class B {
public:
   friend void f(A &a, B &b);
private:
   int m_b;
};
void f(A &a, B &b) { /* uses both A's and B's private data */ }

Statik işlevler ve arkadaş işlevleri arasındaki tek fark, bir arkadaş işlevinin birkaç sınıf kullanabilmesidir.

C ++ 'da arkadaş mekanizmasını kullanmak, c ++ programlama yöntemiyle yaklaşık 10-15 yıllık deneyime sahip programcılar gerektirir ve bu nedenle başlangıçta bundan kaçınmalısınız. Gelişmiş özellik.


7
Ve nasıl 10-15 yıl türetildiniz?
DeadMG

10-15 yıl ilk gerekli olduğu andan itibaren gelir.
tp1

3
Böylece keyfi olarak bir numara oluşturdunuz.
DeadMG

3
-1: "Bundan kaçınmalısınız." C ++ 'ın her özelliği bir sorunu çözmek için oluşturuldu. Bu sorun ortaya çıktığında uygun özelliği kullanın.
kevin cline

-1 için teşekkürler. Bu yorumun bir nedeni vardı. Sanırım tüm özellikler yeni başlayanlar için uygun değildir.
tp1
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.