Katakanlah saya memiliki, atau akan menulis, serangkaian fungsi terkait. Katakanlah itu terkait matematika. Secara organisasi, saya harus:
- Tulis fungsi-fungsi ini dan letakkan di my
MyMath
namespace dan lihat melaluiMyMath::XYZ()
- Buat kelas yang dipanggil
MyMath
dan buat metode ini statis dan lihat yang serupaMyMath::XYZ()
Mengapa saya memilih salah satu dari yang lain sebagai cara mengatur perangkat lunak saya?
c++
namespaces
static-methods
RobertL
sumber
sumber
Jawaban:
Secara default, gunakan fungsi namespaced.
Kelas adalah untuk membangun objek, bukan untuk mengganti ruang nama.
Dalam kode Berorientasi Objek
Scott Meyers menulis seluruh Item untuk buku C ++ Efektifnya tentang topik ini, "Lebih suka fungsi bukan teman yang bukan anggota daripada fungsi anggota". Saya menemukan referensi online untuk prinsip ini dalam sebuah artikel dari Herb Sutter:http://www.gotw.ca/gotw/084.htm
Yang penting untuk diketahui adalah bahwa: Dalam fungsi C ++ di namespace yang sama dengan kelas milik antarmuka kelas itu (karena ADL akan mencari fungsi-fungsi itu ketika menyelesaikan panggilan fungsi).
Fungsi dengan nama tempat, kecuali dinyatakan sebagai "teman," tidak memiliki akses ke internal kelas, sedangkan metode statis memiliki.
Ini berarti, misalnya, bahwa ketika mempertahankan kelas Anda, jika Anda perlu mengubah internal kelas Anda, Anda perlu mencari efek samping dalam semua metodenya, termasuk yang statis.
Ekstensi I
Menambahkan kode ke antarmuka kelas.
Di C #, Anda bisa menambahkan metode ke kelas bahkan jika Anda tidak memiliki akses ke sana. Tetapi dalam C ++, ini tidak mungkin.
Tapi, masih di C ++, Anda masih bisa menambahkan fungsi namespaced, bahkan ke kelas yang dituliskan untuk Anda.
Lihat dari sisi lain, ini penting ketika mendesain kode Anda, karena dengan meletakkan fungsi Anda di namespace, Anda akan mengotorisasi pengguna Anda untuk menambah / melengkapi antarmuka kelas.
Ekstensi II
Efek samping dari poin sebelumnya, tidak mungkin untuk mendeklarasikan metode statis dalam banyak header. Setiap metode harus dideklarasikan di kelas yang sama.
Untuk ruang nama, fungsi dari namespace yang sama dapat dideklarasikan dalam banyak header (fungsi swap yang hampir standar adalah contoh terbaik dari itu).
Perpanjangan III
Kesejukan dasar namespace adalah bahwa dalam beberapa kode, Anda dapat menghindari menyebutkannya, jika Anda menggunakan kata kunci "menggunakan":
Dan Anda bahkan dapat membatasi "polusi" ke satu kelas:
"Pola" ini wajib untuk penggunaan yang tepat dari idiom swap yang hampir standar.
Dan ini tidak mungkin dilakukan dengan metode statis di kelas.
Jadi, namespace C ++ memiliki semantik sendiri.
Tapi itu lebih jauh, karena Anda dapat menggabungkan ruang nama dengan cara yang mirip dengan warisan.
Misalnya, jika Anda memiliki namespace A dengan fungsi AAA, namespace B dengan fungsi BBB, Anda dapat mendeklarasikan namespace C, dan membawa AAA dan BBB di namespace ini dengan menggunakan kata kunci.
Kesimpulan
Ruang nama adalah untuk ruang nama. Kelas adalah untuk kelas.
C ++ dirancang sehingga setiap konsep berbeda, dan digunakan secara berbeda, dalam kasus yang berbeda, sebagai solusi untuk masalah yang berbeda.
Jangan gunakan kelas saat Anda membutuhkan ruang nama.
Dan dalam kasus Anda, Anda perlu ruang nama.
sumber
Ada banyak orang yang tidak setuju dengan saya, tetapi ini adalah bagaimana saya melihatnya:
Kelas pada dasarnya adalah definisi dari jenis objek tertentu. Metode statis harus mendefinisikan operasi yang terkait erat dengan definisi objek.
Jika Anda hanya akan memiliki sekelompok fungsi terkait yang tidak terkait dengan objek yang mendasari atau definisi jenis objek , maka saya akan mengatakan pergi dengan namespace saja. Bagi saya, secara konseptual, ini jauh lebih masuk akal.
Misalnya, dalam kasus Anda, tanyakan pada diri sendiri, "Apa itu MyMath?" Jika
MyMath
tidak mendefinisikan jenis objek, maka saya akan mengatakan: jangan membuatnya menjadi kelas.Tapi seperti yang saya katakan, saya tahu ada banyak orang yang (bahkan dengan keras) tidak setuju dengan saya dalam hal ini (khususnya, pengembang Java dan C #).
sumber
typedef
menggunakannya, menggunakannya sebagai parameter templat, dll.Kalau tidak, gunakan fungsi namespace.
Menanggapi komentar: ya, metode statis dan data statis cenderung terlalu banyak digunakan. Itu sebabnya saya hanya menawarkan dua skenario terkait yang menurut saya bisa membantu. Dalam contoh spesifik OP (satu set rutin matematika), jika ia ingin kemampuan untuk menentukan parameter - katakanlah, tipe data inti dan presisi keluaran - yang akan diterapkan pada semua rutinitas, ia mungkin melakukan sesuatu seperti:
Jika Anda tidak membutuhkannya, maka dengan segala cara menggunakan namespace.
sumber
template
argumen!Anda harus menggunakan namespace, karena namespace memiliki banyak keunggulan dibandingkan kelas:
using
menjadi anggota kelas; kamu bisausing
menjadi anggota namespaceusing class
, meskipunusing namespace
tidak selalu merupakan ide yang bagusAnggota statis, menurut saya, sangat sering digunakan. Mereka bukanlah kebutuhan nyata dalam banyak kasus. Fungsi anggota statis mungkin lebih baik sebagai fungsi lingkup file, dan anggota data statis hanyalah objek global dengan reputasi yang lebih baik dan tidak layak.
sumber
inline
kata kunci untuk memenuhi ODR.inline
, dan BUKAN "inlining" tubuh fungsi. Tujuan nyata (dan dijamin oleh standar)inline
adalah untuk mencegah berbagai definisi. Baca tentang "Aturan Satu Definisi" untuk C ++. Selain itu, pertanyaan SO yang ditautkan tidak dikompilasi karena masalah header yang sudah dikompilasi, bukan masalah ODR.Saya lebih suka namespace, dengan cara itu Anda dapat memiliki data pribadi dalam namespace anonim dalam file implementasi (jadi itu tidak harus muncul di header sama sekali sebagai lawan
private
anggota). Manfaat lain adalah bahwa denganusing
namespace Anda, klien metode dapat memilih untuk tidak menentukanMyMath::
sumber
Satu lagi alasan untuk menggunakan kelas - Opsi untuk memanfaatkan penentu akses. Anda kemudian dapat memecah metode statis publik Anda menjadi metode pribadi yang lebih kecil. Metode publik dapat memanggil beberapa metode pribadi.
sumber
private
metode lebih mudah diakses daripada metode yang prototipenya tidak diterbitkan sama sekali di header (dan dengan demikian, tetap tidak terlihat). Saya bahkan tidak menyebutkan enkapsulasi yang lebih baik yang ditawarkan oleh fungsi namespace anonim..cpp
file yang akan membuatnya pribadi untuk unit terjemahan tanpa memberikan informasi berlebihan kepada siapa pun yang membaca file header. Secara efektif, saya mencoba mengadvokasi untuk idiom PIMPL..cpp
file jika Anda ingin menggunakan templat.Baik namespace dan metode kelas memiliki kegunaannya. Namespace memiliki kemampuan untuk disebarkan ke seluruh file, namun itu adalah kelemahan jika Anda perlu menegakkan semua kode terkait untuk masuk dalam satu file. Seperti disebutkan di atas, kelas juga memungkinkan Anda membuat anggota statis privat di kelas. Anda dapat memilikinya di namespace anonim dari file implementasi namun masih lingkup yang lebih besar daripada memilikinya di dalam kelas.
sumber
private:
orang. dan dalam banyak kasus di mana akses istimewa tampaknya diperlukan, itu dapat diperhitungkan. fungsi paling 'pribadi' adalah yang tidak muncul di header.private:
metode tidak pernah dapat menikmati manfaat ini.