2012-03-28 26 views
7

Her zaman sanal yok ediciler olmadan bir sınıftan miras kalmaman gerektiğini ve çok fazla dikkat etmediğimi duydum, çünkü çoğu kez miras kullanmadım. Bu kural, polimorfizm kullanmak istemiyor olsanız da geçerlidir, ancak tüm sınıf işlevlerini istiyorsanız ve biraz daha eklemek ister misiniz? Somut olmak gerekirse, aşağıdaki sınıf, polimorfik olarak kullanmadığım sürece, iyi tanımlanmış bir davranışla güvende olur mu? (Türetilmiş nesnelere; diğer bir deyişle silme baz işaretçiler)Sanal yıkıcılar olmadan sınıflardan miras alma

template<typename T> 
class SomewhatSafeVector : public std::vector<T> 
{ 
public: 
    typedef std::vector<T> base; 

    T& operator[](unsigned n) { 
     if (n >= base::size()) 
     { 
      throw IndexOutOfBounds(); 
     } 
     return base::operator[](n); 
    } 
}; 
+1

Tamam mı, yoksa sorun değil, yine de standart kitaplık kapsayıcılarından türememelisiniz. Ayrıca, sınırlar içinde dinamik kapsayıcılara erişme konusunda sorun yaşıyorsanız, büyük ölçekli bir erişim olduğundan büyük resmi algoritmik düşünceye ("0-1-çok" ve "aralıklar") bakmayı tercih edebilirsiniz. genellikle bir * mantık * hatası. –

+4

Sanırım özel örneğinizde, kalıtım, yeniden kullanım için değil, arabirimin yeniden kullanımı için kullanıldığı için miras açısından son derece zarif bir çözüm değildir. Arayüzü yeniden kullanmazsınız, çünkü operatörünüz [] 'std :: vektörü 'olmayan bir istisna atar. Kodu yeniden kullanmak isterseniz, sadece paylaşılan paylaşılan işlevleri kullanın veya (bu durumda olduğu gibi), 'std :: vector'' SomewhatSafeVector' üyesi olun. –

+0

@KerrekSB: İlk neden, neden olmasın? İkincisi, benim böyle bir sorunum yok. Ama bence konteynırları kontrol etmenin öğretim ve hata ayıklama amaçları için iyi bir fikir olacağını düşünüyorum. –

cevap

6

Hep sanal yıkıcılar

Bu açıklayan tüm inceliklerini çok fazla zaman alır ve onu, çünkü yeni başlayanlar verilen Pratik bir kural olmadan bir sınıftan miras gerektiğini duydum ettik Sadece daha fazla (ve egzersizler için bu kadar maliyetli değil) aslında onlara (bazen overkill olabilir) tüm çalışan birkaç temel satır vermek.

Temel sınıfta virtual yıkıcı olmadan kaliteyi mükemmel şekilde kullanabilirsiniz. Diğer yandan, eğer temel sınıf virtual yöntemine sahip değilse, miras muhtemelen iş için yanlış bir araçtır. Örneğin: Eğer SafeVector<T> sv; sv[3]; kullanırsanız o zaman, bu güvenlidir, ancak std::vector<T>& v = sv; v[3]; yaparsanız, bu değil ... Bu sadece temel sınıf yöntemi gizleme, çünkü onu geçersiz kılmak için uyarı seviye, size bildiririz).

Burada uygun yöntem, kompozisyon kullanmak ve daha sonra gerçekten kullandığınız yöntemler için uygulama üyesine yönlendirme yöntemleri oluşturmak olacaktır. Pratikte, C++ delege (using attribute.insert;) devralmayı desteklemediği için yorucu oluyor ...

Başka bir alternatif de, kısıtlama olmaksızın her zaman ücretsiz yöntemler ekleyebileceğiniz için, daha güvenli yöntemleri ücretsiz yöntemler sağlamaktır. "OO" zihniyetine sahip insanlara daha az deyim duyuyor olabilir ve bazı operatörler bu şekilde eklenemez.

5

sınıf polimorfik (türetilmiş nesne için bir silme baz işaretçiler) kullanmak niyetinde yoksa o zaman Tanımsız davranış değildir.

Referans:

C++ 03 Standart: 5.3.5

5.3.5/1 Sil:

silme ifade operatör en türetilmiş nesne olarak yok (1.8) veya yeni bir ifadeyle oluşturulmuş dizi.
silme ifadesi:
:: dökme ifadeyi silme tercih
:: tercih silme [] dökme sentezleme

5.3.5/3: İlk olarak

alternatif (delete object), eğer işlenenin statik tipi dinamik tipinden farklıysa, statik tip, işlenenin dinamik tipinin bir temel sınıfı olmalı ve statik tip bir sanal yıkıcıya sahip olmalı veya davranış tanımsız olacaktır. İkinci alternatifte (dizi sil) nesnenin dinamik tip statik tip farklıysa silinecek olursa, davranış sadece can,) Sen polymorphically o nesneyi kullanmak için bekliyoruz

4

undefined.73 olduğunu Polimorfik olarak delete. Sınıfınızın nesnelerine std::vector<>* aracılığıyla işaretçileri silmekten kaçınırsanız, güvende olursunuz. Kenara

: Sen senin operator[] böylece basitleştirmek olabilir: Eğer (yani, asla upcast bir başvuru veya işaretçi olan) polimorfizm hiç kullanmak

T& operator[](unsigned n) { return this->at(n); } 
2

Evet, güvenli olmayan yıkımını gerçekleştirmek için bir yolu yoktur .

Mixin sınıfları genellikle bu şekilde kullanılır ve CRTP, nadiren bir çift desenleri adlandıran sanal bir yıkıcıyı ima eder.

İlgili konular