Pertanyaan Di mana saya harus meletakkan fungsi-fungsi yang tidak terkait dengan suatu kelas telah memicu beberapa perdebatan tentang apakah masuk akal dalam C ++ untuk menggabungkan fungsi-fungsi utilitas dalam suatu kelas atau hanya membuatnya ada sebagai fungsi bebas dalam namespace.
Saya berasal dari latar belakang C # di mana opsi terakhir tidak ada dan dengan demikian cenderung menggunakan kelas statis dalam kode C ++ kecil yang saya tulis. Namun jawaban tertinggi pada pertanyaan itu serta beberapa komentar mengatakan bahwa fungsi bebas lebih disukai, bahkan menunjukkan kelas statis adalah anti-pola. Mengapa begitu di C ++? Setidaknya di permukaan, metode statis di kelas tampaknya tidak bisa dibedakan dari fungsi bebas di namespace. Mengapa demikian preferensi untuk yang terakhir?
Apakah ada yang berbeda, jika koleksi fungsi utilitas memerlukan beberapa data bersama, mis. Cache yang dapat disimpan dalam bidang statis pribadi?
sumber
Jawaban:
Saya kira untuk menjawab bahwa kita harus membandingkan niat dari kedua kelas dan ruang nama. Menurut Wikipedia:
Kelas
Namespace
Sekarang, apa yang ingin Anda capai dengan meletakkan fungsi di kelas (statis) atau namespace? Saya berani bertaruh bahwa definisi namespace lebih baik menggambarkan niat Anda - semua yang Anda inginkan adalah wadah untuk fungsi Anda. Anda tidak memerlukan fitur yang dijelaskan dalam definisi kelas. Perhatikan bahwa kata-kata pertama dari definisi kelas adalah " Dalam pemrograman berorientasi objek ", namun tidak ada yang berorientasi objek tentang kumpulan fungsi.
Mungkin ada alasan teknis juga, tetapi sebagai seseorang yang datang dari Jawa dan mencoba memahami bahasa multi-paradigma yaitu C ++, jawaban yang paling jelas bagi saya adalah: Karena kita tidak perlu OO untuk mencapai ini.
sumber
Saya akan sangat berhati-hati dalam menyebut itu sebagai anti-pola. Namespaces biasanya lebih disukai, tetapi karena tidak ada templat namespace dan namespaces tidak dapat dilewatkan sebagai parameter templat, menggunakan kelas dengan apa-apa kecuali anggota statis sangat umum.
sumber
Kembali pada hari saya perlu mengambil kelas FORTRAN. Saya tahu bahasa-bahasa penting lainnya saat itu, jadi saya pikir saya bisa melakukan FORTRAN tanpa banyak belajar. Ketika saya menyerahkan pekerjaan rumah pertama saya, profesor mengembalikannya kepada saya dan meminta untuk mengulanginya: dia mengatakan bahwa program Pascal yang ditulis dalam sintaks FORTRAN tidak dihitung sebagai pengiriman yang valid.
Masalah serupa sedang terjadi di sini: menggunakan kelas statis untuk meng-host fungsi utilitas di C ++ adalah idiom asing untuk C ++.
Seperti yang Anda sebutkan dalam pertanyaan Anda, menggunakan kelas statis untuk fungsi utilitas di C # adalah suatu keharusan: fungsi yang berdiri sendiri sama sekali bukan opsi di C #. Bahasa yang diperlukan untuk mengembangkan pola untuk memungkinkan programmer mendefinisikan fungsi yang berdiri sendiri dalam beberapa cara lain - yaitu, dalam kelas utilitas statis. Ini adalah trik Java yang diambil kata-demi-kata: misalnya, java.lang.Math dan System.Math dari .NET hampir isomorfik.
C ++, bagaimanapun, menawarkan ruang nama, fasilitas berbeda untuk mencapai tujuan yang sama, dan secara aktif menggunakannya dalam implementasi perpustakaan standarnya. Menambahkan lapisan tambahan kelas statis tidak hanya tidak perlu, tetapi juga agak berlawanan dengan pembaca tanpa C # atau latar belakang Java. Dalam arti tertentu, Anda memperkenalkan "terjemahan pinjaman" ke dalam bahasa untuk sesuatu yang dapat diekspresikan secara asli.
Ketika fungsi Anda perlu berbagi data, situasinya berbeda. Karena fungsi Anda tidak lagi terkait , pola Singleton menjadi cara yang disukai untuk menangani persyaratan ini.
sumber
Mungkin Anda perlu bertanya mengapa Anda ingin kelas yang serba statis?
Satu-satunya alasan yang dapat saya pikirkan adalah bahwa bahasa lain (Java dan C #) yang sangat banyak 'semuanya adalah kelas' memerlukannya. Bahasa-bahasa ini tidak dapat membuat fungsi tingkat atas sama sekali, jadi mereka menciptakan trik untuk menjaganya, dan itu adalah fungsi anggota statis. Mereka sedikit solusi, tetapi C ++ tidak memerlukan hal seperti itu, Anda dapat membuat fungsi tingkat atas, independen yang baru secara langsung.
Jika Anda membutuhkan fungsi yang beroperasi pada item data tertentu, maka masuk akal untuk menggabungkannya ke dalam kelas yang menyimpan data, tetapi kemudian, ini berhenti menjadi fungsi dan mulai menjadi anggota kelas yang beroperasi pada data kelas.
Jika Anda memiliki fungsi yang tidak beroperasi pada tipe data tertentu (saya menggunakan kata di sini karena kelas adalah cara untuk mendefinisikan tipe data baru) maka itu benar-benar merupakan anti-pola untuk mendorong mereka ke dalam kelas, tidak lain dari tujuan semantik.
sumber
Dengan kata lain memiliki kelas bukan namespace tidak memiliki keuntungan.
Untuk satu hal itu menghemat Anda mengetik
static
sepanjang waktu, meskipun itu bisa dibilang manfaat yang agak kecil.Manfaat utama adalah itu adalah alat paling tidak ampuh untuk pekerjaan itu. Kelas dapat digunakan untuk membuat objek, mereka dapat digunakan sebagai jenis variabel atau sebagai argumen templat. Tak satu pun dari itu adalah fitur yang Anda inginkan untuk koleksi fungsi Anda. Jadi lebih baik menggunakan alat yang tidak memiliki fitur-fitur itu, sehingga kelas tidak dapat disalahgunakan secara tidak sengaja.
Mengikuti dari yang menggunakan namespace membuatnya juga segera jelas bagi pengguna kode Anda bahwa ini adalah kumpulan fungsi dan bukan cetak biru untuk membuat objek dari.
sumber
Kelas yang serba statis akan menyelesaikannya, tetapi rasanya seperti mengendarai truk semi 53 kaki ke toko bahan makanan untuk membeli keripik dan salsa ketika sedan empat pintu akan melakukan (yaitu, itu terlalu banyak). Kelas datang dengan sedikit overhead tambahan dan keberadaan mereka mungkin memberi seseorang kesan bahwa instantiasi mungkin ide yang bagus. Fungsi gratis yang ditawarkan oleh C ++ (dan C, di mana semua fungsi gratis) tidak melakukan itu; mereka hanya fungsi dan tidak ada yang lain.
Tidak juga. Tujuan asli dari
static
dalam C (dan kemudian C ++) adalah untuk menawarkan penyimpanan persisten yang dapat digunakan di semua tingkat ruang lingkup:Anda bisa mengambil cakupan ke tingkat file, yang membuatnya terlihat oleh semua ruang lingkup yang lebih sempit tetapi tidak di luar file:
Seorang anggota kelas statis pribadi di C ++ melayani tujuan yang sama tetapi terbatas pada ruang lingkup kelas. Teknik yang digunakan dalam
counter()
contoh di atas juga berfungsi di dalam metode C ++ dan sesuatu yang saya benar-benar sarankan lakukan jika variabel tidak perlu terlihat oleh seluruh kelas.sumber
Jika suatu fungsi tidak mempertahankan keadaan dan reentrant, tampaknya tidak ada banyak gunanya mendorongnya di dalam kelas, (kecuali dipaksa oleh bahasa). Jika fungsi mempertahankan beberapa keadaan, (mis. Itu hanya dapat dibuat aman dengan menggunakan mutex statis), maka metode statis pada kelas tampak sesuai.
sumber
Banyak wacana tentang topik di sini masuk akal, meskipun ada sesuatu yang sangat mendasar tentang C ++ yang membuat
namespaces
danclass
es /struct
s sangat berbeda.Kelas statis (kelas di mana semua anggota statis, dan kelas tidak akan pernah dipakai) adalah objek itu sendiri. Mereka bukan hanya
namespace
berisi fungsi.Meta-pemrograman template memungkinkan kita untuk menggunakan kelas statis sebagai objek waktu kompilasi.
Pertimbangkan ini:
Untuk menggunakannya kita perlu fungsi yang terkandung di dalam kelas. Namespace tidak akan berfungsi di sini. Mempertimbangkan:
Sekarang untuk menggunakannya:
Selama pengalokasi baru memperlihatkan
allocate
danrelease
fungsi yang kompatibel, beralih ke pengalokasi baru itu mudah.Ini tidak dapat dicapai dengan ruang nama.
Apakah Anda selalu membutuhkan fungsi untuk menjadi bagian dari kelas? Tidak.
Apakah menggunakan kelas statis merupakan anti-pola? Itu tergantung pada konteksnya.
Dalam hal ini apa yang ingin Anda capai kemungkinan besar akan dilayani melalui pemrograman berorientasi objek.
sumber
Seperti yang dikatakan John Carmack dengan terkenal:
"Kadang-kadang, implementasi elegan hanya fungsi. Bukan metode. Bukan kelas. Bukan kerangka kerja. Hanya fungsi."
Saya pikir itu cukup banyak. Mengapa Anda membuatnya dengan paksa kelas jika itu jelas bukan kelas? C ++ memiliki kemewahan yang sebenarnya bisa Anda gunakan fungsinya; di Jawa, semuanya adalah metode. Maka Anda memerlukan kelas utilitas, dan banyak dari mereka.
sumber