Kata pengantar
Judul "Masalah mengurangi aksesibilitas subkelas atas fungsi kelas orang tua di Java dan C ++" tampaknya lebih akademis, tetapi memang masalah yang mudah diabaikan. Artikel ini berusaha untuk menguraikan perbedaan antara masalah ini di Java dan C ++.
Pertama, kami akan memperkenalkan apa itu pengurangan aksesibilitas "subkelas" atas cakupan fungsi kelas induk ". Untuk warisan, subclass dapat mengganti "fungsi virtual" dari kelas induk - meskipun tidak ada istilah fungsi virtual di java, semua fungsi java dapat dianggap sebagai fungsi virtual, karena semua fungsi java dapat ditimpa oleh subkelas. Di sini kita hanya meminjam makna istilah "fungsi virtual" dan tidak menggali detail bahasa. Java dan C ++ memungkinkan mengubah aksesibilitas fungsi saat mengesampingkan. Yang disebut "aksesibilitas" adalah menggunakan karakter kontrol akses seperti publik, terlindungi, dan pribadi untuk memodifikasinya untuk mengontrol apakah fungsi tersebut dapat diakses. Biasanya urutan aksesibilitas adalah (karena tidak ada konsep paket dalam C ++, kontrol akses paket tidak dipertimbangkan untuk saat ini, yang tidak mempengaruhi diskusi di sini):
Publik> Dilindungi> Pribadi
Ambil Java sebagai contoh:
class base {protected void wayshello () {System.out.println ("Hello in Base"); }} kelas anak memperluas basis {public void sayshello () {System.out.println ("Hello in Child"); }} Catatan: Fungsi sayHello() di sini. Di basis kelas induk, fungsi ini dimodifikasi menggunakan karakter kontrol akses yang dilindungi. Dan subkelas menggunakan publik sebagai gantinya, tidak akan ada masalah. Ketika subclass mengganti fungsi kelas orang tua, memperluas aksesibilitas biasanya bukan masalah.
Java dan C ++ mengadopsi strategi yang berbeda ketika subclass mengurangi aksesibilitas ke fungsi kelas induk.
Pertama, ambil Java sebagai contoh dan lihat kode berikut:
basis kelas {public void sayshello () {System.out.println ("Hello in Base"); }} kelas anak memperluas base {private void sayshello () {System.out.println ("Hello in Child"); }}Dalam kode di atas, akan ada kesalahan kompilasi pada baris 8 yang disorot - kode ini tidak dapat dikompilasi sama sekali! Java tidak mengizinkan subclass untuk mengurangi aksesibilitas saat menimpa fungsi kelas orang tua. Adapun alasannya, kita dapat menggunakan contoh untuk diilustrasikan. Misalnya, kami menulis kode berikut di luar kelas:
Base base = base baru (); base.sayhello (); base = new child (); base.sayhello ();
Jika kode sebelumnya dapat dikompilasi, ada kemungkinan bahwa ketika basis poin ke basis baru (), sayhello () dapat diakses, tetapi ketika basis titik ke anak baru (), sayhello () tidak dapat diakses! Dalam pandangan Java, ini adalah kontradiksi, dan masalah ini harus dihindari. Oleh karena itu, Java menetapkan dari perspektif kompiler bahwa kami tidak dapat menulis kode di atas.
Untuk C ++, situasinya berbeda. Mari kita lihat contoh C ++:
kelas base {public: virtual void sayshello () {std :: cout << "halo di pangkalan"; }} class child: basis publik {private: void wayshello () {std :: cout << "Hello in Child"; }}Kode ini benar -benar benar di C ++. Perhatikan bahwa subkelas di sini mengurangi aksesibilitas saat menimpa fungsi kelas orang tua. Jika Anda tidak melihat masalah apa pun, maka kami dapat menulis kode berikut di luar kelas:
Anak anak; anak. Sayhello (); // tidak dapat dikompilasi karena sayshello () adalah static_cast <base &> (anak) .sayhello (); // tidak dapat dikompilasi karena sayshello () adalah publik
Panggilan baris 2 gagal karena pada anak, sayHello() bersifat pribadi dan tidak dapat dipanggil secara eksternal. Namun, ketika kami melemparkan anak ke objek dasar menggunakan static_cast, hal -hal berubah - untuk pangkalan, sayHello() bersifat publik, sehingga dapat disebut secara normal.
Untuk tujuan ini, contoh berikut ini dapat ditemukan di bagian Akses ke Fungsi Virtual Bab Kontrol Akses Anggota C ++:
class b {public: virtual int f ();}; kelas d: public b {private: int f ();}; void f () {d d; B* pb = & d; D* PD = & D; pb-> f (); // ok: b :: f () adalah publik, d :: f () dipanggil PD-> f (); // ERROR: D :: f () adalah pribadi}Dalam hal ini, standar C ++ memberikan penjelasan:
Access diperiksa pada titik panggilan menggunakan jenis ekspresi yang digunakan untuk menunjukkan objek yang disebut fungsi anggota (b* dalam contoh di atas). Akses fungsi anggota di kelas di mana ia didefinisikan (d dalam contoh di atas) secara umum tidak diketahui.
Ada dua poin utama untuk terjemahan sederhana:
Karena itu, penelepon C ++ tampaknya dapat "secara cerdik" memanggil fungsi panggilan yang awalnya tidak dapat diakses melalui beberapa transformasi yang terampil. Contoh yang lebih praktis adalah: di QT, fungsi QObject::event() adalah publik, dan fungsi subclass qwidget event() diubah menjadi dilindungi. Untuk detailnya, Anda dapat membaca kode QT yang relevan.
Singkatnya, ketika subclass mengesampingkan fungsi induk, Java benar -benar membatasi bahwa subkelas tidak dapat mempersempit aksesibilitas fungsi, tetapi C ++ tidak memiliki batasan ini. Secara pribadi, saya percaya bahwa dari perspektif rekayasa perangkat lunak, peraturan Java tidak diragukan lagi memiliki signifikansi rekayasa yang lebih, dan panggilan fungsi lebih konsisten. Standar C ++ akan secara signifikan menyederhanakan implementasi kompiler, tetapi ini bukan referensi yang baik untuk rekayasa.
PS: Versi resmi standar C ++ membutuhkan pembelian, tetapi draft dapat diunduh secara gratis. Alamat unduhan draft standar C ++ dapat ditemukan di halaman berikut: https://isocpp.org/std/the-standard
Meringkaskan
Di atas adalah seluruh konten artikel ini. Saya berharap konten artikel ini memiliki nilai referensi tertentu untuk studi atau pekerjaan semua orang. Jika Anda memiliki pertanyaan, Anda dapat meninggalkan pesan untuk berkomunikasi. Terima kasih atas dukungan Anda ke wulin.com.