Sınıfta statik yöntemlere karşı ad alanı + işlevleri


290

Diyelim ki bir dizi ilgili fonksiyonum var ya da yazacağım. Diyelim ki matematikle ilgili. Örgütsel olarak:

  1. Bu işlevleri yazın ve bunları MyMathad alanım içine koyun veMyMath::XYZ()
  2. Adlı bir sınıf oluşturun MyMathve bu yöntemleri statik hale getirin ve benzer şekildeMyMath::XYZ()

Yazılımımı organize etmenin bir yolu olarak neden birini diğerinden seçeyim?


4
birincisi, ad alanları, "sınıflarla C" denildiği andan itibaren dilde bulunan sınıflara ve statik yöntemlere kıyasla dile daha yakındır. Bazı programcılar eski özelliklerle daha rahat olabilir. Diğer bazı programcılar eski derleyiciler kullanıyor olabilir. Sadece benim $ .02
Rom

21
@Rom: "Eski programcılar" konusunda haklısın, ama "eski derleyiciler" konusunda yanılıyorsun. Ad alanları eons'tan beri doğru bir şekilde derlenmiştir (1998'den kalma Visual C ++ 6 ile onlarla çalıştım!). "Sınıflarla C" gelince, bu forumdaki bazı insanlar bu gerçekleştiğinde bile doğmadı: Bunu standart ve yaygın bir C ++ özelliğinden kaçınmak için bir argüman olarak kullanmak yanlıştır. Sonuç olarak, yalnızca eski C ++ derleyicileri ad alanlarını desteklemez. Bu argümanı kullanmamak için bir bahane olarak kullanmayın.
Paercebal

@paercebal: Bazı eski derleyiciler hala gömülü dünyada kullanılmaktadır. Ad alanlarını desteklememek, muhtemelen herkesin her gün etkileşime girdiği çeşitli küçük CPU'lar için kod yazarken uyması gereken en küçük rahatsızlıklardan biridir: stereo, mikrodalga fırın, arabanızdaki motor kontrol ünitesi, trafik ışığı vb. açık olun: Her yerde daha iyi, daha yeni bir derleyici kullanmamayı savunmuyorum. Au conrare: En yeni dil özellikleri için (RTTI;) hariç). Sadece böyle bir eğilim olduğunu işaret ediyorum
Rom

13
@Rom: Mevcut durumda, soru yazarının seçeneği vardır, bu yüzden görünüşe göre, derleyicilerinin hiçbiri isim-boşluklu bir kod derleyememektedir. Ve bu C ++ ile ilgili bir soru olduğundan, gerekirse ad alanlarından ve RTTI çözümlerinden bahsedilmesi de dahil olmak üzere bir C ++ yanıtı verilmelidir. Bir C yanıtı veya eski derleyiciler için sınıflarla bir C yanıtı vermek konu dışıdır.
Mayıs 19:19

2
"Sadece benim $ .02" - ad alanlarını desteklemeyen mevcut C ++ derleyicilerine dair herhangi bir kanıt sunsaydınız daha değerli olurdu. "bazı eski derleyiciler hala gömülü dünyada kullanılıyor" - bu aptalca; "gömülü dünya" C ++ ad alanlarından daha yeni bir gelişmedir. "Sınıflı C", 1979'da, herkes C kodunu herhangi bir şeye gömmeden çok önce tanıtıldı. "Ben sadece böyle bir eğilimin varlığına işaret ediyorum" - öyle olsa bile, bunun bu soru ile ilgisi yoktur.
Jim Balter

Yanıtlar:


243

Varsayılan olarak, ad boşluklu işlevleri kullanın.

Sınıflar, ad alanlarının yerine nesnelerin oluşturulması içindir.

Nesneye Dayalı kodda

Scott Meyers, Etkili C ++ kitabı için "Üye olmayan arkadaş olmayan işlevleri üye işlevlerine tercih et" başlıklı makalenin tamamını yazdı. Herb Sutter'ın bir makalesinde bu prensibe çevrimiçi bir referans buldum:http://www.gotw.ca/gotw/084.htm

Bilmeniz gereken önemli olan şudur: C ++ işlevlerinde bir sınıfla aynı ad alanındaki işlevler o sınıfın arabirimine aittir (çünkü ADL işlev çağrılarını çözerken bu işlevleri arayacaktır).

Ad boşluklu işlevler, "arkadaş" olarak bildirilmedikçe, sınıfın iç bileşenlerine erişemezken, statik yöntemlere sahiptir.

Bu, örneğin, sınıfınızı korurken, sınıfınızın iç kısımlarını değiştirmeniz gerektiğinde, statik olanlar da dahil olmak üzere tüm yöntemlerinde yan etkileri aramanız gerekeceği anlamına gelir.

Eklenti I

Sınıf arayüzüne kod ekleme.

C # 'da, sınıfa erişiminiz olmasa bile bir sınıfa yöntem ekleyebilirsiniz. Ancak C ++ ile bu mümkün değildir.

Ancak, yine de C ++ 'da, birisinin sizin için yazdığı bir sınıfa bile, ad boşluklu bir işlev ekleyebilirsiniz.

Diğer taraftan, kodunuzu tasarlarken bu önemlidir, çünkü işlevlerinizi bir ad alanına koyarak kullanıcılarınıza sınıfın arayüzünü artırma / tamamlama yetkisi vereceksiniz.

Dahili II

Önceki noktanın bir yan etkisi, birden çok başlıkta statik yöntemler bildirmek imkansızdır. Her yöntem aynı sınıfta bildirilmelidir.

Ad alanları için, aynı ad alanındaki işlevler birden çok başlıkta bildirilebilir (neredeyse standart takas işlevi bunun en iyi örneğidir).

Uzantı III

Bir ad alanının temel serinliği, bazı kodlarda, "using" anahtar sözcüğünü kullanırsanız, bundan bahsetmekten kaçınabilmenizdir:

#include <string>
#include <vector>

// Etc.
{
   using namespace std ;
   // Now, everything from std is accessible without qualification
   string s ; // Ok
   vector v ; // Ok
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

Ve hatta "kirliliği" bir sınıfla sınırlayabilirsiniz:

#include <string>
#include <vector>

{
   using std::string ;
   string s ; // Ok
   vector v ; // COMPILATION ERROR
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

Bu "model", neredeyse standart takas deyiminin düzgün kullanımı için zorunludur.

Ve bu, sınıflardaki statik yöntemlerle yapmak imkansızdır.

Yani, C ++ ad alanlarının kendi semantikleri vardır.

Ancak, ad alanlarını kalıtıma benzer bir şekilde birleştirebileceğiniz için daha da ileri gider.

Örneğin, AAA işlevli bir ad alanı A, BBB işlevli bir ad alanı B varsa, bir ad alanı C bildirebilir ve anahtar kelimeyi kullanarak bu ad alanına AAA ve BBB getirebilirsiniz.

Sonuç

Ad alanları ad alanları içindir. Sınıflar sınıflar içindir.

C ++ her kavramın farklı olması için tasarlanmıştır ve farklı durumlarda farklı sorunlara bir çözüm olarak farklı şekilde kullanılır.

Ad alanlarına ihtiyacınız olduğunda sınıfları kullanmayın.

Ve sizin durumunuzda, ad alanlarına ihtiyacınız var.


Bu cevap konulara da uygulanabilir mi, yani evreler için statik yöntemler yerine ad alanları kullanmak daha mı iyidir?
dashesy

3
@dashesy: ad alanları ve statik yöntemlerin iş parçacığı ile ilgisi yoktur, bu nedenle evet, ad alanları daha iyidir çünkü ad alanları statik yöntemlerden neredeyse her zaman daha iyidir. Bir şey varsa, statik yöntemlerin sınıf üyesi değişkenlerine erişimi vardır, bu nedenle bir şekilde ad alanlarından daha düşük bir kapsülleme değerine sahiptirler. Ve verilerin izole edilmesi, iş parçacıklı yürütmede daha da önemlidir.
paercebal

@ paercebal- teşekkürler, iş parçacığı işlevleri için statik sınıf yöntemleri kullanıyordum. Şimdi sınıfı ad alanı olarak kötüye kullandığımı anlıyorum, bu yüzden bir nesnede birden çok iş parçacığına sahip olmak için en iyi yaklaşım nedir? Bu soruyu da
SO'ya sordum

1
@dashesy: ​​Sorun istiyorsun. Farklı iş parçacıklarıyla istediğiniz şey, paylaşılmaması gereken verileri izole etmektir, bu nedenle bir sınıfın özel verilerine ayrıcalıklı erişime sahip birden çok iş parçacığına sahip olmak kötü bir fikirdir. Ben saklasın biri bir sınıf içerisindeki iplik ve ana iş parçacığı için verilerinden cezayı verileri izole etmek emin olun. Elbette, paylaşılması gereken veriler o sınıfın üyeleri olabilir, ancak yine de senkronize edilmelidir (kilitler, atomik, vb.). Ne kadar libs'e erişebildiğinizden emin değilim, ancak görevleri / async'i kullanmak daha da iyi.
paercebal

paercebal'ın cevabı kabul edilen cevap olmalı!
Ad

54

Benimle aynı fikirde olmayan birçok insan var, ama ben böyle görüyorum:

Bir sınıf aslında belirli bir nesnenin tanımıdır. Statik yöntemler, o nesne tanımına yakından bağlı olan işlemleri tanımlamalıdır.

Sadece bir temel nesne veya bir tür nesnenin tanımı ile ilişkili olmayan bir grup ilgili fonksiyona sahip olacaksanız , o zaman sadece bir ad alanı ile gitmek söyleyebilirim. Sadece benim için, kavramsal olarak, bu çok daha mantıklı.

Örneğin, sizin durumunuzda kendinize, "MyMath nedir?" Eğer MyMathnesnenin bir tür tanımlamıyor, o zaman ben söyleyebilirim: Bir sınıf yapmazlar.

Ama dediğim gibi, (hatta şiddetle) bu konuda bana (özellikle Java ve C # geliştiricileri) katılmayacak birçok insan olduğunu biliyorum.


3
Bu konuda çok saf bir perspektifiniz var. Ancak pratik olarak, tüm statik yöntemlere sahip bir sınıf kullanışlı olabilir: bunları yapabilirsiniz typedef, şablon parametreleri olarak kullanabilirsiniz, vb.
Shog9

56
Bu Jave ve C # insanların başka seçeneği olmadığı için.
Martin York

7
@ shog9. İşlevleri de değiştirebilirsiniz.
Martin York

6
@ Dan: muhtemelen, matematik rutinlerine ihtiyaç duyan ve farklı uygulamaları "takmayı" desteklemek isteyen biri.
Shog9

1
@Dan: "Birisi bir sınıfı şablon parametresi olarak kullanmakla ilgileniyorsa, o sınıfın neredeyse altta yatan bir nesneyi tanımladığını düşünüyorum." Hayır, hiç de değil. Özellikleri düşünün. (Yine de, cevabınıza tamamen katılıyorum.)
sbi

18
  • Statik verilere ihtiyacınız varsa, statik yöntemler kullanın.
  • Bunlar şablon işlevleriyse ve tüm işlevler için birlikte bir dizi şablon parametresi belirleyebilmek istiyorsanız, şablon sınıfında statik yöntemler kullanın.

Aksi takdirde, ad boşluklu işlevler kullanın.


Yorumlara yanıt olarak: evet, statik yöntemler ve statik veriler aşırı kullanılır. Bu yüzden yardımcı olabileceklerini düşündüğüm sadece iki ilgili senaryo sundum. OP'nin özel örneğinde (bir dizi matematik rutini), tüm rutinlere uygulanacak parametreleri (örneğin, bir çekirdek veri türü ve çıktı hassasiyeti) belirleme yeteneğini isterse, şöyle bir şey yapabilir:

template<typename T, int decimalPlaces>
class MyMath
{
   // routines operate on datatype T, preserving at least decimalPlaces precision
};

// math routines for manufacturing calculations
typedef MyMath<double, 4> CAMMath;
// math routines for on-screen displays
typedef MyMath<float, 2> PreviewMath;

Buna ihtiyacınız yoksa, elbette bir ad alanı kullanın.


2
statik veri olarak adlandırılan, ad alanının uygulama dosyasında ad alanı verileri olabilir; bu, üstbilgide görünmesi gerekmediği için bağlantıyı daha da azaltır.
Motti

Statik veriler, ad alanı kapsamındaki globallerden daha iyi değildir.
coppro

@coppro. Bunlar, özel hale getirilebilecekleri (ancak başka türlü anlaşabildikleri) için rastgele küresellerden evrim zincirinin en az bir adım ötesindedir.
Martin York

@Motti: OTOH, başlıkta olmasını istiyorsanız (satır içi / şablon işlevleri), bu konuda çirkin olmaya geri dönersiniz.
Shog9

1
İlginç bir örnek, templateargümanları tekrarlamaktan kaçınmak için bir sınıf stenografi kullanmak !
underscore_d

13

Bir ad alanının bir sınıfa göre birçok avantajı olduğu için bir ad alanı kullanmalısınız:

  • Her şeyi aynı başlıkta tanımlamanız gerekmez
  • Başlıktaki tüm uygulamanızı göstermenize gerek yoktur
  • usingSınıf üyesi olamazsınız ; yapabilirsinusingbir ad alanı üyesi
  • using classYine de yapamazsınusing namespace çoğu zaman iyi bir fikir değil
  • Bir sınıf kullanmak, gerçekten yokken oluşturulacak bazı nesnelerin olduğunu ima eder

Statik üyeler, bence, çok fazla kullanıldı. Çoğu durumda gerçek bir zorunluluk değildir. Statik üye işlevleri muhtemelen dosya kapsamı işlevleri olarak daha iyi durumdadır ve statik veri üyeleri daha iyi, hak edilmemiş bir üne sahip genel nesnelerdir.


3
"Sınıftaki tüm uygulamanızı açığa çıkarmanıza gerek yoktur" ne de bir sınıf kullandığınızda.
Vanuan

Dahası: Ad alanları kullanıyorsanız, başlıktaki tüm uygulamanızı gösteremezsiniz (sonuçta birden çok sembol tanımı elde edersiniz). Satır içi sınıf üyesi işlevleri bunu yapmanızı sağlar.
Vanuan

1
@Vanuan: Başlıktaki ad alanı uygulamalarını gösterebilirsiniz. inlineODR'yi tatmin etmek için anahtar kelimeyi kullanmanız yeterlidir.
Thomas Eding

@ThomasEding gerekmez! = Olabilir
Vanuan

3
@Vanuan: Kullanırken derleyici tarafından yalnızca bir şey garanti edilir ve inlinebir işlevin gövdesini "satır içi" DEĞİLDİR. Gerçek bir (ve standart tarafından garanti) amacı, inlinebirden çok tanımları önlemektir. C ++ için "Bir Tanım Kuralı" hakkında bilgi edinin. Ayrıca, bağlı SO sorusu ODR sorunları yerine önceden derlenmiş üstbilgi sorunları nedeniyle derleme değildi.
Thomas Eding

3

Ad alanlarını tercih ederim, bu şekilde uygulama dosyasında anonim bir ad alanında özel verilere sahip olabilirsiniz (bu nedenle privateüyelerin aksine başlıkta hiç görünmek zorunda değildir ). Başka bir avantajı, usingad alanınız tarafından yöntemlerin istemcilerinin,MyMath::


2
Uygulama dosyasındaki anonim bir ad alanında sınıflarla da özel verileriniz olabilir. Mantığınızı takip ettiğimden emin değilim.
Patrick Johnmeyer

0

Sınıfı kullanmak için bir neden daha - Erişim belirteçlerini kullanma seçeneği. Daha sonra, genel statik yönteminizi daha küçük özel yöntemlere ayırabilirsiniz. Genel yöntem birden çok özel yöntem çağırabilir.


6
Erişim değiştiricileri havalıdır, ancak en fazla privateyönteme bile, prototipi hiç bir başlıkta yayınlanmayan (ve böylece görünmez kalan) bir yöntemden daha erişilebilirdir. Anonim olarak adlandırılmış işlevler tarafından sunulan daha iyi kapsülleme bile söz etmiyorum.
paercebal

2
Özel yöntemler, IMO, işlevin kendisini uygulamada gizlemekten (cpp dosyası) daha düşüktür ve üstbilgi dosyasında hiçbir zaman gösterilmez. Lütfen cevabınızı ve neden özel üyeleri kullanmayı tercih edeceğinizi açıklayın . O zamana kadar -1.
nonsensickle

@nonsensickle Belki de birçok tekrarlanan bölüme sahip bir mamut fonksiyonunun, özel durumun arkasındaki rahatsız edici alt bölümleri gizlerken, başkalarının tehlikeli / çok dikkatli bir şekilde kullanılması gerekiyorsa onlara ulaşmasını durdurarak güvenli bir şekilde parçalanabileceği anlamına gelir.
Troyseph

1
@Troyseph bile, bu bilgileri .cppdosyadaki adsız bir ad alanı içinde gizleyebilir, bu da başlık dosyasını okuyan herkese gereksiz bilgi vermeden o çeviri birimine özel yapar. Etkili olarak, PIMPL deyimini savunmaya çalışıyorum.
nonsensickle

.cppŞablonları kullanmak istiyorsanız bir dosyaya koyamazsınız .
Yay295

0

Hem ad alanı hem de sınıf yönteminin kullanımları vardır. Ad alanı dosyalar arasında yayılma yeteneğine sahiptir, ancak tek bir dosyaya gitmek için ilgili tüm kodları uygulamanız gerekiyorsa bu bir zayıflıktır. Yukarıda belirtildiği gibi sınıf, sınıfta özel statik üyeler oluşturmanıza da izin verir. Uygulama dosyasının anonim ad alanında olabilir, ancak yine de onları sınıf içinde bulundurmaktan daha büyük bir kapsamdır.


"Uygulama dosyasının anonim ad alanında [şeyler saklamak] onları sınıf içinde bulundurmaktan daha büyük bir kapsamdır" - hayır, değildir. üyelerine ayrıcalıklı erişim gerekli değildir durumlarda, anonim isim alanlı şeyler daha özel daha private:olanlardan. ve ayrıcalıklı erişim birçok durumda görünüyor gerekli olan, yani dışarı hesaba katılabilir. en 'özel' işlevi başlıkta görünmeyen işlevdir. private:yöntemler asla bu avantajdan yararlanamaz.
underscore_d
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.