Pertanyaan Perbedaan antara warisan pribadi, publik, dan dilindungi


Apa perbedaan antara public, private, dan protected warisan dalam C ++? Semua pertanyaan yang saya temukan pada SO berurusan dengan kasus-kasus tertentu.


813
2018-05-13 20:47


asal


Jawaban:


Untuk menjawab pertanyaan itu, saya ingin mendeskripsikan aksesor anggota terlebih dahulu dengan kata-kata saya sendiri. Jika Anda sudah mengetahuinya, lompat ke judul "next:".

Ada tiga pengakses yang saya ketahui: public, protected dan private.

Membiarkan:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • Segala sesuatu yang sadar Base juga menyadari itu Base mengandung publicMember.
  • Hanya anak-anak (dan anak-anak mereka) yang sadar akan hal itu Base mengandung protectedMember.
  • Tidak ada yang lain Base menyadari privateMember.

Dengan "menyadari", maksud saya "mengakui keberadaan, dan dengan demikian dapat mengakses".

berikutnya:

Hal yang sama terjadi dengan warisan publik, swasta, dan terlindungi. Mari pertimbangkan kelas Base dan kelas Child yang mewarisi dari Base.

  • Jika warisan itu public, semua yang sadar Base dan Child juga menyadari itu Child mewarisi dari Base.
  • Jika warisan itu protected, saja Child, dan anak-anaknya, sadar bahwa mereka mewarisi dari Base.
  • Jika warisan itu private, tidak ada yang lain selain Child sadar akan warisan.

902
2018-05-13 20:49



class A 
{
public:
    int x;
protected:
    int y;
private:
    int z;
};

class B : public A
{
    // x is public
    // y is protected
    // z is not accessible from B
};

class C : protected A
{
    // x is protected
    // y is protected
    // z is not accessible from C
};

class D : private A    // 'private' is default for classes
{
    // x is private
    // y is private
    // z is not accessible from D
};

CATATAN PENTING: Kelas B, C dan D semuanya mengandung variabel x, y dan z. Itu hanya soal akses.

Tentang penggunaan warisan yang dilindungi dan pribadi yang dapat Anda baca sini.


1221
2017-09-03 11:27



Membatasi visibilitas pewarisan akan membuat kode tidak dapat melihat bahwa beberapa kelas mewarisi kelas lain: Konversi implisit dari turunan ke basis tidak akan berfungsi, dan static_cast dari basis ke turunan tidak akan berfungsi.

Hanya anggota / teman dari kelas yang dapat melihat warisan pribadi, dan hanya anggota / teman dan kelas turunan yang dapat melihat warisan yang dilindungi.

publik warisan

  1. Warisan IS-A. Sebuah tombol adalah jendela, dan di mana saja di mana jendela diperlukan, tombol juga dapat dilewatkan.

    class button : public window { };
    

terlindung warisan

  1. Dilindungi diterapkan-dalam-dari-dari. Sangat berguna. Digunakan dalam boost::compressed_pair untuk memperoleh dari kelas kosong dan menghemat memori menggunakan pengoptimalan kelas dasar kosong (contoh di bawah ini tidak menggunakan template untuk tetap pada titik):

    struct empty_pair_impl : protected empty_class_1 
    { non_empty_class_2 second; };
    
    struct pair : private empty_pair_impl {
      non_empty_class_2 &second() {
        return this->second;
      }
    
      empty_class_1 &first() {
        return *this; // notice we return *this!
      }
    };
    

pribadi warisan

  1. Diimplementasikan-dalam-dari-dari. Penggunaan kelas dasar hanya untuk mengimplementasikan kelas turunan. Berguna dengan sifat dan jika ukuran penting (ciri-ciri kosong yang hanya berisi fungsi akan memanfaatkan pengoptimalan kelas dasar yang kosong). Sering penahanan adalah solusi yang lebih baik. Ukuran untuk string sangat penting, sehingga sering digunakan di sini

    template<typename StorageModel>
    struct string : private StorageModel {
    public:
      void realloc() {
        // uses inherited function
        StorageModel::realloc();
      }
    };
    

publik anggota

  1. Agregat

    class pair {
    public:
      First first;
      Second second;
    };
    
  2. Accessors

    class window {
    public:
        int getWidth() const;
    };
    

terlindung anggota

  1. Menyediakan akses yang ditingkatkan untuk kelas turunan

    class stack {
    protected:
      vector<element> c;
    };
    
    class window {
    protected:
      void registerClass(window_descriptor w);
    };
    

pribadi anggota

  1. Simpan detail penerapan

    class window {
    private:
      int width;
    };
    

Perhatikan bahwa C-gaya gips sengaja memungkinkan pengecoran kelas turunan ke kelas dasar yang dilindungi atau pribadi dengan cara yang ditentukan dan aman dan untuk dilemparkan ke arah lain juga. Ini harus dihindari di semua biaya, karena dapat membuat kode tergantung pada rincian penerapan - tetapi jika perlu, Anda dapat menggunakan teknik ini.


98
2017-09-03 16:04



Ini ada hubungannya dengan bagaimana anggota publik kelas dasar terpapar dari kelas turunan.

  • publik -> anggota publik kelas dasar akan bersifat publik (biasanya default)    
  • dilindungi -> anggota publik kelas dasar akan dilindungi    
  • pribadi -> anggota umum kelas dasar akan menjadi pribadi

Sebagai litb menunjukkan, pewarisan publik adalah warisan tradisional yang akan Anda lihat di sebagian besar bahasa pemrograman. Yaitu model hubungan "IS-A". Warisan privat, sesuatu AFAIK yang khas untuk C ++, adalah hubungan "DITERAPAN DALAM PERSYARATAN". Itu yang kamu mau menggunakan antarmuka publik di kelas turunan, tetapi tidak ingin pengguna kelas turunan memiliki akses ke antarmuka itu. Banyak yang berpendapat bahwa dalam hal ini Anda harus menggabungkan kelas dasar, yaitu alih-alih memiliki kelas dasar sebagai basis pribadi, membuat anggota yang diturunkan untuk menggunakan kembali fungsi kelas dasar.


61
2018-05-13 20:49



Ketiga kata kunci ini juga digunakan dalam konteks yang sepenuhnya berbeda untuk menentukan model pewarisan visibilitas.

Tabel ini mengumpulkan semua kombinasi yang mungkin dari deklarasi komponen dan model pewarisan yang menghadirkan akses yang dihasilkan ke komponen ketika subkelas benar-benar ditentukan.

enter image description here

Tabel di atas ditafsirkan dengan cara berikut (lihat baris pertama):

jika suatu komponen dideklarasikan sebagai publik dan kelasnya diwariskan sebagai publik hasilnya mengakses aku s publik.

Sebuah contoh:

 class Super {
    public:      int p;
    private:     int q;
    protected:   int r;
 };

 class Sub : private Super {};

 class Subsub : public Sub {};

Akses yang dihasilkan untuk variabel p, q, r di kelas Subsub aku s tidak ada.

Contoh lain:

class Super {
    private:     int x;
    protected:   int y;
    public:      int z;
 };
class Sub : protected Super {};

Akses yang dihasilkan untuk variabel y, z di kelas Sub aku s terlindung dan untuk variabel x aku s tidak ada.

Contoh yang lebih detail:

class Super {
private:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};
int main(void) {
    Super object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

Sekarang mari kita mendefinisikan subclass:

class Sub : Super { };

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

Kelas yang didefinisikan bernama Sub yang merupakan subkelas dari kelas bernama Super atau itu Sub kelas berasal dari Super kelas. Itu Sub kelas memperkenalkan baik variabel baru maupun fungsi baru. Apakah ini berarti bahwa objek apa pun dari Sub kelas mewarisi semua sifat setelah Super kelas yang sebenarnya salinan dari Super objek kelas?

Tidak. Itu tidak.

Jika kita mengkompilasi kode berikut, kita tidak akan mendapatkan apa pun kecuali kesalahan kompilasi yang mengatakan itu put dan get metode tidak dapat diakses. Mengapa?

Ketika kita mengabaikan specifier visibilitas, compiler mengasumsikan bahwa kita akan menerapkan apa yang disebut warisan pribadi. Itu berarti semuanya publik komponen superclass berubah menjadi pribadi akses, komponen superclass pribadi tidak akan dapat diakses sama sekali. Ini akibatnya berarti Anda tidak diizinkan untuk menggunakan yang terakhir di dalam subkelas.

Kami harus memberi tahu compiler bahwa kami ingin mempertahankan kebijakan akses yang digunakan sebelumnya.

class Sub : public Super { };

Jangan disesatkan: itu tidak berarti bahwa komponen pribadi dari Super   kelas (seperti variabel penyimpanan) akan berubah menjadi publik dalam   cara yang agak ajaib. Pribadi komponen akan tetap ada pribadi, publikakan bertahan publik.

Objek dari Sub kelas dapat melakukan "hampir" hal yang sama dengan saudara kandungnya yang lebih tua yang diciptakan dari Super kelas. "Hampir" karena fakta menjadi subclass juga berarti bahwa kelas kehilangan akses ke komponen pribadi superclass. Kami tidak dapat menulis fungsi anggota Sub kelas yang akan dapat langsung memanipulasi variabel penyimpanan.

Ini adalah pembatasan yang sangat serius. Apakah ada solusi?

iya nih.

Tingkat akses ketiga disebut terlindung. Kata kunci yang diproteksi berarti komponen yang ditandai dengannya berperilaku seperti publik ketika digunakan oleh salah satu subclass dan tampak seperti yang pribadi ke seluruh dunia. - Ini hanya berlaku untuk kelas yang diwariskan secara publik (seperti kelas Super dalam contoh kami) -

class Super {
protected:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};

class Sub : public Super {
public:
    void print(void) {cout << "storage = " << storage;}
};

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get() + 1);
    object.print();
    return 0;
}

Seperti yang Anda lihat pada contoh kode, kita memiliki fungsi baru pada Sub kelas dan itu melakukan satu hal penting: mengakses variabel penyimpanan dari kelas Super.

Itu tidak akan mungkin jika variabel dinyatakan sebagai pribadi. Dalam ruang lingkup fungsi utama, variabel tetap tersembunyi, jadi jika Anda menulis sesuatu seperti:

object.storage = 0;

Compiler akan memberi tahu Anda bahwa itu adalah error: 'int Super::storage' is protected.

Akhirnya, program terakhir akan menghasilkan output berikut:

storage = 101

40
2018-06-07 16:56



Member in base class : Private   Protected   Public   

Warisan jenis  :Objek diwarisi sebagai:

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public

34
2017-09-09 05:25



1) Warisan Publik:

Sebuah. Anggota pribadi kelas Base tidak dapat diakses di kelas Derived.

b. Anggota kelas Base dilindungi tetap dilindungi di kelas Berasal.

c. Anggota umum kelas Base tetap menjadi publik di kelas Derived.

Jadi, kelas-kelas lain dapat menggunakan anggota umum kelas Base melalui objek kelas Turunan.

2) Warisan yang Dilindungi:

Sebuah. Anggota pribadi kelas Base tidak dapat diakses di kelas Derived.

b. Anggota kelas Base dilindungi tetap dilindungi di kelas Berasal.

c. Anggota umum kelas Base juga menjadi anggota kelas Turunan yang dilindungi.

Jadi, kelas-kelas lain tidak dapat menggunakan anggota umum kelas Base melalui objek kelas Derived; tetapi mereka tersedia untuk subkelas Derived.

3) Warisan Swasta:

Sebuah. Anggota pribadi kelas Base tidak dapat diakses di kelas Derived.

b. Terlindungi & publik anggota kelas Base menjadi anggota pribadi kelas Turunan.

Jadi, tidak ada anggota kelas Base dapat diakses oleh kelas-kelas lain melalui objek kelas Turunan karena mereka pribadi di kelas Berasal. Jadi, bahkan subkelas Derived kelas tidak dapat mengaksesnya.


22
2018-05-26 04:42