Dalam menjawab pertanyaan ini , konsensus umum adalah bahwa metode statis tidak dimaksudkan untuk ditimpa (dan dengan demikian fungsi statis di C # tidak boleh virtual atau abstrak). Namun, ini bukan hanya kasus di C #; Java juga melarang ini dan C ++ sepertinya juga tidak suka. Namun, saya dapat memikirkan banyak contoh fungsi statis yang ingin saya timpa dalam kelas anak (misalnya, metode pabrik). Sementara secara teori, ada cara untuk menyiasatinya, tidak ada yang bersih atau sederhana.
Mengapa fungsi statis tidak bisa ditimpa?
object-oriented-design
abstract-class
static-methods
PixelArtDragon
sumber
sumber
self
pointer yang menunjuk ke kelas dan bukan ke instance kelas.Jawaban:
Dengan metode statis, tidak ada objek untuk memberikan kontrol yang tepat terhadap mekanisme override.
Mekanisme metode virtual kelas / instance yang normal memungkinkan untuk mengontrol override yang disetel dengan halus sebagai berikut: setiap objek nyata adalah instance dari satu kelas. Kelas itu menentukan perilaku override; selalu mendapatkan celah pertama pada metode virtual. Kemudian dapat memilih untuk memanggil metode induk pada waktu yang tepat untuk penerapannya. Setiap metode induk kemudian juga mendapat giliran untuk memanggil metode induknya. Ini menghasilkan kaskade bagus dari pemanggilan orang tua, yang memenuhi salah satu konsep penggunaan kembali kode yang dikenal sebagai orientasi objek. (Di sini kode dasar / kelas super digunakan kembali dengan cara yang relatif kompleks; gagasan ortogonal lain tentang penggunaan kembali kode dalam OOP hanya memiliki banyak objek dari kelas yang sama.)
Kelas dasar dapat digunakan kembali oleh berbagai subclass, dan masing-masing dapat hidup berdampingan dengan nyaman. Setiap kelas yang digunakan untuk instantiate objek mendiktekan perilakunya sendiri, secara damai dan bersamaan hidup berdampingan dengan yang lain. Klien memiliki kendali atas perilaku mana yang diinginkan dan kapan dengan memilih kelas mana yang akan digunakan untuk membuat instance objek dan memberikan kepada yang lain sesuai keinginan.
(Ini bukan mekanisme yang sempurna, karena kita selalu dapat mengidentifikasi kemampuan yang tidak didukung, tentu saja, itulah sebabnya pola seperti metode pabrik dan injeksi ketergantungan diletakkan di atas.)
Jadi, jika kita membuat kemampuan menimpa untuk statika tanpa mengubah apa pun, kita akan mengalami kesulitan memesan penggantian. Akan sulit untuk mendefinisikan konteks terbatas untuk penerapan override, sehingga Anda akan mendapatkan override secara global daripada lebih lokal seperti dengan objek. Tidak ada objek instan untuk mengubah perilaku. Jadi, jika seseorang memanggil metode statis yang kebetulan telah ditimpa oleh kelas lain, haruskah override mendapatkan kontrol atau tidak? Jika ada beberapa penggantian semacam itu, siapa yang mendapat kendali lebih dulu? kedua? Dengan mengesampingkan objek instan, semua pertanyaan ini memiliki jawaban yang bermakna dan beralasan, tetapi dengan statika tidak.
Penggantian untuk statika akan sangat kacau, dan, hal-hal seperti ini telah dilakukan sebelumnya.
Misalnya, Mac OS System 7 dan sebelumnya menggunakan mekanisme patch trap untuk memperluas sistem dengan mendapatkan kontrol panggilan sistem buatan aplikasi sebelum sistem operasi. Anda bisa menganggap tabel tambalan panggilan sistem sebagai array penunjuk fungsi, mirip dengan vtable untuk objek contoh, kecuali bahwa itu adalah tabel global tunggal.
Hal ini menyebabkan kesedihan yang tak terhingga bagi para programmer karena sifat patch yang tidak teratur. Siapa pun yang dapat menambal jebakan terakhir pada dasarnya menang, bahkan jika mereka tidak mau. Setiap patcher dari jebakan akan menangkap nilai perangkap sebelumnya untuk semacam kemampuan panggilan induk, yang sangat rapuh. Menghapus tambalan, katakan ketika Anda tidak lagi perlu tahu tentang panggilan sistem dianggap sebagai bentuk yang buruk karena Anda tidak benar-benar memiliki informasi yang diperlukan untuk menghapus tambalan Anda (jika Anda melakukannya, Anda juga akan membuka kancing tambalan lain yang telah mengikuti kamu).
Ini bukan untuk mengatakan bahwa tidak mungkin untuk membuat mekanisme untuk menimpa statika, tetapi apa yang saya lebih suka lakukan adalah mengubah bidang statis dan metode statis menjadi bidang contoh dan metode contoh metaclasses, sehingga objek normal teknik orientasi akan berlaku. Perhatikan bahwa ada sistem yang melakukan ini juga: CSE 341: Kelas Smalltalk dan metaclasses ; Lihat juga: Apa yang dimaksud dengan Smalltalk setara dengan statis Java?
Saya mencoba mengatakan bahwa Anda harus melakukan beberapa desain fitur bahasa yang serius untuk membuatnya bekerja dengan cukup baik. Sebagai contoh, pendekatan naif dilakukan, berjalan pincang, tetapi sangat bermasalah, dan bisa dibilang (yaitu saya berpendapat) secara arsitektur cacat dengan menyediakan abstraksi yang tidak lengkap dan sulit untuk digunakan.
Pada saat Anda selesai merancang fitur penggantian statis agar berfungsi dengan baik, Anda mungkin baru saja menemukan beberapa bentuk metaclasses, yang merupakan perpanjangan alami dari OOP ke / untuk metode berbasis kelas. Jadi, tidak ada alasan untuk tidak melakukan ini - dan beberapa bahasa benar-benar melakukannya. Mungkin sedikit lebih banyak persyaratan tambahan bahwa sejumlah bahasa memilih untuk tidak melakukannya.
sumber
this.instanceMethod()
memiliki resolusi dinamis, jadi jikaself.staticMethod()
memiliki resolusi yang sama, yaitu dinamis, itu tidak akan menjadi metode statis lagi.Mengganti tergantung pada pengiriman virtual: Anda menggunakan tipe runtime dari
this
parameter untuk memutuskan metode mana yang akan dipanggil. Metode statis tidak memilikithis
parameter, jadi tidak ada yang dikirim.Beberapa bahasa, terutama Delphi dan Python, memiliki ruang lingkup "di antara" yang memungkinkan untuk ini: metode kelas. Metode kelas bukan metode contoh biasa, tetapi juga tidak statis; itu menerima
self
parameter (mengejutkan, kedua bahasa memanggilthis
parameterself
) itu adalah referensi ke tipe objek itu sendiri, bukan ke instance dari tipe itu. Dengan nilai itu, sekarang Anda memiliki jenis yang tersedia untuk melakukan pengiriman virtual.Sayangnya, baik JVM maupun CLR tidak memiliki apa pun yang sebanding.
sumber
self
yang memiliki kelas sebagai objek aktual, instantiated dengan metode yang dapat ditimpa - Smalltalk tentu saja, Ruby, Dart, Objective C, Self, Python? Dibandingkan dengan bahasa yang mengambil setelah C ++, di mana kelas bukan objek kelas pertama, bahkan jika ada beberapa akses refleksi?virtual
dan kemudian diganti dalam kelas turunan, seperti metode instance.Anda bertanya
aku bertanya
Bahasa tertentu memaksa Anda untuk memulai pertunjukan dengan metode statis. Tetapi setelah itu Anda benar-benar dapat memecahkan banyak masalah tanpa metode statis sama sekali.
Beberapa orang suka menggunakan metode statis kapan saja tidak ada ketergantungan pada keadaan dalam suatu objek. Beberapa orang suka menggunakan metode statis untuk konstruksi objek lain. Beberapa orang suka menghindari metode statis sebanyak mungkin.
Tidak satu pun dari orang-orang ini yang salah.
Jika Anda perlu ditimpa, berhentilah memberi label statis. Nothings akan pecah karena Anda memiliki objek berkewarganegaraan terbang di sekitar.
sumber
_start()
simbol di Linux). Dalam contoh itu, executable adalah objek (ia memiliki "tabel pengiriman" sendiri dan segalanya) dan titik masuknya adalah operasi yang dikirim secara dinamis. Oleh karena itu, titik masuk program secara inheren virtual ketika dilihat dari luar dan dapat dengan mudah dibuat terlihat virtual jika dilihat dari dalam juga.Ini bukan pertanyaan "harus".
"Overriding" berarti "pengiriman secara dinamis ". "Metode statis" berarti "pengiriman secara statis". Jika ada sesuatu yang statis, itu tidak dapat diganti. Jika sesuatu dapat ditimpa, itu tidak statis.
Pertanyaan Anda agak mirip dengan bertanya: "Mengapa becak tidak bisa memiliki empat roda?" The definisi dari "roda tiga" adalah yang memiliki tiga roda. Jika itu adalah roda tiga, ia tidak dapat memiliki empat roda, jika ia memiliki empat roda, ia tidak dapat menjadi roda tiga. Demikian juga, definisi "metode statis" adalah bahwa ia dikirim secara statis. Jika ini adalah metode statis, itu tidak dapat dikirim secara dinamis, jika dapat dikirim secara dinamis, itu tidak bisa menjadi metode statis.
Tentu saja sangat mungkin untuk memiliki metode kelas yang dapat diganti. Atau, Anda bisa memiliki bahasa seperti Ruby, di mana kelas adalah objek sama seperti objek lainnya dan dengan demikian dapat memiliki metode contoh, yang sepenuhnya menghilangkan kebutuhan metode kelas sama sekali. (Ruby hanya memiliki satu jenis metode: metode instan. Tidak memiliki metode kelas, metode statis, konstruktor, fungsi, atau prosedur.)
sumber
Dalam C #, Anda selalu memanggil anggota statis menggunakan kelas, mis .
BaseClass.StaticMethod()
TidakbaseObject.StaticMethod()
. Jadi pada akhirnya, jika AndaChildClass
mewarisi dariBaseClass
danchildObject
turunan dariChildClass
, Anda tidak akan dapat memanggil metode statis darichildObject
. Anda akan selalu perlu menggunakan kelas nyata secara eksplisit, jadistatic virtual
itu tidak masuk akal.Yang dapat Anda lakukan adalah mendefinisikan kembali
static
metode yang sama di kelas anak Anda, dan menggunakannew
kata kunci.Jika memungkinkan untuk menelepon
baseObject.StaticMethod()
, maka pertanyaan Anda akan masuk akal.sumber