C ++ ve Java'daki soyut sınıflar / arayüzler için farklı bir kullanım gerekçesi var mı?


13

Herb Sutter'e göre, uygulamayı mümkün olduğunca ayrıştırmak için soyut arayüzleri (tüm saf sanal fonksiyonlar) C ++ 'daki soyut sınıflara tercih etmeliyiz. Şahsen bu kuralı çok yararlı bulsam da, yakın zamanda birçok Java programcısı olan bir ekibe katıldım ve Java kodunda bu kılavuz mevcut görünmüyor. Fonksiyonlar ve uygulamaları soyut sınıflarda çok sık yer almaktadır. Bu yüzden Herb Sutter'ı C ++ için bile yanlış mı yaptım yoksa C ++ 'da Java ile karşılaştırıldığında soyut işlevlerin kullanımında genel bir fark var mı? Uygulama koduna sahip soyut sınıflar Java'da C ++ 'dan daha mantıklı mı?


1
Bazı şüphelerim vardı ve nihayet buraya koydum çünkü java oo hakkında eksik olduğum bazı tasarım ilkelerinden kaynaklanıyor olabilir. O zaman genel bir tavsiye değil, dili kullanma hakkı ve yanlışlığı hakkında daha fazla bilgi
Martin

Arayüzler tamamen sanal olmalıdır. Soyut sınıflar fikri, kısmen uygulandıkları ve gereksiz yere kodu tekrarlamadan boşlukları doldurmaktır (örneğin, neden her alt sınıfta yazma (bayt) ve write (int) soyut sınıf çağrı yazma (bayt) yazma (int))

1
Muhtemel ilgili: stackoverflow.com/q/1231985/484230 , java'daki soyut sınıfları tercih etmenin bir nedenini verir. C ++ için bu neden, arayüz düzeyinde işlevsellik ekleyebilen ücretsiz işlevlerin varlığı nedeniyle doğru görünmüyor
Martin

1
Bence Altın Kural "yaprak dışı sınıfları soyutlaştırmak" ama bu sadece "saf" ya da "boş" bir gereklilik oluşturmuyor.
Kerrek SB

1
Sizin için çalışıyorsa, sizin için çalışır. Gerçekten neden kodları artık en son görüşlere uymuyor insanlar panik görmüyorum.
James

Yanıtlar:


5

OOP'un bileşimi ve ikamesi vardır.

C ++, çoklu kalıtım, şablon uzmanlığı, katıştırma ve değer / taşıma / işaretçi semantiğine sahiptir.

Java'nın tek miras ve arayüzleri, gömme ve referans semantiği vardır.

OOP okulunun bu dilleri kullanmasının ortak yolu, nesne ikamesi ve kompozisyon için gömme için miras kullanmaktır. Ama aynı zamanda ortak bir ataya ve çalışma zamanı yayınlamanın bir yoluna ihtiyacınız var (C ++ 'da denir dynamic_cast, Java'da sadece başka bir arabirim ister).

Java tüm bunları kendi java.lang.Objectköklü hiyerarşisiyle yapar. C ++ önceden tanımlanmış bir ortak köke sahip değildir, bu nedenle aynı "resme" gelmek için en azından tanımlamanız gerekir (ancak bu, bazı C ++ olasılıklarını sınırlar ...).

Bundan sonra, derleme zamanı polimorfizmi (CRTP'yi düşünün) ve değer semantiğine sahip olma olasılığı, "OOP nesnesi" kavramının bir C ++ programına taşınması için başka alternatifler de sunabilir.

Hatta, geleneksel okul paradigmasını tersine çevirerek, kompozisyonu yönetmek için ikame ve özel miras yönetimi için gömme ve örtülü dönüşüm kullanacağını düşünebilirsiniz. (Elbette, bu yol diğerinden 20 yaş daha genç, bu yüzden bunu yaparken geniş bir topluluk desteği beklemeyin)

Veya tüm sınıflar için sanal bir ortak temel oluşturabilir, arabirimden uygulamalara dağıtım olarak "egemenlik" kullanarak "egemenlik" kullanarak, kısmen uygulanmış arabirimlerden, tam bir arabirim kümesinden geçerek, son sınıflara (tam uygulama) form arabirimi (uygulama yok) düşünebilirsiniz. -parallologram "kalıtım şeması.

Sadece bir ve tek OOP yolunun her iki dilin yeteneklerini sınırladığı varsayılarak OOP ile j ++ 'ın C ++ ile karşılaştırılması.

C ++ 'ı Java kodlama deyimlerine sıkı sıkıya bağlı kalmaya zorlamak, Java'yı C ++ benzeri bir dil olarak Java'yı denatüre etmeye zorlamak için C +' yı denatüre etmektedir.

"Duyarlılık" meselesi değil, iki dilin sahip olduğu farklı "toplama mekanizmaları" mıydı ve bunları birleştirmenin farklı bir yolu, bir deyim bir dilde diğerinden daha karlı hale geliyor, ya da tam tersi.


1
Bence bu cevap çok ilginç, çünkü dil özelliklerini özlü olarak bir oo ve tasarım ilkeleri için bir araç olarak bir doktrin olarak değil, bir yardım olarak tanımlamaktadır. Eğer c ++ 'da oo yapmak istiyorsanız, ancak ortak bir kök gerekmez. Bu sadece yanlıştır, ayrıca operatörleriniz ve şablonlarınız olduğu için (işaret ettiğiniz gibi java'nın ana ağaç tasarımına çok güçlü bir alternatiftir). Bunun dışında puanlarınız tüm cevaplarda en değerli
Martin

1
@Martin: "Teknik anlamda" haklısınız, ancak çalışma zamanı çokmofizmi gerekiyorsa (örneklenen nesnelerin gerçek türü program girdisine bağlı olduğundan) bir "kök" ("a" bir kısayol değil , bir makaledir " tek ve tek ") tüm nesnenin" kuzenlerini "ve hiyerarşiyi çalışma zamanı yürünebilir hale getiren şeydir. Farklı kökler, birbirleriyle ilişkili olmayan farklı soylardan kaynaklanır . Bunun "iyi" veya "kötü" olup olmadığı deyim değil, bir bağlam meselesidir.
Emilio Garavaglia

Bu doğru. Tüm c ++ programı için yapay olarak bir genel kökü anlattığınızı düşündüm ve java ile karşılaştırıldığında, mevcut olmadığını kusur olarak gördüm. Ancak düzenlemenizden sonra noktayı oldukça netleştiriyorsunuz. Tekrar teşekkürler
Martin

12

İlke her iki dil için de geçerli, ancak adil bir karşılaştırma yapmıyorsunuz. C ++ saf soyut sınıflarını Java arayüzleriyle karşılaştırmalısınız.

C ++ 'da bile, bazı işlevlerin uygulandığı ancak saf bir soyut sınıftan türetilen (uygulama yok) soyut sınıflara sahip olabilirsiniz . Java'da, arabirimlerden türetilebilecek (uygulama olmadan) aynı soyut sınıflara sahip olursunuz (bazı uygulamalarla).


Peki ne zaman c ++ 'da bir arabirim sınıfı yerine soyut bir sınıf tercih ederdiniz. Ben her zaman arayüz artı c ++ üye olmayan işlevleri seçti.
Martin

1
@Martine bağlı tasarım. Temel olarak, her zaman bir arayüz tercih edin. Ama " her zaman " kuralların istisnaları vardır ...
Luchian Grigore

Yeterince doğru ama Java Kodunda çoğunluğu temsil eden soyut sınıflar görüyorum. Bunun nedeni java'da arayüzlerde çalışan serbest fonksiyonların mümkün olmaması olabilir mi?
Martin

3
@Martin iyi serbest fonksiyonlar Java'da hiç mümkün değildir, bu yüzden bir sebep olabilir, evet. İyi nokta! Kendi sorunuzu yanıtladı! Kendiniz bir cevap ekleyebilirsiniz, bence bu kadar.
Luchian Grigore

4

Genellikle aynı OO ilkeleri Java ve C ++ için geçerlidir. Bununla birlikte, büyük bir fark, C ++ 'ın çoklu kalıtımı desteklemesi, Java'da ise sadece bir sınıftan miras alabilmenizdir. Java'nın, çoklu miras eksikliğine ek olarak ve muhtemelen onunla ne yapabileceğinizi kısıtlamak için inandığım arayüzlere sahip olmasının ana nedeni budur (çünkü çoklu mirasın kötüye kullanılması konusunda çok fazla eleştiri vardır). Yani, muhtemelen bir Java programcısının zihninde, soyut sınıflar ve arayüzler arasında daha güçlü bir ayrım vardır . Soyut sınıflar davranışı paylaşmak ve devralmak için kullanılırken arayüzler ekstra işlevsellik eklemek için kullanılır. Unutmayın, Java'da yalnızca bir sınıftan miras alabilirsiniz, ancak birçok arabiriminiz olabilir. Bununla birlikte, tamamen soyut sınıfları (örneğin, bir "C ++ arayüzü") C ++ olarak Java arabiriminin amacından farklı olarak davranışı paylaşmak ve devralmak için kullanılır (yine de işlevleri uygulamanız gerekir), bu nedenle kullanım Java arabirimlerinden farklıdır.


0

Bazen bazı varsayılan uygulamalara sahip olmak mantıklıdır. Örneğin, tüm alt sınıflar için geçerli olan genel bir PrintError (dize msg) yöntemi.

virtual PrintError(string msg) { cout << msg; }

Gerçekten gerekliyse yine de geçersiz kılınabilir, ancak istemciye yalnızca genel sürümü çağırmasına izin vererek biraz güçlük kaydedebilirsiniz.

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.