Neden C ++ 'da çoklu kalıtımdan kaçınmalıyım?


167

Birden fazla miras kullanmak iyi bir kavram mı yoksa bunun yerine başka şeyler de yapabilir miyim?

Yanıtlar:


259

Çoklu kalıtım (MI olarak kısaltılır) kokuyor , bu da genellikle kötü nedenlerle yapıldığı ve bakımcının karşısında geri uçacağı anlamına gelir .

özet

  1. Kalıtım yerine özelliklerin bileşimini düşünün
  2. Korkunç Elmas'a karşı dikkatli olun
  3. Nesneler yerine birden çok arabirimin mirasını düşünün
  4. Bazen, Çoklu Kalıtım doğru şeydir. Öyleyse kullanın.
  5. Çok sayıda miras alınan mimarinizi kod incelemelerinde savunmaya hazır olun

1. Belki de kompozisyon?

Bu kalıtım için geçerlidir ve bu nedenle çoklu kalıtım için daha da doğrudur.

Nesnenin gerçekten bir başkasından miras alması gerekiyor? A'nın Carbir Engineişten ya da a'dan miras alması gerekmez Wheel. A'nın Carbir Engineve dört vardır Wheel.

Kompozisyon yerine bu sorunları çözmek için birden fazla miras kullanıyorsanız, yanlış bir şey yaptınız.

2. Dehşet Pırlantası

Genellikle, bir sınıf var A, sonra Bve Cher iki devralma A. Ve sonra (neden bana sorma) birisi Dhem Bve hem de miras alması gerektiğine karar verir C.

Sekiz yılda iki kez bu tür bir sorunla karşılaştım ve aşağıdakilerden dolayı görmek eğlenceli:

  1. Başından beri ne kadar hata yapıldı (Her iki durumda da, her ikisinden Dmiras almamalıydım Bve C), çünkü bu kötü bir mimariydi (aslında Chiç var olmamalıydı ...)
  2. Bunun için ne kadar bakımcı ödüyorlardı, çünkü C ++ 'da, ana sınıf Atorun sınıfında iki kez mevcuttu Dve bu nedenle, bir ana alanın A::fieldgüncellenmesi , ya iki kez (üzerinden B::fieldve C::field) güncellenmesi ya da bir şeyin sessizce yanlış gitmesi ve çökmesi anlamına geliyordu , (yeni bir işaretçi girin B::fieldve silin C::field...)

Miras nitelendirmek için C ++ sanal anahtar sözcüğünü kullanmak, bu istediğiniz şey değilse yukarıda açıklanan çift mizanpajdan kaçınır, ancak yine de, deneyimime göre, muhtemelen yanlış bir şey yapıyorsunuz ...

Nesne hiyerarşisinde, hiyerarşiyi grafik olarak değil, bir Ağaç (düğümün BİR üst öğesi vardır) olarak tutmaya çalışmalısınız.

Elmas hakkında daha fazla bilgi (edit 2017-05-03)

Diamond of Dread in C ++ ile ilgili asıl sorun ( tasarımın ses olduğu varsayılırsa - kodunuzu gözden geçirin! ), Bir seçim yapmanız gerektiğidir :

  • Sınıfın Amizanpajınızda iki kez olması arzu edilir mi ve bu ne anlama geliyor? Evet ise, elbette ondan iki kez miras alın.
  • sadece bir kez olması gerekiyorsa, ondan sanal olarak miras alın.

Bu seçim sorunun doğasında vardır ve C ++ 'da, diğer dillerden farklı olarak, tasarımınızı dil düzeyinde zorlamaya gerek kalmadan yapabilirsiniz.

Ancak tüm güçler gibi, bu güçle sorumluluk gelir: Tasarımınızı gözden geçirin.

3. Arayüzler

Sıfır veya bir beton sınıfının ve sıfır veya daha fazla arayüzün çoklu kalıtımı genellikle iyidir, çünkü yukarıda açıklanan Dread Diamond ile karşılaşmazsınız. Aslında, Java'da işler böyle yapılır.

Genellikle, C devralındığında Ave Bkullanıcıların bir Csanki a Ave / veya sanki a B.

C ++ 'da, bir arayüz aşağıdakileri içeren soyut bir sınıftır:

  1. tüm yöntemi saf sanal olarak bildirildi (= 0 ile eklenmiş) (2017-05-03 kaldırıldı)
  2. üye değişkeni yok

Sıfırın bir gerçek nesneye ve sıfır veya daha fazla arabirime Çoklu kalıtım "koklamak" olarak kabul edilmez (en azından, o kadar değil).

C ++ Soyut Arabirimi hakkında daha fazla bilgi (düzenleme 2017-05-03)

Birincisi, NVI deseni bir arayüz üretmek için kullanılabilir, çünkü gerçek kriterler hiçbir durum içermemelidir (yani üye değişkenler hariç this). Soyut arayüzünüzün amacı bir sözleşme yayınlamaktır ("beni bu şekilde ve bu şekilde arayabilirsiniz"), başka bir şey, hiçbir şey daha az. Sadece soyut sanal yönteme sahip olmanın sınırlandırılması bir yükümlülük değil bir tasarım seçimi olmalıdır.

İkincisi, C ++ 'da, soyut arayüzlerden neredeyse miras almak mantıklıdır (ek maliyet / dolaylı olsa bile). Yapmazsanız ve arayüz devralma hiyerarşinizde birden çok kez görünürse, belirsizlikler yaşarsınız.

Üçüncüsü, nesne yönelimi harika, ancak C ++ 'daki Tek Gerçek TM değil . Doğru araçları kullanın ve C ++ 'da farklı türde çözümler sunan başka paradigmalarınız olduğunu her zaman unutmayın.

4. Gerçekten Çoklu Mirasa ihtiyacınız var mı?

Bazen evet.

Genellikle, Csınıf devralmakta Ave Bve Ave B(yani değil aynı hiyerarşide ortak, farklı kavramlar vs. hiçbir şey) iki ilgisiz nesneleri vardır.

Örneğin, NodesX, Y, Z koordinatlarına sahip bir sisteminiz olabilir, çok fazla geometrik hesaplamalar yapabilir (belki bir nokta, geometrik nesnelerin bir parçası) ve her Düğüm diğer ajanlarla iletişim kurabilen bir Otomatik Ajandır.

Belki zaten her biri kendi ad alanına sahip iki kütüphaneye erişiminiz vardır (isim alanlarını kullanmanın başka bir nedeni ... Ama isim alanlarını kullanıyorsunuz, değil mi?), Biri varlık geove diğeriai

Böylece own::Nodehem ai::Agentve ' den kendi türetmeniz var geo::Point.

Bu, kendinize bunun yerine kompozisyon kullanmamayı sormanız gereken andır. Eğer own::Nodegerçekten bir hem ai::Agentbir geo::Point, daha sonra kompozisyon yapmayacağım.

Ardından, own::Node3B alandaki konumlarına göre diğer ajanlarla iletişim kurmanız için birden fazla mirasa ihtiyacınız olacak .

(Bunu not edeceksiniz ai::Agentve geo::Pointtamamen, tamamen, tamamen İLGİLİ OLMAYIN ... Bu, çoklu kalıtım tehlikesini büyük ölçüde azaltır)

Diğer durumlar (düzenleme 2017-05-03)

Başka durumlar da var:

  • (umarım özel) mirasın uygulama detayı olarak kullanılması
  • politikalar gibi bazı C ++ deyimleri birden fazla kalıtım kullanabilir (her bir bölüm diğerleriyle iletişim kurması gerektiğinde this)
  • std :: exception'dan sanal kalıtım ( İstisnalar için Sanal Kalıtım gerekli mi? )
  • vb.

Bazen kompozisyon kullanabilirsiniz ve bazen MI daha iyidir. Mesele şu: Bir seçeneğiniz var. Sorumlu bir şekilde yapın (ve kodunuzu gözden geçirin).

5. Peki, Çoklu Kalıtım yapmalı mıyım?

Çoğu zaman, deneyimlerime göre, hayır. MI o kazık tembel tarafından kullanılabilir çünkü (a yapmak gibi sonuçlarının da farkında olmadan birlikte özellikleri, iş gibi görünüyor olsa bile, doğru araç değildir Carhem bir Engineve Wheel).

Ama bazen, evet. Ve o zaman, hiçbir şey MI'dan daha iyi çalışmayacak.

Ancak MI koklamakta olduğundan, kod incelemelerinde mimarinizi savunmaya hazır olun (ve savunmak iyi bir şeydir, çünkü savunamazsanız, o zaman yapmamalısınız).


4
Mükemmel bir uyum olsa bile, yetki devri üzerindeki tasarruflar, onu kullanmaya alışkın olmayan programcıların karışıklığını telafi etmeyeceğini, ancak başka bir şekilde iyi bir özetin gerekli olmadığını ve nadiren yararlı olmadığını iddia ediyorum.
Bill K

2
Nokta 5, ben MI kullanan kodun hemen yanında nedenini açıklayan bir yorum olması gerektiğini eklemek istiyorum, bu yüzden bir kod inceleme sözlü olarak açıklamak zorunda değilsiniz. Bu olmadan, yorumcunuz olmayan biri, kodunuzu gördüklerinde iyi muhakemenizi sorgulayabilir ve savunmak için hiçbir fırsatınız olmayabilir.
Tim Abell

çünkü yukarıda tarif edilen Dehşet Pırlantası ile karşılaşmazsınız. ” Neden olmasın?
curiousguy

1
Gözlemci modeli için MI kullanıyorum.
Calmarius

13
@BillK: Tabii ki gerekli değil. MI olmadan bir Turning tam diliniz varsa, MI ile bir dilin yapabileceği her şeyi yapabilirsiniz. Yani evet, gerekli değil. Hiç. Bununla birlikte, çok kullanışlı bir araç olabilir ve Dreaded Diamond olarak adlandırılan ... "Dreaded" kelimesinin neden orada olduğunu bile hiç anlamadım. Aslında akıl yürütmek oldukça kolaydır ve genellikle bir sorun değildir.
Thomas Eding

145

Bjarne Stroustrup ile yapılan bir röportajdan :

İnsanlar oldukça doğru bir şekilde çoklu mirasa ihtiyacınız olmadığını söylüyorlar, çünkü çoklu miras ile yapabileceğiniz her şeyi tek miras ile de yapabilirsiniz. Sadece bahsettiğim delegasyon hilesini kullan. Ayrıca, herhangi bir mirasa ihtiyacınız yoktur, çünkü tek mirasla yaptığınız her şey, bir sınıf boyunca ileterek miras olmadan da yapabilirsiniz. Aslında, herhangi bir sınıfa da ihtiyacınız yok, çünkü her şeyi işaretçiler ve veri yapılarıyla yapabilirsiniz. Ama neden bunu yapmak istesin? Dil olanaklarını kullanmak ne zaman uygundur? Ne zaman bir çözümü tercih ederdiniz? Çoklu kalıtımın yararlı olduğu vakaları gördüm ve hatta oldukça karmaşık çoklu kalıtımın yararlı olduğu vakaları gördüm. Genellikle, dilin sunduğu olanakları geçici çözüm olarak kullanmayı tercih ederim


6
C # ve Java'da kaçırdığım bazı C ++ özellikleri vardır, ancak tasarımları daha zor / karmaşık hale getirecektir. Örneğin, değişmezlik garantileri const- yaşadım aksak geçici çözümler yazmak için (genellikle arayüzleri ve kompozisyon kullanarak) bir sınıf gerçekten zaman gerekli mutable- sahip olmak ve-değişmez varyantları. Ancak, bir zamanlar birden fazla miras kaçırmadım ve bu özelliğin olmaması nedeniyle bir geçici çözüm yazmak zorunda olduğumu hiç hissetmedim. Aradaki fark bu. Her durumda şimdiye kadar, gördüğüm değil MI daha iyi tasarım seçimi değil, bir geçici çözüm olduğunu kullanılarak.
BlueRaja - Danny Pflughoeft

24
+1: Mükemmel cevap: Kullanmak istemiyorsanız, kullanmayın.
Thomas Eding

38

Bundan kaçınmak için bir neden yoktur ve bazı durumlarda çok yararlı olabilir. Yine de olası sorunların farkında olmanız gerekir.

En büyüğü ölüm elmasıdır:

class GrandParent;
class Parent1 : public GrandParent;
class Parent2 : public GrandParent;
class Child : public Parent1, public Parent2;

Artık Child içinde GrandParent'in iki "kopyası" nız var.

C ++ bunu düşünmüş ve sorunları aşmak için sanal kalıtım yapmanıza izin veriyor.

class GrandParent;
class Parent1 : public virtual GrandParent;
class Parent2 : public virtual GrandParent;
class Child : public Parent1, public Parent2;

Daima tasarımınızı gözden geçirin, verilerin yeniden kullanılmasından tasarruf etmek için kalıtım kullanmadığınızdan emin olun. Kompozisyon ile aynı şeyi temsil edebilirseniz (ve tipik olarak yapabilirsiniz) bu çok daha iyi bir yaklaşımdır.


21
Ve kalıtımı yasaklar ve bunun yerine sadece kompozisyon kullanırsanız, her zaman iki tane GrandParentvar Child. MI korkusu var, çünkü insanlar sadece dil kurallarını anlamayabileceklerini düşünüyorlar. Ancak bu basit kuralları alamayan herkes de önemsiz olmayan bir program yazamaz.
curiousguy

1
Kulağa sert geliyor, C ++ kuralları her yerde çok ayrıntılı. Tamam, bu yüzden bireysel kurallar basit olsa bile, her şey basit değil, en azından bir insanın izlemesi için birçok şey var.
Zebrafish

11

Bkz. W: Çoklu Kalıtım .

Birden fazla miras eleştiri aldı ve bu nedenle birçok dilde uygulanmadı. Eleştiriler şunları içerir:

  • Artan karmaşıklık
  • Anlamsal belirsizlik genellikle elmas problemi olarak özetlenir .
  • Tek bir sınıftan birden çok kez miras kalmamak
  • Miras sırasını değiştiren sınıf anlambilimi.

C ++ / Java stili yapıcıları olan dillerde çoklu kalıtım, kurucuların ve kurucu zincirinin miras sorununu daha da şiddetlendirir, böylece bu dillerde bakım ve genişletilebilirlik sorunları yaratır. Çok çeşitli inşaat yöntemleriyle miras ilişkilerindeki nesnelerin, yapıcı zincirleme paradigması altında uygulanması zordur.

COM ve Java arayüzü gibi arayüz (saf soyut sınıf) kullanmak için bunu modern bir yol.

Bunun yerine başka şeyler yapabilir miyim?

Evet yapabilirsin. GoF'den çalarım .

  • Bir Uygulamaya değil, Arabirime Programlama
  • Miras yerine kompozisyonu tercih et

8

Kamusal miras bir IS-A ilişkisidir ve bazen bir sınıf birkaç farklı sınıf türü olabilir ve bazen bunu yansıtmak önemlidir.

"Karışımlar" da bazen yararlıdır. Genellikle küçük sınıflardır, genellikle hiçbir şeyden miras kalmazlar, kullanışlı işlevsellik sağlarlar.

Kalıtım hiyerarşisi oldukça sığ olduğu (neredeyse her zaman olması gerektiği gibi) ve iyi yönetildiği sürece, korkunç elmas mirasını almanız olası değildir. Elmas, birden fazla miras kullanan tüm dillerde bir sorun oluşturmaz, ancak C ++ 'ın tedavisi genellikle garip ve bazen kafa karıştırıcıdır.

Birden fazla mirasın çok kullanışlı olduğu durumlarla karşılaşsam da, aslında oldukça nadirdirler. Bunun nedeni, birden fazla mirasa gerçekten ihtiyaç duymadığım zamanlarda diğer tasarım yöntemlerini kullanmayı tercih etmemdir. Dil yapılarını karıştırmaktan kaçınmayı tercih ediyorum ve neler olduğunu anlamak için el kitabını gerçekten iyi okumak zorunda olduğunuz miras vakaları oluşturmak kolaydır.


6

Birden fazla mirastan "kaçınmalısınız" ama 'elmas problemi' ( http://en.wikipedia.org/wiki/Diamond_problem ) gibi ortaya çıkabilecek sorunların farkında olmalı ve size verilen gücü dikkatli bir şekilde ele almalısınız. , tüm güçlerde olması gerektiği gibi.


1
+1: İşaretçilerden kaçınmamanız gerektiği gibi; onların sonuçlarının farkında olmanız yeterlidir. İnsanlar bazı hippi hijyen için kötü olduğunu söyledi çünkü internetten öğrendikleri ifadeler ("MI kötüdür", "optimize etmeyin", "goto kötüdür" gibi) çıngırak durdurmak gerekir. En kötü yanı, asla bu tür şeyleri kullanmayı denememeleri ve sadece İncil'den konuşulmuş gibi almalarıdır.
Thomas Eding

1
Katılıyorum. "Önlemek" değil, sorunu çözmek için en iyi yolu biliyorum. Belki kompozisyon özelliklerini kullanmayı tercih ederim, ama C ++ buna sahip değil. Belki 'handles' otomatik temsilci seçme tercih ederim, ancak C ++ buna sahip değil. Bu yüzden MI'nın genel ve künt aracını belki de aynı anda birkaç farklı amaç için kullanıyorum.
JDługosz

3

Biraz soyut olma riski altında, kategori teorisi çerçevesinde kalıtım hakkında düşünmeyi aydınlatıcı buluyorum.

Tüm sınıflarımızı ve aralarındaki miras ilişkilerini gösteren okları düşünürsek, böyle bir şey

A --> B

aracı class Btüremiştir class A. Unutmayın, verilen

A --> B, B --> C

C'nin A'dan türeyen B'den türediğini söylüyoruz, bu nedenle C'nin A'dan türediği de söyleniyor,

A --> C

Ayrıca, Aönemsiz bir şekilde Atüretilmiş her sınıf için A, kalıtım modelimizin bir kategori tanımını yerine getirdiğini söylüyoruz . Daha geleneksel bir dilde, Classtüm sınıf ve morfizm miras ilişkilerini içeren bir kategorimiz var .

Bu biraz kurulum, ama bununla birlikte Diamond of Doom'umuza bir göz atalım:

C --> D
^     ^
|     |
A --> B

Gölgeli görünümlü bir diyagram, ama olacak. Yani Dtüm devralır A, Bve C. Dahası, OP'nin sorusunu ele almaya yaklaştıkça D, herhangi bir üst sınıfından da miras kalır A. Bir diyagram çizebiliriz

C --> D --> R
^     ^
|     |
A --> B
^ 
|
Q

Şimdi, burada Diamond of Death ile ilişkili sorunlar, bazı özellik / yöntem adlarının ne zaman paylaşıldığı Cve Bpaylaşıldığı ve bazı şeylerin belirsizleştiği; ancak, paylaşılan bir davranışı içine Ataşırsak, belirsizlik ortadan kalkar.

Kategorik açıdan koyun, bizim istediğimiz A, Bve Ceğer böyle olması Bve Cgelen devralır Qsonra Abir alt sınıf olarak tekrar yazılabilir Q. Bu, pushout olarakA adlandırılan bir şey yapar .

Geri çekmeD adı verilen simetrik bir yapı da vardır . Bu temelde hem ve hem de mirasını oluşturabileceğiniz en genel yararlı sınıftır . Başka sınıf varsa Yani, çarpma devralan ve ardından bir sınıftır ait alt sınıf olarak tekrar yazılabilir .BCRBCDRD

Pırlantanın ipuçlarının geri çekilmesinden ve itilmelerden emin olmanız, aksi takdirde ortaya çıkabilecek ad çakışması veya bakım sorunlarını genel olarak ele almamız için bize güzel bir yol sağlar.

Not Paercebal 'ın cevabı onun tembihleri hepimiz olası sınıfların tam kategorisinde Sınıf çalışması göz önüne alındığında yukarıda modelin ima olarak bu ilham verdi.

Argümanını, çoklu kalıtım ilişkilerinin ne kadar karmaşık ve güçlü olabileceğini gösteren bir şeye genelleştirmek istedim.

TL; DR Programınızdaki kalıtım ilişkilerini bir kategori oluşturmak olarak düşünün. Daha sonra, çok sayıda miras alınan sınıfları pushout ve simetrik olarak yaparak, geri çekilme olan ortak bir ebeveyn sınıfı yaparak Diamond of Doom problemlerinden kaçınabilirsiniz.


3

Eiffel kullanıyoruz. Mükemmel MI'ya sahibiz. Telaşa gerek yok. Sorun yok. Kolayca yönetilebilir. MI kullanmamanız gereken zamanlar vardır. Bununla birlikte, insanların fark ettiğinden daha yararlıdır çünkü: A) iyi yönetmeyen tehlikeli bir dilde -VEYA- B) yıllarca ve yıllarca MI'da nasıl çalıştıklarından memnunlar -VEYA- C) diğer nedenler ( listeden çok fazla eminim - yukarıdaki cevaplara bakın).

Bizim için, Eiffel'i kullanan MI, her şey kadar doğal ve araç kutusunda başka bir iyi araç. Açıkçası, başka hiç kimsenin Eiffel kullanmadığından endişe duyuyoruz. Telaşa gerek yok. Sahip olduğumuz şeyden mutluyuz ve sizi bir göz atmaya davet ediyoruz.

Bakarken: Void güvenliğini ve Null işaretçi kaydının kaldırılmasını özel olarak not edin. Hepimiz MI etrafında dans ederken, işaretçileriniz kayboluyor! :-)


2

Her programlama dili artıları ve eksileri ile nesne yönelimli programlama biraz farklı bir tedavi vardır. C ++ 'ın sürümü vurguyu kareli bir şekilde performansa yerleştirir ve eşlik eden dezavantajı geçersiz kod yazmanın rahatsız edici derecede kolay olmasıdır - ve bu çoklu kalıtım için geçerlidir. Sonuç olarak, programcıları bu özellikten uzaklaştırma eğilimi vardır.

Diğer insanlar çoklu mirasın neye yaramadığı sorusunu ele aldı. Ancak, bundan kaçınmanın nedeninin güvenli olmadığı için az ya da çok ima ettiği yönünde birkaç yorum gördük. Evet, hayır.

C ++ 'da sıklıkla geçerli olduğu gibi, temel bir yönergeyi izlerseniz, sürekli olarak "omzunuzun üzerinden bakmak" zorunda kalmadan güvenle kullanabilirsiniz. Anahtar fikir, "karma" olarak adlandırılan özel bir sınıf tanımını ayırt etmenizdir; class, tüm üye işlevleri sanal (veya salt sanal) ise bir karmadır. Daha sonra tek bir ana sınıftan ve istediğiniz sayıda "mix-in" den miras almanıza izin verilir - ancak mixins'i "sanal" anahtar kelimesiyle devralmanız gerekir. Örneğin

class CounterMixin {
    int count;
public:
    CounterMixin() : count( 0 ) {}
    virtual ~CounterMixin() {}
    virtual void increment() { count += 1; }
    virtual int getCount() { return count; }
};

class Foo : public Bar, virtual public CounterMixin { ..... };

Benim önerim, bir sınıfı karma sınıf olarak kullanmayı planlıyorsanız, kodu okuyan herkesin neler olduğunu görmesini ve temel kılavuz kurallara göre oynadığınızı doğrulamasını kolaylaştırmak için bir adlandırma kuralı da benimsemenizdir. . Ayrıca, sanal temel sınıfların çalışma şekli nedeniyle, mix'lerinizin varsayılan kurucuları da varsa daha iyi çalıştığını göreceksiniz. Ve tüm yıkıcıları sanallaştırmayı da unutmayın.

Burada "mix-in" kelimesini kullanmanın parametrelenmiş şablon sınıfı ile aynı olmadığını unutmayın ( iyi bir açıklama için bu bağlantıya bakın ) ama terminolojinin adil bir kullanımı olduğunu düşünüyorum.

Şimdi, çoklu kalıtımın güvenli bir şekilde kullanılmasının tek yolu olduğu izlenimini vermek istemiyorum. Kontrol edilmesi oldukça kolay olan sadece bir yol.


2

Dikkatlice kullanmalısınız, Elmas Sorunu gibi, bazı şeylerin karmaşık olabileceği bazı durumlar var .

alternatif metin
(kaynak: learncpp.com )


12
Bu kötü bir örnektir, çünkü bir fotokopi makinesi onlardan miras alınmak yerine bir tarayıcı ve yazıcıdan oluşmalıdır.
Svante

2
Her neyse, a Printerbile olmamalı PoweredDevice. A Printer, güç yönetimi için değil yazdırma içindir. Belirli bir yazıcının uygulanması bazı güç yönetimi yapmak zorunda kalabilir, ancak bu güç yönetimi komutları doğrudan yazıcının kullanıcılarına gösterilmemelidir. Bu hiyerarşiyi gerçek anlamda kullandığını düşünemiyorum.
curiousguy


1

Elmas deseninin ötesinde, çoklu kalıtım, nesne modelinin anlaşılmasını zorlaştırır ve bu da bakım maliyetlerini artırır.

Kompozisyonun anlaşılması, anlaşılması ve açıklanması kendiliğinden kolaydır. Kod yazmak için sıkıcı olabilir, ancak iyi bir IDE (Visual Studio ile çalışmamın üzerinden birkaç yıl geçti, ancak kesinlikle Java IDE'lerin hepsinde harika kompozisyon kısayol otomasyon araçları var) bu engelin üstesinden gelmelidir.

Ayrıca, bakım açısından, "elmas sorunu" da gerçek olmayan kalıtım örneklerinde ortaya çıkar. Örneğin, A ve B'ye sahipseniz ve C sınıfınız her ikisini de genişletiyorsa ve A, portakal suyu yapan bir 'makeJuice' yöntemine sahipse ve bunu bir kez kireçle portakal suyu yapmak için genişletirseniz: tasarımcı için ne olur? B 'elektrik akımı üreten bir' makeJuice 'yöntemi ekler mi? 'A' ve 'B' uyumlu "anne" olabilir şu anda , ama bu her zaman bu kadar olacak anlamına gelmez!

Genel olarak, kalıtımdan ve özellikle çoklu kalıtımdan kaçınma eğilimi sağlamdır. Tüm maximlar gibi, istisnalar vardır, ancak kodladığınız istisnalara işaret eden yanıp sönen yeşil bir neon işaretinin olduğundan emin olmanız gerekir (ve beyninizi eğitin, böylece böyle miras ağaçlarını her gördüğünüzde kendi yanıp sönen yeşil neonunuzda çizin işareti) ve ara sıra her şeyin anlamlı olduğunu kontrol ettiğinizden emin olun.


what happens when the designer for 'B' adds a 'makeJuice' method which generates and electrical current?Uhhh, elbette derleme hatası alıyorsunuz (kullanım belirsiz ise).
Thomas Eding

1

Somut nesnelerin MI ile ilgili en önemli sorun, nadiren meşru bir şekilde "A VE B olması" gereken bir nesneye sahip olmanızdır, bu nedenle nadiren mantıksal zeminlerde doğru çözümdür. Çok daha sık olarak, "C, A veya B olarak hareket edebilir" e uygun bir C nesnesine sahipsiniz ve arayüz kalıtım ve kompozisyonuyla elde edebilirsiniz. Ancak çoklu arayüzlerin hata yapmaması hala MI, sadece bir altkümesidir.

Özellikle C ++ için, özelliğin temel zayıflığı, Çoklu Kalıtım'ın gerçek varlığı değildir, ancak izin verdiği bazı yapılar neredeyse her zaman yanlış biçimlendirilir. Örneğin, aynı nesnenin birden çok kopyasını devralmak gibi:

class B : public A, public A {};

, TANIMLAMA ile hatalı biçimlendirilmiş. İngilizceye çevrilmiş olan bu "B bir A ve A'dır". Yani, insan dilinde bile ciddi bir belirsizlik var. Şunu mu demek istediniz: "B has 2 As" ya da sadece "B is a A"? Böyle bir patolojik koda izin vermek ve daha kötüsü bir kullanım örneği yapmak, C ++ özelliğinin halef dillerinde tutulması için bir durum söz konusu olduğunda iyilik yapmamıştır.


0

Kompozisyonu kalıtım yerine kullanabilirsiniz.

Genel duygu, kompozisyonun daha iyi olduğu ve çok iyi tartışıldığıdır.


4
-1: The general feeling is that composition is better, and it's very well discussed.Bu kompozisyonun daha iyi olduğu anlamına gelmez.
Thomas Eding

Aslında daha iyi.
Ali Afshar

12
Daha iyi olmadığı durumlar hariç.
Thomas Eding

0

ilgili sınıf başına 4/8 bayt gerekir. (Sınıf başına bir işaretçi).

Bu asla bir endişe kaynağı olmayabilir, ancak bir gün milyarlarca zaman süren bir mikro veri yapınız varsa.


1
Bunun hakkında emin olmak? Tipik olarak, herhangi bir ciddi miras her sınıf üyesinde bir işaretçi gerektirir, ancak bu zorunlu olarak miras alınan sınıflarla ölçeklendirilir mi? Daha da önemlisi, kaç kez milyarlarca ufacık veri yapınız oldu?
David Thornley

3
@DavidThornley " Milyarlarca ufacık veri yapısı kaç kez oldu? " MI'ya karşı argümanlar oluştururken.
curiousguy
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.