Tampaknya C memiliki objek semu sendiri seperti 'struct' yang dapat dianggap sebagai objek (dengan cara tingkat tinggi yang biasanya kita pikirkan).
Dan juga, file C sendiri pada dasarnya terpisah "modul", kan? Lalu bukankah modul juga seperti 'objek'? Saya bingung mengapa C, yang tampaknya sangat mirip dengan C ++, dianggap sebagai bahasa "prosedural" tingkat rendah di mana C ++ adalah tingkat tinggi "berorientasi objek"
* edit: (klarifikasi) mengapa dan di mana, apakah garis digambar, untuk apa 'objek' itu, dan bukan?
object-oriented
procedural
Dark Templar
sumber
sumber
Jawaban:
Mari bersama-sama Anda dan saya membaca halaman Wikipedia tentang pemrograman berorientasi objek dan memeriksa fitur struct C-style yang sesuai dengan apa yang secara tradisional dianggap sebagai gaya berorientasi objek:
Apakah C struct terdiri dari bidang dan metode bersama dengan interaksinya ? Tidak.
Apakah C struct melakukan hal-hal ini dengan cara "kelas satu"? Tidak. Bahasa ini menentang Anda di setiap langkah.
Apakah C struct melakukan ini? Tidak.
Apakah C struct melakukan ini? Iya.
Tidak.
Bisakah struct sendiri mengirim dan menerima pesan? Tidak. Bisakah data diproses? Tidak.
Apakah ini terjadi di C? Tidak.
Apakah ada fitur C struct ini? Tidak.
Menurut Anda karakteristik struct mana yang menurut Anda "berorientasi objek"? Karena saya tidak dapat menemukan apa pun selain fakta bahwa struct mendefinisikan jenis .
Sekarang, tentu saja Anda dapat membuat struct yang memiliki bidang yang menjadi penunjuk fungsi. Anda bisa membuat struct memiliki bidang yang pointer ke array pointer fungsi, sesuai dengan tabel metode virtual. Dan seterusnya. Anda tentu saja dapat meniru C ++ dalam C. Tapi itu adalah cara yang sangat non-idiomatis untuk memprogram dalam C; Anda akan lebih baik hanya menggunakan C ++.
Sekali lagi, karakteristik modul apa yang Anda pikirkan yang membuatnya bertindak seperti objek? Apakah modul mendukung abstraksi, enkapsulasi, pengiriman pesan, modularitas, polimorfisme, dan pewarisan?
Abstraksi dan enkapsulasi cukup lemah. Jelas modul bersifat modular; itu sebabnya mereka disebut modul. Perpesanan? Hanya dalam arti bahwa panggilan metode adalah pesan dan modul dapat berisi metode. Polimorfisme? Nggak. Warisan? Nggak. Modul adalah kandidat yang cukup lemah untuk "objek".
sumber
Kata kuncinya adalah "berorientasi", bukan "objek". Bahkan kode C ++ yang menggunakan objek tetapi menggunakannya seperti struct tidak berorientasi objek .
C dan C ++ keduanya dapat melakukan OOP (selain dari tidak ada kontrol akses di C), tetapi sintaks untuk melakukannya di C tidak nyaman (untuk sedikitnya), sedangkan sintaks di C ++ membuatnya sangat mengundang. C berorientasi pada prosedural, sedangkan C ++ berorientasi pada objek, meskipun kemampuan inti hampir identik dalam hal itu.
Kode yang menggunakan objek untuk mengimplementasikan desain yang hanya dapat dilakukan dengan objek (biasanya berarti mengambil keuntungan dari polimorfisme) adalah kode berorientasi objek. Kode yang menggunakan objek sedikit lebih banyak daripada kantung data, bahkan menggunakan pewarisan dalam bahasa berorientasi objek, sebenarnya hanya kode prosedural yang lebih rumit dari yang seharusnya. Kode dalam C yang menggunakan pointer fungsi yang diubah pada saat runtime dengan struct penuh data agak melakukan polimorfisme, dan bisa dikatakan "berorientasi objek", bahkan dalam bahasa yang berorientasi prosedural.
sumber
Berdasarkan kepala sekolah tingkat tertinggi:
Objek adalah enkapsulasi data dan perilaku dalam cara yang saling terkait sehingga mereka beroperasi secara keseluruhan yang dapat instantiate beberapa kali dan bekerja sebagai kotak hitam jika Anda tahu antarmuka eksternal.
Struct berisi data tetapi tidak ada perilaku dan karenanya tidak dapat dianggap objek.
Modul berisi perilaku dan data tetapi tidak dienkapsulasi sedemikian rupa sehingga keduanya terkait dan tentu saja tidak dapat dipakai berulang kali.
Dan itu sebelum Anda mendapatkan warisan dan polimorfisme ...
sumber
"struct" hanya data. Tes cepat dan kotor yang biasa dari "orientasi objek" adalah: "Apakah ada struktur yang memungkinkan kode dan data untuk dienkapsulasi sebagai satu unit?". C gagal, dan karenanya prosedural. C ++ melewati tes itu.
sumber
this
pointer eksplisit , tetapi dalam hal ini, data dan sarana untuk memproses data akan dienkapsulasi di dalam struktur.#include
d ke dalamnya, dan minus apapun dihapus dengan tidak kondisional termasuk (#if
,#ifdef
, dan sejenisnya).C, seperti halnya C ++, memiliki kemampuan menyediakan Abstraksi Data , yang merupakan salah satu ungkapan dari paradigma pemrograman berorientasi objek yang ada sebelumnya.
OOP dalam C ++ memperluas sarana untuk data abstrak. Beberapa mengatakan itu berbahaya , sementara yang lain menganggapnya sebagai alat yang baik bila digunakan dengan benar.
Namun, Anda akan menemukan banyak C "peretas" berkhotbah tentang bagaimana C mampu melakukan abstraksi dengan jumlah yang tepat dan bagaimana overhead yang dibuat oleh C ++ hanya mengalihkan mereka dari penyelesaian masalah yang sebenarnya.
Yang lain cenderung melihatnya dengan cara yang lebih seimbang, menerima baik kelebihan maupun kekurangannya.
sumber
Anda perlu melihat sisi lain dari koin: C ++.
Dalam OOP, kami memikirkan objek abstrak (dan merancang program yang sesuai), misalnya mobil yang dapat berhenti, berakselerasi, belok kiri atau kanan, dll. Sebuah struct dengan bundel fungsi sama sekali tidak sesuai dengan konsep.
Dengan objek "nyata" kita perlu menyembunyikan anggota misalnya, atau kita juga dapat memiliki warisan dengan "nyata" hubungan dan banyak lagi.
SETELAH MEMBACA KOMENTAR DI BAWAH INI: Ya benar bahwa (hampir) semuanya dapat dilakukan dengan C (itu selalu benar), tetapi pada pandangan pertama saya berpikir bahwa apa yang membedakan c dari c ++ adalah cara Anda berpikir ketika merancang sebuah program.
Satu-satunya hal yang benar-benar membuat perbedaan adalah penerapan kebijakan oleh kompiler . yaitu fungsi virtual murni, dan semacamnya. tetapi jawaban ini hanya akan berhubungan dengan masalah teknis, tapi saya pikir perbedaan utama (seperti yang disebutkan) adalah cara asli yang Anda pikirkan saat Anda kode, karena C ++ memberi Anda sintaks bawaan yang lebih baik untuk melakukan hal-hal seperti itu, daripada melakukan OOP di cara yang agak canggung di C.
sumber
Anda semacam mengatakannya sendiri. Sementara C memiliki benda-benda yang mirip objek, mereka masih bukan objek, dan itulah sebabnya C tidak dianggap sebagai bahasa OOP.
sumber
Berorientasi Objek mengacu pada pola arsitektur (atau bahkan pola-meta), dan, bahasa yang memiliki fitur untuk membantu mengimplementasikan atau mengamanatkan penggunaan pola ini.
Anda dapat menerapkan desain "OO" (Gnome desktop mungkin adalah contoh terbaik dari OO yang dilakukan dalam C murni), saya bahkan telah melihat ini dilakukan dengan COBOL!
Namun mampu menerapkan dosis desain OO tidak membuat bahasa OO. Purist akan berpendapat bahwa Java dan C ++ tidak benar-benar OO karena Anda tidak dapat menimpa atau mewarisi "tipe" dasar seperti "int" dan "char", dan, Java tidak mendukung multiple inheritance. Tetapi karena mereka adalah bahasa OO yang paling banyak digunakan dan mendukung sebagian besar paradigma yang paling "nyata" programmer yang dibayar untuk menghasilkan kode kerja menganggap mereka sebagai bahasa OO.
C di sisi lain hanya mendukung struktur (seperti halnya COBOL, Pascal, dan puluhan bahasa prosedural lainnya), Anda dapat berargumen bahwa mendukung banyak pewarisan karena Anda dapat menggunakan fungsi apa pun pada bagian data apa pun, tetapi sebagian besar akan menganggap ini sebagai bug. dari fitur.
sumber
Mari kita lihat definisi OO:
C tidak memberikan ketiganya. Secara khusus, itu tidak menyediakan Olahpesan , yang merupakan yang paling penting.
sumber
static
fungsi internal ( ) dan anggota data.Ada sejumlah bahan utama untuk OO, tetapi yang besar adalah bahwa sebagian besar kode tidak tahu apa yang ada di dalam objek (mereka melihat antarmuka permukaan, bukan implementasinya), bahwa keadaan suatu objek adalah unit yang dikelola (Yaitu, ketika objek berhenti menjadi, begitu juga keadaannya), dan ketika beberapa kode memanggil operasi pada objek, mereka melakukannya tanpa tahu persis apa operasi itu atau melibatkan (semua yang mereka lakukan adalah mengikuti pola untuk melempar "Pesan" di dinding).
C tidak enkapsulasi dengan baik; kode yang tidak melihat definisi struktur tidak dapat (secara sah) mengintip ke dalamnya. Yang perlu Anda lakukan adalah memasukkan definisi seperti ini di file header:
Tentu saja, akan ada kebutuhan untuk fungsi yang membangun
Foo
(yaitu, pabrik) dan yang harus mendelegasikan beberapa pekerjaan ke objek yang dialokasikan itu sendiri (yaitu, melalui metode "konstruktor"), dan juga memiliki cara membuang objek lagi (sambil membiarkannya membersihkan melalui metode "destruktor") tapi itu detail.Metode pengiriman (yaitu, pengiriman pesan) juga dapat dilakukan melalui konvensi bahwa elemen pertama dari struktur sebenarnya adalah pointer ke struktur yang penuh dengan pointer fungsi, dan bahwa masing-masing pointer fungsi tersebut harus menggunakan
Foo
argumen pertama. Pengiriman kemudian menjadi masalah mencari fungsi dan memanggilnya dengan penulisan ulang argumen yang tepat, yang tidak sulit dilakukan dengan makro dan sedikit kelicikan. (Tabel fungsi tersebut adalah inti dari apa sebenarnya kelas dalam bahasa seperti C ++.)Selain itu, itu memberi Anda keterlambatan mengikat juga: semua kode pengiriman tahu adalah bahwa itu melibatkan offset tertentu ke dalam tabel yang ditunjuk oleh objek. Itu hanya perlu diatur selama alokasi dan inisialisasi objek. Dimungkinkan untuk menggunakan skema pengiriman yang lebih kompleks yang memberi Anda lebih banyak dinamika runtime (dengan biaya kecepatan) tetapi mereka ceri di atas mekanisme dasar.
Namun itu tidak berarti bahwa C adalah bahasa OO. Kuncinya adalah bahwa C membiarkan Anda melakukan sendiri semua pekerjaan rumit dengan menulis sendiri konvensi dan mekanisme pengiriman (atau menggunakan perpustakaan pihak ketiga). Itu banyak pekerjaan. Ini juga tidak memberikan dukungan sintaksis atau semantik, sehingga menerapkan sistem kelas penuh (dengan hal-hal seperti warisan) akan sangat menyakitkan; jika Anda berurusan dengan masalah kompleks yang digambarkan dengan baik oleh model OO, bahasa OO akan sangat berguna dalam menulis solusinya. Kompleksitas ekstra dapat dibenarkan.
sumber
Saya pikir C sangat baik dan layak untuk menerapkan konsep berorientasi objek, mengangkat bahu . Sebagian besar perbedaan seperti yang saya lihat di antara subset penyebut umum bahasa yang dianggap berorientasi objek bersifat kecil dan sintaksis dari sudut pandang pragmatis saya.
Mari kita mulai dengan, katakanlah, menyembunyikan informasi. Dalam C kita dapat mencapai itu hanya dengan menyembunyikan definisi struktur dan bekerja dengannya melalui pointer buram. Itu secara efektif memodelkan perbedaan
public
vsprivate
bidang data seperti yang kita dapatkan dengan kelas. Dan itu cukup mudah dilakukan dan hampir tidak anti-idiomatik, karena pustaka C standar sangat bergantung pada ini untuk mencapai penyembunyian informasi.Tentu saja Anda kehilangan kemampuan untuk dengan mudah mengontrol dengan tepat di mana struktur dialokasikan dalam memori dengan menggunakan jenis buram, tetapi itu hanya perbedaan yang patut diperhatikan antara, katakanlah, C dan C ++. C ++ jelas merupakan alat yang unggul ketika membandingkan kemampuannya untuk memprogram konsep-konsep berorientasi objek lebih dari C sambil tetap mempertahankan kontrol atas tata letak memori, tetapi itu tidak berarti bahwa Java atau C # lebih unggul daripada C dalam hal itu, karena keduanya membuat Anda benar-benar kehilangan kemampuan untuk mengontrol di mana objek dialokasikan dalam memori.
Dan kita harus menggunakan sintaksis seperti
fopen(file, ...); fclose(file);
sebagai lawanfile.open(...); file.close();
tetapi teriakan besar. Siapa yang peduli? Mungkin hanya seseorang yang sangat bersandar pada penyelesaian otomatis dalam IDE mereka. Saya akui itu bisa menjadi fitur yang sangat berguna dari sudut pandang praktis, tapi mungkin bukan yang mengharuskan diskusi tentang apakah suatu bahasa cocok untuk OOP.Kami tidak memiliki kemampuan untuk mengimplementasikan
protected
bidang secara efektif . Saya akan benar-benar tunduk di sana. Tetapi saya tidak berpikir ada aturan konkret yang mengatakan, " Semua bahasa OO harus memiliki fitur untuk memungkinkan subclass mengakses anggota kelas dasar yang masih belum dapat diakses oleh klien normal ." Selain itu saya jarang melihat kasus penggunaan untuk anggota yang dilindungi yang setidaknya tidak sedikit curiga menjadi rintangan pemeliharaan.Dan tentu saja kita harus "meniru" polimorfisme OO dengan tabel fungsi pointer dan pointer ke mereka untuk pengiriman dinamis dengan sedikit lebih boilerplate untuk menginisialisasi analog
vtables
danvptrs
, tetapi sedikit boilerplate tidak pernah menyebabkan saya banyak kesedihan.Warisan adalah cara yang sama. Kita dapat dengan mudah memodelkan itu melalui komposisi, dan pada cara kerja internal kompiler itu bermuara pada hal yang sama. Tentu saja kita kehilangan keamanan tipe jika kita ingin downcast , dan di sana saya katakan jika Anda ingin downcasting sama sekali, untuk tolong jangan menggunakan C untuk itu karena hal-hal yang dilakukan orang di C untuk meniru downcasting dapat mengerikan dari suatu tipe sudut pandang keamanan, tapi saya lebih suka orang tidak downcast sama sekali. Jenis keamanan adalah sesuatu yang Anda dapat dengan mudah mulai ketinggalan dalam C karena kompiler menyediakan begitu banyak kelonggaran untuk menafsirkan hal-hal hanya sebagai bit dan byte, mengorbankan kemampuan untuk menangkap calon kesalahan pada waktu kompilasi, tetapi beberapa bahasa dianggap berorientasi objek bukan bahkan diketik secara statis.
Tidak tahu, saya pikir tidak apa-apa. Tentu saja saya tidak akan menggunakan C untuk mencoba membuat basis kode skala besar yang sesuai dengan prinsip-prinsip SOLID, tapi itu belum tentu karena kedatangannya yang pendek di bidang berorientasi objek. Banyak fitur yang akan saya lewatkan jika saya mencoba menggunakan C untuk tujuan seperti itu akan terkait dengan fitur bahasa yang tidak secara langsung dianggap sebagai prasyarat untuk OOP seperti keselamatan tipe kuat, destruktor yang secara otomatis dipanggil ketika benda keluar dari ruang lingkup, operator kelebihan muatan, templat / generik, dan penanganan pengecualian. Saat itulah saya kehilangan fitur tambahan yang saya raih untuk C ++.
sumber
foo_create
danfoo_destroy
danfoo_clone
, misalnyastruct Foo
dalam kasus seperti ini adalah untuk memastikan anggota datanya tidak dapat diakses dan dimutasi oleh dunia luar, yang diberikan oleh tipe-tipe buram (dideklarasikan tetapi tidak didefinisikan ke dunia luar) segera. Ini bisa dibilang bentuk yang lebih kuat dari penyembunyian informasi, setara dengan yang adapimpl
di C ++.Bukan pertanyaan yang buruk.
Jika Anda akan memanggil c bahasa OO Anda perlu memanggil semua bahasa prosedural OO juga. Jadi itu akan membuat istilah itu tidak berarti. c tidak memiliki dukungan bahasa untuk OO. Jika memiliki struct, tetapi struct tidak
types
ada kelas.Sebenarnya c tidak memiliki banyak fitur sama sekali dibandingkan dengan kebanyakan bahasa. Ini sebagian besar digunakan untuk kecepatan, kesederhanaan, popularitas dan dukungan termasuk banyak perpustakaan.
sumber