Apakah ada alasan penggunaan yang berbeda untuk kelas / antarmuka abstrak di C ++ dan Java


13

Menurut Herb Sutter kita harus lebih memilih antarmuka abstrak (semua fungsi virtual murni) ke kelas abstrak di C ++ untuk memisahkan implementasi sejauh mungkin. Sementara saya pribadi menemukan aturan ini sangat berguna, saya baru-baru ini bergabung dengan tim dengan banyak programmer Java dan dalam kode Java pedoman ini sepertinya tidak ada. Fungsi dan implementasinya sangat sering terletak di kelas abstrak. Jadi saya mendapatkan Herb Sutter semuanya salah bahkan untuk C ++ atau apakah ada perbedaan umum dalam penggunaan fungsi abstrak di C ++ dibandingkan dengan Java. Apakah kelas abstrak dengan kode implementasi lebih masuk akal di Jawa daripada di C ++ dan jika ya mengapa?


1
Saya punya beberapa keraguan dan akhirnya menaruhnya di sini karena bisa jadi karena beberapa prinsip desain yang saya lewatkan tentang java oo. Jadi itu bukan tentang saran umum tetapi lebih tentang benar dan salah untuk menggunakan bahasa
Martin

Antarmuka dimaksudkan untuk murni virtual. Gagasan kelas abstrak adalah bahwa mereka sebagian diimplementasikan, dan terserah pada implementasi untuk mengisi kesenjangan tanpa mengulangi kode yang tidak perlu (misalnya, mengapa harus menulis (byte) dan menulis (int) di setiap subkelas ketika Anda dapat memiliki abstrak panggilan kelas tulis (byte) dari tulis (int))

1
Mungkin terkait: stackoverflow.com/q/1231985/484230 memberi alasan lebih disukai kelas abstrak di java. Untuk C ++ alasan ini tampaknya tidak berlaku karena adanya fungsi gratis yang dapat menambahkan fungsionalitas pada tingkat antarmuka
Martin

1
Saya pikir Aturan Emas adalah untuk "membuat kelas non-daun abstrak", tetapi itu tidak membuat persyaratan "hanya murni" atau "kosong".
Kerrek SB

1
Jika berhasil untuk Anda, itu bekerja untuk Anda. Saya benar-benar tidak melihat mengapa orang panik setelah kode mereka tidak lagi menganut pendapat terbaru.
James

Jawaban:


5

OOP memiliki komposisi dan substitusi.

C ++ memiliki banyak pewarisan, spesialisasi templat, embedding dan semantik nilai / pindahkan / pointer.

Java memiliki satu pewarisan dan antarmuka, semantik semantik dan rujukan.

Cara umum sekolah OOP menggunakan bahasa-bahasa ini adalah menggunakan pewarisan untuk penggantian objek dan menanamkan untuk komposisi. Tetapi Anda juga membutuhkan leluhur yang sama dan cara untuk runtime-cast (dalam C ++ disebut dynamic_cast, di Jawa hanya meminta antarmuka dari yang lain).

Java melakukan semua ini dengan java.lang.Objecthierarki yang telah di-root sendiri . C ++ tidak memiliki root umum yang telah ditentukan, jadi Anda setidaknya harus mendefinisikannya, untuk datang ke "gambar" yang sama (tapi ini membatasi beberapa kemungkinan C ++ ...).

Setelah itu, kemungkinan untuk memiliki kompilasi-waktu polimorfisme (think to CRTP) dan nilai semantik juga dapat menawarkan alternatif lain dengan cara konsep "objek OOP" dapat porting ke dalam program C ++.

Anda bahkan dapat membayangkan bid'ah menggunakan penanaman dan konversi implisit untuk mengelola substitusi dan warisan pribadi untuk mengelola komposisi, bahkan membalikkan paradigma sekolah tradisional. (Tentu saja, cara ini 20 tahun lebih muda dari yang lain, jadi jangan berharap dukungan masyarakat luas dalam melakukan itu)

Atau Anda dapat membayangkan pangkalan bersama virtual untuk semua kelas, membentuk antarmuka (tidak ada implementasi) hingga kelas akhir (sepenuhnya diimplementasikan) melalui antarmuka yang diimplementasikan sebagian, bahkan cluster antarmuka, menggunakan "dominasi" sebagai pengiriman dari antarmuka ke implementasi melalui "multi-stacked". skema pewarisan -parallelogram ".

Membandingkan OOP ke java ke C ++ dengan asumsi hanya ada satu dan hanya cara OOP yang membatasi kemampuan kedua bahasa.

Memaksa C ++ untuk sepenuhnya mematuhi idiom pengkodean Java mendenaturasi C ++ karena memaksa Java untuk berperilaku sebagai bahasa mirip C ++ adalah denaturasi Java.

Bukan masalah "sensibilitas" tetapi "mekanisme agregasi" yang berbeda memiliki kedua bahasa dan cara yang berbeda untuk menggabungkan mereka yang membuat beberapa idiom lebih menguntungkan dalam satu bahasa daripada yang lain dan sebaliknya.


1
Saya pikir jawaban ini sangat menarik, karena ia dengan mudah menggambarkan fitur bahasa sebagai alat untuk prinsip-prinsip desain dan hanya sebagai bantuan dan bukan doktrin. Namun Anda tidak perlu root umum jika Anda ingin melakukan oo di c ++. Ini benar-benar salah, juga karena Anda memiliki operator dan template (yang merupakan alternatif yang sangat kuat untuk desain pohon utama java seperti yang Anda tunjukkan). Selain itu, poin Anda adalah yang paling berharga dalam semua jawaban
Martin

1
@ Martin: Dalam "pengertian teknis" Anda benar sedang, tetapi jika Anda perlu runtime polymorophism (karena jenis sebenarnya dari benda instantiated tergantung pada program input) a "root" ( 'a' adalah sebuah artikel, bukan jalan pintas untuk " satu-satunya ") adalah apa yang membuat semua objek" sepupu ", dan hierarki run-time-walkable. Akar yang berbeda berasal nenek moyang yang berbeda tidak saling terkait. Apakah ini "baik" atau "buruk" adalah masalah konteks, bukan idiom.
Emilio Garavaglia

Itu benar. Saya pikir Anda mengacu pada artifisial porviding satu root umum untuk seluruh program c ++ dan melihatnya sebagai cacat karena tidak ada, dibandingkan dengan java. Namun setelah diedit, Anda menjelaskan maksudnya. Terima kasih lagi
Martin

12

Prinsip ini berlaku untuk kedua bahasa, tetapi Anda tidak melakukan perbandingan yang adil. Anda harus membandingkan kelas abstrak murni C ++ dengan antarmuka Java.

Bahkan di C ++, Anda dapat memiliki kelas abstrak yang memiliki beberapa fungsi diimplementasikan, tetapi berasal dari kelas abstrak murni (tanpa implementasi). Di Java, Anda akan memiliki kelas abstrak yang sama (dengan beberapa implementasi), yang dapat diturunkan dari antarmuka (tanpa implementasi).


Jadi kapan Anda lebih suka kelas abstrak daripada kelas antarmuka di c ++. Saya selalu memilih antarmuka plus fungsi non-anggota di c ++.
Martin

1
@ Martin itu tergantung pada desain. Pada dasarnya, selalu lebih suka antarmuka. Tapi aturan " selalu " memiliki pengecualian ...
Luchian Grigore

Cukup benar tetapi dalam Java Code saya melihat kelas abstrak sebagian besar mewakili mayoritas. Mungkinkah ini disebabkan oleh kenyataan bahwa fungsi bebas yang bekerja pada antarmuka tidak dimungkinkan di java?
Martin

3
@Martin juga fungsi bebas sama sekali tidak mungkin di Jawa, jadi itu bisa menjadi alasan, ya. Tempat yang bagus! Menjawab pertanyaan Anda sendiri! Anda dapat menambahkan jawaban sendiri, saya pikir itu saja.
Luchian Grigore

4

Secara umum prinsip-prinsip OO yang sama berlaku untuk Java dan C ++. Namun, satu perbedaan besar adalah bahwa C ++ mendukung multiple-inheritance sementara di Java Anda hanya dapat mewarisi dari satu kelas. Ini adalah alasan utama mengapa Java memiliki antarmuka saya percaya, untuk menambah kurangnya pewarisan berganda dan mungkin untuk membatasi apa yang dapat Anda lakukan dengannya (karena ada banyak kritik atas penyalahgunaan pewarisan berganda). Jadi, mungkin dalam pikiran programmer Java, ada perbedaan yang lebih kuat antara kelas dan antarmuka abstrak. Kelas abstrak digunakan untuk berbagi dan mewarisi perilaku sementara antarmuka hanya digunakan untuk menambah fungsionalitas tambahan. Ingat, di Java Anda hanya dapat mewarisi dari satu kelas, tetapi Anda dapat memiliki banyak antarmuka. Namun dalam C ++, kelas abstrak murni (yaitu "antarmuka C ++") adalah digunakan untuk berbagi dan mewarisi perilaku tidak seperti tujuan dari antarmuka Java (meskipun Anda masih diharuskan untuk mengimplementasikan fungsi-fungsi), maka penggunaannya berbeda dari antarmuka Java.


0

Terkadang masuk akal untuk memiliki beberapa implementasi standar. Misalnya metode PrintError (string msg) generik yang berlaku untuk semua sub kelas.

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

Itu masih bisa diganti jika benar-benar diperlukan, tetapi Anda dapat menyimpan beberapa kerumitan klien dengan memungkinkan mereka hanya memanggil versi generik.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.