Hiç korumalı üye değişkenleri kullanmalı mısınız?


98

Hiç korumalı üye değişkenleri kullanmalı mısınız? Avantajları nelerdir ve bu hangi sorunlara neden olabilir?

Yanıtlar:


75

Hiç korumalı üye değişkenleri kullanmalı mısınız?

Saklanma durumu konusunda ne kadar seçici olduğunuza bağlı.

  • Herhangi bir iç durum sızıntısı istemiyorsanız, tüm üye değişkenlerinizi özel olarak beyan etmenin yoludur.
  • Alt sınıfların dahili duruma erişmesini gerçekten umursamıyorsanız, korumalı yeterince iyidir.

Bir geliştirici gelir ve sınıfınızın alt sınıflarını alt sınıflara alırsa, tam olarak anlamadıkları için alt sınıflara girebilirler. Özel üyelerle, genel arayüz dışında, işlerin nasıl yapıldığına ilişkin uygulamaya özgü ayrıntıları göremezler, bu da size daha sonra değiştirme esnekliği verir.


1
Get / set yöntemiyle korumalı değişkenlerin performansı ve özel değişkenlerin performansı hakkında yorum yapabilir misiniz?
Jake

3
Profilleme yoluyla şişe boynunun erişimciler (neredeyse hiçbir zaman olmadığı gibi) olduğunu bulmazsanız endişelenmeye değer bir şey olmadığını söyleyebilirim. Bir sorun haline gelirse, JIT'yi işler hakkında daha akıllı hale getirmek için yapılabilecek püf noktaları var. Örneğin java'da, erişimcinin onu son olarak işaretleyerek satır içine alınabileceğini ima edebilirsiniz. Dürüst olmak gerekirse, alıcıların ve ayarlayıcıların performansı, sistem organizasyonu ve profil oluşturucu tarafından belirlenen gerçek performans sorunları ile uğraşmaktan çok daha az önemlidir.
Allain Lalonde

24
@Jake: Tasarım kararlarını asla performans varsayımlarına dayalı olarak vermemelisiniz. Tasarım kararlarını, en iyi tasarım olduğunu düşündüğünüze göre verirsiniz ve ancak gerçek hayattaki profilleme, tasarımınızda bir tıkanıklık gösterirse, gidip onu düzeltirsiniz. Genellikle tasarım sağlamsa, performans da iyidir.
Mecki

Genel arayüz dışındaki özel üyelerle, uygulamaya özgü ayrıntıları göremezler Sadece sınıfı açıp bakabilirler, bu yüzden bu hiç mantıklı değil mi ?!
Siyah

2
@Black Açıkça Allain, bu üyelere ' erişemezler ' ve bu nedenle onlara karşı kod oluşturamaz, sınıfın yazarını korumalı üyeleri daha sonra kaldırmak / değiştirmek için serbest bıraktı. (Tabii ki, Pimpl deyim de görsel ve başlık dahil çeviri birimlerinden saklayarak sağlayacak.)
underscore_d

32

Genel olarak, bir şey kasıtlı olarak kamuya açık olarak tasarlanmıyorsa, onu özel yaparım.

Türetilmiş bir sınıftan o özel değişkene veya yönteme erişmem gereken bir durum ortaya çıkarsa, onu özelden korumalı olarak değiştiririm.

Bu neredeyse hiç gerçekleşmez - çoğu durumu modellemek için özellikle iyi bir yol olmadığından, kalıtımın hiç hayranı değilim. Her neyse, devam edin, endişelenmeyin.

Geliştiricilerin çoğu için bunun iyi (ve muhtemelen bunu yapmanın en iyi yolu) olduğunu söyleyebilirim.

İşin basit gerçeği, başka bir geliştirici bir yıl sonra gelir ve özel üye değişkeninize erişmeleri gerektiğine karar verirse, basitçe kodu düzenleyecek, korumalı olarak değiştirecek ve işlerine devam edeceklerdir.

Bunun tek gerçek istisnası, ikili dll'leri kara kutu biçiminde üçüncü şahıslara gönderme işindeyseniz. Bu, temelde Microsoft, bu 'Özel DataGrid Kontrolü' satıcıları ve belki de genişletilebilirlik kitaplıkları ile birlikte gelen birkaç başka büyük uygulamadan oluşur. Bu kategoride olmadığınız sürece, bu tür şeyler için endişelenmek için zaman / çaba harcamaya değmez.


31

Günümüzde genel his, türetilmiş sınıflar ve tabanları arasında gereksiz eşleşmeye neden olmalarıdır.

Korunan yöntemlere / özelliklere göre belirli bir avantajları yoktur (bir zamanlar hafif bir performans avantajına sahip olabilirler) ve aynı zamanda çok derin mirasın moda olduğu bir çağda daha çok kullanılıyorlardı, ki şu anda öyle değil.


2
Gerekmiyor no particular advantage over protected methods/propertiesolmak no particular advantage over *private* methods/properties?
Penghe Geng

Hayır, çünkü türetilmiş sınıflar ve tabanları arasında iletişim kurmanın çeşitli yollarının avantajlarından / dezavantajlarından bahsettiğim için - tüm bu teknikler 'korumalı' olacaktır - fark, bunların üye değişkenler (alanlar) veya özellikler / yöntemler ( yani bir tür alt yordamlar).
Will Dean

1
Hızlı açıklama için teşekkürler. Orijinal göndericinin 6 yıllık bir gönderiye soruma bir saat içinde cevabını aldığım için mutluyum. Bunun diğer çevrimiçi forumların çoğunda olabileceğini düşünmüyorsunuz :)
Penghe Geng

10
Daha da dikkat çekici olanı, bu süre zarfında kendime gerçekten katılıyorum ...
Will Dean

Bir kurucunun işlerinden biri, ona tüm durum değişkenlerinin açıkça başlatıldığını görmektir. Bu kurala uyarsanız, superyapıyı ana kurucuyu çağırmak için kullanabilirsiniz ; daha sonra ebeveyn sınıfta özel durum değişkenlerini başlatmakla ilgilenecektir.
ncmathsadist

9

Benim için temel sorun, bir değişkeni korumalı hale getirdiğinizde, sınıfınızdaki herhangi bir yöntemin değerinin bir aralık içinde olmasına güvenmesine izin veremezsiniz , çünkü bir alt sınıf onu her zaman aralık dışına yerleştirebilir.

Örneğin, işlenebilir bir nesnenin genişliğini ve yüksekliğini tanımlayan bir sınıfa sahipsem ve bu değişkenleri korumalı yaparsam, en boy oranı (örneğin) üzerinde hiçbir varsayımda bulunamam.

Kritik olarak, ben yapabilirsiniz asla ben boy oranını korumak için benim ayarlayıcıları güncellemek bile, değişkenler belirleyiciler üzerinden ayarlı olmak ya üzerinden erişilebilir olduğunu garanti beri, kod kitaplık olarak serbest bırakmak o andan itibaren herhangi bir noktada bu varsayımlarda mevcut koddaki alıcılar.

Sınıfımın herhangi bir alt sınıfı da, alt sınıflarının tüm noktası bu olsa bile değişkenlerin değerlerini zorlayamayacağı için bu garantiyi vermeyi seçemez .

Örnek olarak:

  • Korumalı değişkenler olarak depolanan genişlik ve yüksekliğe sahip bir dikdörtgen sınıfım var.
  • Açık bir alt sınıf (bağlamım içinde) bir "DisplayedRectangle" sınıfıdır; buradaki tek fark, genişlikleri ve yükseklikleri bir grafik gösterim için geçerli değerlerle sınırlandırmamdır.
  • Ama bu artık mümkün değil benim DisplayedRectangle sınıf beri, olamaz gerçekten bu değerleri sınırlamak hala DisplayedRectangle olarak tedavi edilirken bunun herhangi bir alt sınıfı, doğrudan değerleri geçersiz olabilir gibi.

Değişkenleri özel olarak sınırlayarak, daha sonra ayarlayıcılar veya alıcılar aracılığıyla istediğim davranışı uygulayabilirim.


8

Genel olarak, korunan üye değişkenlerinizi, onları kullanan kod üzerinde tam kontrole sahip olduğunuz nadir durumlarda tutarım. Herkese açık bir API oluşturuyorsanız, asla derim. Aşağıda üye değişkenine nesnenin bir "özelliği" olarak değineceğiz.

Bir üye değişkeni erişimcilerle özel değil de korumalı hale getirdikten sonra süper sınıfınızın yapamayacağı şey :

  1. mülkiyet okunduğu zaman tembelce bir değer yaratın. Korumalı bir alıcı yöntemi eklerseniz, değeri tembel olarak oluşturabilir ve geri verebilirsiniz.

  2. mülkün ne zaman değiştirildiğini veya silindiğini bilmek. Bu, süper sınıf bu değişkenin durumu hakkında varsayımlar yaptığında hatalara neden olabilir. Değişken için korumalı bir ayarlayıcı yöntemi yapmak bu kontrolü sağlar.

  3. Değişken okunduğunda veya yazıldığında bir kesme noktası ayarlayın veya hata ayıklama çıktısı ekleyin.

  4. Bu üye değişkeni, onu kullanabilecek tüm kodu aramadan yeniden adlandırın.

Genel olarak, korumalı bir üye değişkeni oluşturmayı önermemin nadir bir durum olacağını düşünüyorum. Korunan değişkeni değiştiren başka bir koddaki bir hatayı saatler sonra takip etmektense, alıcılar / ayarlayıcılar aracılığıyla mülkü açığa çıkarmak için birkaç dakika harcamak daha iyidir. Sadece bu da değil, aynı zamanda bağımlı kodu bozmadan gelecekteki işlevselliği (tembel yükleme gibi) eklemeye karşı sigortalısınız. Şimdi yapmaktan daha geç yapmak daha zordur.


7

Tasarım düzeyinde, korumalı bir özelliği kullanmak uygun olabilir, ancak uygulama için bunu erişimci / mutatör yöntemlerinden ziyade korumalı bir üye değişkenine eşlemede hiçbir avantaj görmüyorum.

Korumalı üye değişkenlerinin önemli dezavantajları vardır, çünkü istemci kodunun (alt sınıf) temel sınıf sınıfının iç durumuna etkin bir şekilde erişmesine izin verirler. Bu, temel sınıfın değişmezlerini etkin bir şekilde korumasını engeller.

Aynı nedenden ötürü, korumalı üye değişkenleri, sabit olması garanti edilmedikçe veya tek bir iş parçacığıyla sınırlı olmadıkça güvenli çok iş parçacıklı kod yazmayı önemli ölçüde daha zor hale getirir.

Erişimci / mutatör yöntemleri, bakım sırasında önemli ölçüde daha fazla API kararlılığı ve uygulama esnekliği sunar.

Ayrıca, bir OO sadeciyseniz, nesneler durumu okuyarak / ayarlayarak değil, mesajlar göndererek işbirliği yapar / iletişim kurar.

Karşılığında çok az avantaj sunarlar. Bunları mutlaka başka birinin kodundan çıkarmam, ama onları kendim kullanmıyorum.


4

Çoğu zaman, korumalı kullanmak tehlikelidir, çünkü sınıfınızın kapsüllemesini bir şekilde kırarsınız, bu da kötü tasarlanmış bir türetilmiş sınıf tarafından pekala parçalanabilir.

Ama güzel bir örneğim var: Diyelim ki bir tür genel kapsayıcı yapabilirsiniz. Dahili bir uygulaması ve dahili erişimcileri vardır. Ancak verilerine en az 3 genel erişim sunmanız gerekir: map, hash_map, vektör benzeri. O zaman şöyle bir şeye sahipsin:

template <typename T, typename TContainer>
class Base
{
   // etc.
   protected
   TContainer container ;
}

template <typename Key, typename T>
class DerivedMap     : public Base<T, std::map<Key, T> >      { /* etc. */ }

template <typename Key, typename T>
class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ }

template <typename T>
class DerivedVector  : public Base<T, std::vector<T> >        { /* etc. */ }

Bu tür bir kodu bir aydan daha kısa bir süre önce kullandım (yani kod bellekten geliyor). Biraz düşündükten sonra, genel Base kapsayıcısının soyut bir sınıf olması gerektiğine inanıyorum, oldukça iyi yaşayabilse bile, çünkü doğrudan Base kullanmak o kadar acı verici olurdu ki yasaklanmalıdır.

Özet Böylece, türetilmiş sınıf tarafından kullanılan verileri korumuş olursunuz. Yine de, Base sınıfının soyut olması gerektiği gerçeğini hesaba katmalıyız.


Kapsüllemeyi artık kamu üyelerinden daha fazla bozmaz. Türetilmiş sınıfların, sınıfın kullanıcılarına maruz kalmayan sınıfın durumunu kullanabileceğini söyleyen bir ayardır.
gbjbaanb

@gbjbaanb: Kendinizle çelişiyorsunuz "bu, kapsülü genel üyelerin yaptığından daha fazla bozmaz", "[sadece] türetilmiş sınıflar 'state" sınıfını kullanabilir. "korumalı", kamu ile özelin ortasıdır. Yani "korumalı [...] kapsüllemeyi biraz bozuyor" hala doğru ...
paercebal

aslında, c ++ dilinde, std :: stack gibi kapsayıcı bağdaştırıcıları, temeldeki kapsayıcı nesnesini "c" adlı korumalı bir değişkenle açığa çıkarır.
Johannes Schaub - litb

Bu yazının oldukça eski olduğunu biliyorum, ama ben de bir araya gelme ihtiyacı hissediyorum. Kapsüllemeyi "bir şekilde" kırmazsınız, tamamen kırarsınız. protecteddaha fazla kapsüllenmiş değil public. Yanlış olduğum kanıtlanmaya hazırım. Tek yapmanız gereken korumalı bir üye ile bir sınıf yazmak ve benim onu ​​değiştirmemi yasaklamak. Açıkçası, korumalı kullanımın tüm amacı miras için olduğundan, sınıfın nihai olmaması gerekir. Bir şey ya kapsüllenmiştir ya da değildir. Aradaki durum yok.
Taekahn

3

Kısacası evet.

Korumalı üye değişkenleri, herhangi bir alt sınıftan ve aynı paketteki herhangi bir sınıftan değişkene erişim sağlar. Bu, özellikle salt okunur veriler için oldukça yararlı olabilir. Ancak bunların gerekli olduğuna inanmıyorum, çünkü korumalı bir üye değişkeni, özel bir üye değişkeni ve birkaç alıcı ve ayarlayıcı kullanılarak çoğaltılabilir.


1
Tersine, özel üye değişkenleri de asla gerekli değildir; halk herhangi bir kullanım için yeterlidir.
Alice

3

Sadece kayıt için, "Olağanüstü C ++" ın 24. Maddesi altında, dipnotlardan birinde, Sutter "hiçbir zaman genel veya korumalı bir üye değişkeni olan bir sınıf yazmazsınız, değil mi? (Bazı kütüphaneler tarafından belirlenen zayıf örnek ne olursa olsun .) "


2

.Net erişim değiştiricileri hakkında ayrıntılı bilgi için buraya gidin

Korunan üye değişkenlerinin gerçek avantajları veya dezavantajları yoktur, bu, sizin özel durumunuzda neye ihtiyacınız olduğu sorusudur. Genel olarak üye değişkenleri özel olarak bildirmek ve özellikler aracılığıyla dışarıdan erişimi etkinleştirmek kabul edilen bir uygulamadır. Ayrıca, bazı araçlar (örneğin, bazı O / R eşleyicileri) nesne verilerinin özellikler tarafından temsil edilmesini bekler ve genel veya korumalı üye değişkenlerini tanımaz. Ancak alt sınıflarınızın (ve YALNIZCA alt sınıflarınızın) belirli bir değişkene erişmesini istediğinizi biliyorsanız, onu korumalı olarak ilan etmemek için hiçbir neden yoktur.


Alt sınıfların bir değişkene erişmesini istemek, değişkenleri özgürce değiştirebilmelerini istemekten çok farklıdır . Bu, korunan değişkenlere karşı ana argümanlardan biridir: artık temel sınıfınız, herhangi bir değişmezinin geçerli olduğunu varsayamaz, çünkü türetilmiş herhangi bir sınıf, korunan üyelerle kesinlikle her şeyi yapabilir. Onlara karşı ana argüman budur. Sadece verilere erişmeleri gerekiyorsa , o zaman ... bir erişimci yazın. : P (Ben gerçi muhtemelen daha ben gerekenden daha kullanın korumalı değişkenleri, ve ben kesim aşağı çalışıyor olacağım!)
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.