tipe templated seharusnya mengikuti "konsep" (Input Iterator, Forward Iterator, dll ...) di mana rincian sebenarnya dari konsep tersebut ditentukan seluruhnya oleh implementasi fungsi templat / kelas, dan bukan oleh kelas dari tipe digunakan dengan template, yang agak anti-penggunaan OOP.
Saya pikir Anda salah paham tentang penggunaan konsep yang dimaksudkan oleh templat. Forward Iterator, misalnya, adalah konsep yang sangat jelas. Untuk menemukan ekspresi yang harus valid agar kelas menjadi Forward Iterator, dan semantik mereka termasuk kompleksitas komputasi, Anda melihat standar atau di http://www.sgi.com/tech/stl/ForwardIterator.html (Anda harus mengikuti tautan ke Input, Output, dan Trivial Iterator untuk melihat semuanya).
Dokumen itu adalah antarmuka yang sangat baik, dan "rincian sebenarnya dari konsep" didefinisikan di sana. Mereka tidak didefinisikan oleh implementasi Forward Iterators, dan mereka juga tidak didefinisikan oleh algoritma yang menggunakan Forward Iterators.
Perbedaan dalam cara antarmuka ditangani antara STL dan Java tiga kali lipat:
1) STL mendefinisikan ekspresi yang valid menggunakan objek, sedangkan Java mendefinisikan metode yang harus dipanggil pada objek. Tentu saja ekspresi yang valid mungkin merupakan panggilan metode (fungsi anggota), tetapi tidak harus demikian.
2) Java interface adalah objek runtime, sedangkan konsep STL tidak terlihat saat runtime bahkan dengan RTTI.
3) Jika Anda gagal membuat valid ekspresi yang valid diperlukan untuk konsep STL, Anda mendapatkan kesalahan kompilasi yang tidak ditentukan ketika Anda instantiate beberapa template dengan tipe. Jika Anda gagal menerapkan metode yang diperlukan dari antarmuka Java, Anda mendapatkan kesalahan kompilasi tertentu yang mengatakannya.
Bagian ketiga ini adalah jika Anda suka jenis (compile-time) "duck typing": antarmuka bisa tersirat. Di Jawa, antarmuka agak eksplisit: kelas "adalah" Iterable jika dan hanya jika dikatakan mengimplementasikan Iterable. Kompiler dapat memeriksa bahwa tanda tangan dari semua metodenya ada dan benar, tetapi semantiknya masih implisit (mis. Keduanya didokumentasikan atau tidak, tetapi hanya lebih banyak kode (unit test) yang dapat memberi tahu Anda apakah implementasinya benar).
Di C ++, seperti di Python, semantik dan sintaksis adalah implisit, meskipun di C ++ (dan di Python jika Anda mendapatkan preprocessor pengetikan kuat) Anda memang mendapatkan bantuan dari kompiler. Jika seorang programmer membutuhkan deklarasi antarmuka eksplisit seperti Java oleh kelas pelaksana, maka pendekatan standarnya adalah menggunakan ciri-ciri tipe (dan multiple inheritance dapat mencegah hal ini menjadi terlalu bertele-tele). Apa yang kurang, dibandingkan dengan Java, adalah satu template yang dapat saya instantiate dengan tipe saya, dan yang akan mengkompilasi jika dan hanya jika semua ekspresi yang diperlukan valid untuk tipe saya. Ini akan memberi tahu saya apakah saya sudah menerapkan semua bit yang diperlukan, "sebelum saya menggunakannya". Itu kenyamanan, tapi itu bukan inti dari OOP (dan itu masih tidak menguji semantik,
STL mungkin atau mungkin tidak cukup OO untuk selera Anda, tetapi tentu saja memisahkan antarmuka secara bersih dari implementasi. Itu tidak memiliki kemampuan Java untuk melakukan refleksi atas antarmuka, dan melaporkan pelanggaran persyaratan antarmuka secara berbeda.
Anda dapat memberi tahu fungsinya ... mengharapkan Forward Iterator hanya dengan melihat definisinya, di mana Anda perlu melihat implementasinya atau dokumentasi untuk ...
Secara pribadi saya berpikir bahwa tipe implisit adalah kekuatan, ketika digunakan dengan tepat. Algoritme mengatakan apa yang dilakukannya dengan parameter templatnya, dan implementer memastikan hal-hal itu berfungsi: itu adalah penyebut yang umum dari apa yang harus dilakukan "antarmuka". Selain itu dengan STL, Anda tidak mungkin menggunakan, katakanlah, std::copy
berdasarkan menemukan deklarasi maju dalam file header. Pemrogram harus mencari tahu apa fungsi yang diambil berdasarkan dokumentasinya, bukan hanya pada tanda tangan fungsi. Ini benar dalam C ++, Python, atau Java. Ada batasan pada apa yang dapat dicapai dengan mengetik dalam bahasa apa pun, dan mencoba menggunakan mengetik untuk melakukan sesuatu yang tidak dilakukannya (periksa semantik) akan menjadi kesalahan.
Yang mengatakan, algoritma STL biasanya memberi nama parameter template mereka dengan cara yang menjelaskan konsep apa yang diperlukan. Namun ini adalah untuk memberikan informasi tambahan yang berguna di baris pertama dokumentasi, bukan untuk membuat deklarasi maju lebih informatif. Ada lebih banyak hal yang perlu Anda ketahui daripada yang dapat diringkas dalam jenis parameter, sehingga Anda harus membaca dokumen. (Misalnya dalam algoritma yang mengambil rentang input dan output iterator, kemungkinan iterator output membutuhkan "ruang" yang cukup untuk sejumlah output berdasarkan pada ukuran rentang input dan mungkin nilai-nilai di dalamnya. Coba ketikkan itu dengan kuat. )
Inilah Bjarne pada antarmuka yang dinyatakan secara eksplisit: http://www.artima.com/cppsource/cpp0xP.html
Dalam generik, argumen harus dari kelas yang berasal dari antarmuka (setara C ++ untuk antarmuka adalah kelas abstrak) yang ditentukan dalam definisi generik. Itu berarti bahwa semua tipe argumen umum harus masuk ke dalam hierarki. Hal itu menimbulkan kendala yang tidak perlu pada desain yang membutuhkan tinjauan ke masa depan yang tidak masuk akal dari pihak pengembang. Misalnya, jika Anda menulis generik dan saya mendefinisikan kelas, orang tidak dapat menggunakan kelas saya sebagai argumen untuk generik Anda kecuali saya tahu tentang antarmuka yang Anda tentukan dan telah mengambil kelas saya dari itu. Itu kaku.
Melihatnya sebaliknya, dengan mengetik bebek Anda dapat mengimplementasikan antarmuka tanpa mengetahui bahwa antarmuka ada. Atau seseorang dapat menulis antarmuka dengan sengaja sehingga kelas Anda mengimplementasikannya, setelah berkonsultasi dengan dokumen Anda untuk memastikan bahwa mereka tidak meminta apa pun yang belum Anda lakukan. Itu fleksibel.