Perbedaan antara warisan pribadi, publik, dan dilindungi

Jawaban:

1065

Untuk menjawab pertanyaan itu, saya ingin menggambarkan aksesor anggota pertama dengan kata-kata saya sendiri. Jika Anda sudah tahu ini, lewati ke judul "selanjutnya:".

Ada tiga accesor bahwa aku menyadari: public, protecteddan private.

Membiarkan:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • Segala sesuatu yang disadari Basejuga sadar yang Baseberisi publicMember.
  • Hanya anak-anak (dan anak-anak mereka) yang sadar yang Baseberisi protectedMember.
  • Tidak ada Baseyang menyadari privateMember.

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

lanjut:

Hal yang sama terjadi dengan warisan publik, swasta dan dilindungi. Mari kita pertimbangkan kelas Basedan kelas Childyang mewarisi dari Base.

  • Jika warisan itu public, segala sesuatu yang sadar Basedan Childjuga sadar yang Childmewarisi dari Base.
  • Jika warisan itu protected, hanya Child, dan anak-anaknya, sadar bahwa mereka mewarisinya Base.
  • Jika warisan itu private, tidak ada orang lain Childyang menyadari warisan itu.
Anzurio
sumber
183
Saya ingin menambahkan beberapa kata bahwa visibilitas dalam C ++ didasarkan pada kelas dan bukan pada objek, yang berarti bahwa objek dari kelas yang sama dapat mengakses bidang pribadi masing-masing tanpa batasan.
Zhe Chen
48
Jika Anda kesulitan memahami hal ini, baca jawaban Kirill V. Lyadvinsky, lalu kembali dan baca ini.
The Vivandiere
6
Ini hanyalah kasus lain yang mengilustrasikan bagaimana, sebagian besar, mewarisi dari SomeBasesama seperti cara hardcode untuk menulis-dalam anggota tipe anonim SomeBase. Ini, seperti anggota lainnya, memiliki penentu akses, yang memberikan kontrol yang sama pada akses eksternal.
underscore_d
1
@ZheChen jika saya memiliki objek Tom dan Jerry dari kelas Person dengan usia bidang pribadi bagaimana Anda mengakses (dan memodifikasi?) Usia Jerry menggunakan Tom?
gen
2
Bisakah Anda menggambarkan apa yang Anda maksudkan dengan "sadar akan 'warisan'"? Saya dapat mengerti "saya dapat mengakses ini, saya tidak dapat mengaksesnya" tetapi saya tidak mengerti ketika seseorang berkata "Saya tahu bahwa A mewarisi dari B" apa yang saya lakukan di sini apakah saya memeriksa warisan?
neilxdims
1458
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 berisi variabel x, y dan z. Ini hanya masalah akses.

Tentang penggunaan warisan yang dilindungi dan pribadi, Anda dapat membaca di sini .

Kirill V. Lyadvinsky
sumber
35
Apa yang ditulis Anzurio hanya diklik bersamaan dengan jawaban Anda di bawah ini. Плус 1.
Iwillnotexist Idonotexist
2
Pemahaman saya tentang bagaimana ini bekerja SANGAT JAUH! Terima kasih banyak untuk klarifikasi.
tjwrona1992
saya butuh waktu untuk memahami hal ini. Tapi sekarang sudah jelas. Terima kasih!
Chan Kim
115

Membatasi visibilitas pewarisan akan membuat kode tidak dapat melihat bahwa beberapa kelas mewarisi kelas lain: Konversi tersirat dari turunan ke pangkalan tidak akan berfungsi, dan static_castdari pangkalan ke turunan tidak akan berfungsi baik.

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

warisan publik

  1. Warisan IS-A. Sebuah tombol adalah-jendela, dan di mana pun di mana dibutuhkan sebuah jendela, sebuah tombol dapat dilewati juga.

    class button : public window { };

warisan yang dilindungi

  1. Dilindungi diimplementasikan dalam istilah-of. Sangat berguna. Digunakan boost::compressed_pairuntuk mendapatkan dari kelas kosong dan menghemat memori menggunakan optimasi 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!
      }
    };

warisan pribadi

  1. Diimplementasikan-dalam-hal-dari. Penggunaan kelas dasar hanya untuk mengimplementasikan kelas turunan. Berguna dengan sifat dan jika ukuran penting (sifat kosong yang hanya berisi fungsi akan menggunakan optimasi kelas dasar kosong). Seringkali penahanan adalah solusi yang lebih baik. Ukuran untuk string sangat penting, jadi ini adalah penggunaan yang sering terlihat di sini

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

anggota publik

  1. Agregat

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

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

anggota yang dilindungi

  1. Memberikan peningkatan akses untuk kelas turunan

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

anggota pribadi

  1. Simpan detail implementasi

    class window {
    private:
      int width;
    };

Perhatikan bahwa cast gaya-C dengan sengaja memungkinkan casting kelas turunan ke kelas basis yang dilindungi atau privat dengan cara yang ditentukan dan aman dan untuk dilemparkan ke arah lain juga. Ini harus dihindari dengan cara apa pun, karena dapat membuat kode tergantung pada detail implementasi - tetapi jika perlu, Anda dapat menggunakan teknik ini.

Johannes Schaub - litb
sumber
7
Saya pikir Scott Myers (sama seperti saya suka barang-barangnya) memiliki banyak jawaban untuk kebingungan umum. Saya sekarang berpikir analoginya tentang IS-A dan IS-IMPLEMENTED-IN-SYARAT-OF cukup memadai untuk apa yang sedang terjadi.
DangerMouse
65

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

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

masukkan deskripsi gambar di sini

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

jika suatu komponen dinyatakan sebagai publik dan kelasnya diwarisi sebagai publik , akses yang dihasilkan adalah 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, rdi kelas Subsub adalah 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, zdi kelas Sub ini dilindungi dan untuk variabel xadalah tidak ada .

Contoh yang lebih rinci:

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 subclass dari kelas bernama Superatau Subkelas yang berasal dari Superkelas. The Submemperkenalkan kelas tidak variabel baru atau fungsi baru. Apakah ini berarti bahwa objek apa pun dari Subkelas mewarisi semua sifat setelah Superkelas sebenarnya merupakan salinan dari objek Superkelas?

Tidak ada . Tidak.

Jika kita mengkompilasi kode berikut, kita tidak akan mendapatkan apa-apa selain kesalahan kompilasi yang mengatakan bahwa putdan getmetode tidak dapat diakses. Mengapa?

Ketika kita menghilangkan specifier visibilitas, kompilator mengasumsikan bahwa kita akan menerapkan apa yang disebut warisan pribadi . Ini berarti bahwa semua masyarakat komponen superclass berubah menjadi pribadi akses, komponen superclass swasta tidak akan dapat diakses sama sekali. Karena itu berarti Anda tidak diperbolehkan menggunakan yang terakhir di dalam subkelas.

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

class Sub : public Super { };

Jangan salah : itu tidak berarti bahwa komponen pribadi dari kelas Super (seperti variabel penyimpanan) akan berubah menjadi komponen publik dengan cara yang agak ajaib. Komponen pribadi akan tetap pribadi , publik akan tetap publik .

Objek Subkelas dapat melakukan "hampir" hal yang sama seperti saudara kandung mereka yang dibuat dari Superkelas. "Hampir" karena fakta menjadi subclass juga berarti bahwa kelas kehilangan akses ke komponen pribadi dari superclass . Kami tidak dapat menulis fungsi anggota Subkelas yang akan dapat secara langsung memanipulasi variabel penyimpanan.

Ini adalah batasan yang sangat serius. Apakah ada solusi?

Ya .

Tingkat akses ketiga disebut dilindungi . Kata kunci yang dilindungi berarti bahwa komponen yang ditandai dengan itu berperilaku seperti yang umum ketika digunakan oleh salah satu subclass dan terlihat seperti yang pribadi ke seluruh dunia . - Ini hanya berlaku untuk kelas yang diwariskan kepada publik (seperti kelas Super dalam contoh kita) -

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 dalam kode contoh, kita memiliki fungsionalitas baru untuk Subkelas dan melakukan satu hal penting: mengakses variabel penyimpanan dari kelas Super .

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

object.storage = 0;

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

Akhirnya, program terakhir akan menghasilkan output berikut:

storage = 101
BugShotGG
sumber
4
Pertama yang menyebutkan kurangnya pengubah (seperti dalam Kelas: SuperClass) menghasilkan pribadi. Ini adalah bagian penting yang hilang, bersama dengan penjelasan menyeluruh. +1
Air
2
IMO berlebihan, tapi saya suka tabel di awal.
cp.engr
63

Ini berkaitan dengan bagaimana anggota publik dari kelas dasar diekspos dari kelas turunan.

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

Seperti ditunjukkan litb, warisan publik adalah warisan tradisional yang akan Anda lihat di sebagian besar bahasa pemrograman. Itu adalah model hubungan "IS-A". Warisan pribadi, sesuatu yang AFAIK khas C ++, adalah hubungan "IMPLEMENTED IN SYARAT OF". Itu adalah Anda ingin 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 mengagregasi kelas dasar, yang alih-alih menjadikan kelas dasar sebagai basis pribadi, buatlah anggota turunan untuk menggunakan kembali fungsionalitas kelas dasar.

Doug T.
sumber
13
Lebih baik mengatakan "publik: warisan akan dilihat oleh semua orang". dilindungi: warisan hanya akan dilihat oleh kelas turunan dan teman-teman "," pribadi: warisan hanya akan dilihat oleh kelas itu sendiri dan teman-teman ". Ini berbeda dari kata-kata Anda, karena tidak hanya para anggota dapat tidak terlihat, tetapi juga IS-Suatu relasi dapat terlihat.
Johannes Schaub - litb
4
Satu kali saya menggunakan warisan pribadi adalah untuk melakukan apa yang dijelaskan oleh Doug T yaitu "Anda ingin menggunakan antarmuka publik di kelas turunan, tetapi tidak ingin pengguna kelas turunan memiliki akses ke antarmuka itu". Saya pada dasarnya menggunakannya untuk menutup antarmuka lama dan mengekspos satu sama lain melalui kelas turunan.
Kaya
36
Member in base class : Private   Protected   Public   

Jenis warisan :              Objek yang diwarisi sebagai :

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public
kinshuk4
sumber
23
Ini menyesatkan. Anggota pribadi dari kelas dasar berperilaku sangat berbeda dari anggota kelas swasta biasa - mereka tidak dapat diakses dari kelas turunan sama sekali. Saya pikir kolom Anda tiga "Pribadi" harus menjadi kolom "Tidak dapat diakses". Lihat jawaban Kirill V. Lyadvinsky untuk pertanyaan ini.
Sam Kauffman
27

1) Waris Publik :

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

b. Anggota kelas Base yang dilindungi tetap dilindungi di kelas Turunan.

c. Anggota umum dari kelas Base tetap umum di kelas turunan.

Jadi, kelas lain dapat menggunakan anggota publik dari kelas Base melalui objek kelas turunan.

2) Warisan yang Dilindungi :

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

b. Anggota kelas Base yang dilindungi tetap dilindungi di kelas Turunan.

c. Anggota publik dari kelas Base juga menjadi anggota yang dilindungi dari kelas turunan.

Jadi, kelas lain tidak bisa menggunakan anggota publik kelas Base melalui objek kelas turunan; tetapi mereka tersedia untuk subclass dari Turunkan.

3) Warisan Pribadi :

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

b. Anggota kelas Base yang dilindungi & publik menjadi anggota pribadi kelas Turunan.

Jadi, tidak ada anggota kelas Base yang dapat diakses oleh kelas lain melalui objek kelas Derived karena mereka pribadi di kelas Derived. Jadi, bahkan subkelas dari kelas turunan tidak dapat mengaksesnya.

yuvi
sumber
20

Warisan publik memodelkan hubungan IS-A. Dengan

class B {};
class D : public B {};

setiap D a B .

Warisan pribadi memodelkan hubungan IS-IMPLEMENTED-USING (atau apa pun namanya). Dengan

class B {};
class D : private B {};

a Dadalah tidak satu B, tapi setiap Dmenggunakan yang Bdalam pelaksanaannya. Warisan pribadi selalu dapat dihilangkan dengan menggunakan penahanan:

class B {};
class D {
  private: 
    B b_;
};

Ini Djuga dapat diimplementasikan menggunakan B, dalam hal ini menggunakan nya b_. Kontainmen adalah kopling yang kurang ketat antara tipe dibandingkan pewarisan, jadi secara umum seharusnya lebih disukai. Terkadang menggunakan penahanan alih-alih warisan pribadi tidak senyaman warisan pribadi. Seringkali itu alasan lemah untuk menjadi malas.

Saya tidak berpikir ada yang tahu protectedmodel pewarisan apa . Setidaknya saya belum melihat penjelasan yang meyakinkan.

sbi
sumber
Beberapa mengatakan sebagai hubungan. Seperti menggunakan kursi sebagai palu. Kursi di sini: dilindungi hammer
user4951
saat menggunakan penahanan alih-alih warisan pribadi tidak senyaman warisan pribadi? Bisakah Anda jelaskan dengan menggunakan contoh?
Destructor
@Pravasi: Jika Dberasal dari pribadi D, itu dapat mengesampingkan fungsi virtual B. (Jika, misalnya, Badalah antarmuka pengamat, maka Ddapat mengimplementasikannya dan beralih thiske fungsi yang memerlukan antarmuka, tanpa semua orang dapat menggunakan Dsebagai pengamat.) Juga, Dsecara selektif dapat membuat anggota yang Btersedia di antarmuka dengan melakukan using B::member. Keduanya secara sintaksis tidak nyaman untuk diterapkan ketika Bmenjadi anggota.
sbi 6-15
@sbi: yang lama tapi ... kontainmen adalah jalan keluar dalam kasus CRTP dan / atau virtual (seperti yang Anda jelaskan dalam komentar - tetapi itu tidak bisa dimodelkan sebagai kontainmen jika B memiliki metode abstrak dan Anda tidak diizinkan menyentuhnya). protectedwarisan yang saya temukan berguna dengan virtualkelas dasar dan protectedctor:struct CommonStuff { CommonStuff(Stuff*) {/* assert !=0 */ } }; struct HandlerMixin1 : protected virtual CommonStuff { protected: HandlerMixin1() : CommonStuff(nullptr) {} /*...*/ }; struct Handler : HandlerMixin1, ... { Handler(Stuff& stuff) : CommonStuff(&stuff) {} };
lorro
11

Jika Anda mewarisi secara publik dari kelas lain, semua orang tahu Anda mewarisi dan Anda dapat digunakan secara polimorfik oleh siapa saja melalui pointer kelas dasar.

Jika Anda mewarisi secara dilindungi hanya kelas anak-anak Anda yang akan dapat menggunakan Anda secara polimorfik.

Jika Anda mewarisi secara pribadi hanya diri Anda yang dapat menjalankan metode kelas induk.

Yang pada dasarnya melambangkan pengetahuan yang dimiliki seluruh kelas tentang hubungan Anda dengan kelas orang tua Anda

Arkaitz Jimenez
sumber
9

Anggota data yang dilindungi dapat diakses oleh setiap kelas yang mewarisi dari kelas Anda. Namun, anggota data pribadi tidak bisa. Katakanlah kita memiliki yang berikut ini:

class MyClass {
    private:
        int myPrivateMember;    // lol
    protected:
        int myProtectedMember;
};

Dari dalam ekstensi Anda ke kelas ini, referensi this.myPrivateMembertidak akan berfungsi. Namun, this.myProtectedMemberakan. Nilainya masih dienkapsulasi, jadi jika kita memiliki instance kelas ini dipanggil myObj, maka myObj.myProtectedMembertidak akan berfungsi, jadi fungsinya mirip dengan anggota data pribadi.

Andrew Noyes
sumber
8
Accessors    | Base Class | Derived Class | World
—————————————+————————————+———————————————+———————
public       |      y     |       y       |   y
—————————————+————————————+———————————————+———————
protected    |      y     |       y       |   n
—————————————+————————————+———————————————+———————
private      |            |               |    
  or         |      y     |       n       |   n
no accessor  |            |               |

y: accessible
n: not accessible

Berdasarkan contoh ini untuk java ... Saya pikir sebuah meja kecil bernilai seribu kata :)

Enissay
sumber
Java hanya memiliki warisan publik
Zelldon
Ini bukan topik untuk berbicara tentang java tetapi TIDAK, Anda salah ... Ikuti tautan dalam jawaban saya di atas untuk detail
Enissay
Anda menyebutkan java jadi itu topiknya. Dan contoh Anda menangani specifier yang digunakan di jaca. Pertanyaannya adalah tentang penentu untuk warisan yang tidak ada di Jawa dan membuat perbedaan. Jika bidang dalam superclass bersifat publik dan warisan bersifat pribadi, bidang tersebut hanya dapat diakses di dalam subkelas. Di luar tidak ada indikasi jika subclass memperpanjang superclass. Tetapi tabel Anda hanya menjelaskan penentu untuk bidang dan metode.
Zelldon
7

Ringkasan:

  • Pribadi: tidak ada yang bisa melihatnya kecuali di dalam kelas
  • Terlindungi: Kelas privat + turunan dapat melihatnya
  • Publik: dunia dapat melihatnya

Saat mewarisi, Anda dapat (dalam beberapa bahasa) mengubah jenis perlindungan anggota data ke arah tertentu, misalnya dari terlindung ke publik.

Roee Adler
sumber
6

Pribadi:

Anggota pribadi dari kelas dasar hanya dapat diakses oleh anggota kelas dasar itu.

Publik:

Anggota publik dari kelas dasar dapat diakses oleh anggota kelas dasar itu, anggota kelas turunannya serta anggota yang berada di luar kelas dasar dan kelas turunan.

Terlindung:

Anggota yang dilindungi dari kelas dasar dapat diakses oleh anggota kelas dasar serta anggota kelas turunannya.


Pendeknya:

pribadi : basis

dilindungi : basis + berasal

publik : basis + berasal + anggota lain

varun
sumber
5

Saya menemukan jawaban yang mudah dan berpikir untuk mempostingnya untuk referensi saya di masa depan juga.

Ini dari tautan http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/

class Base
{
public:
    int m_nPublic; // can be accessed by anybody
private:
    int m_nPrivate; // can only be accessed by Base member functions (but not derived classes)
protected:
    int m_nProtected; // can be accessed by Base member functions, or derived classes.
};

class Derived: public Base
{
public:
    Derived()
    {
        // Derived's access to Base members is not influenced by the type of inheritance used,
        // so the following is always true:

        m_nPublic = 1; // allowed: can access public base members from derived class
        m_nPrivate = 2; // not allowed: can not access private base members from derived class
        m_nProtected = 3; // allowed: can access protected base members from derived class
    }
};

int main()
{
    Base cBase;
    cBase.m_nPublic = 1; // allowed: can access public members from outside class
    cBase.m_nPrivate = 2; // not allowed: can not access private members from outside class
    cBase.m_nProtected = 3; // not allowed: can not access protected members from outside class
}
Prajosh Premdas
sumber
3

Ini pada dasarnya adalah perlindungan akses dari publik dan anggota kelas dasar yang dilindungi di kelas turunan. Dengan warisan publik, kelas turunan dapat melihat anggota pangkalan publik dan yang dilindungi. Dengan warisan pribadi, itu tidak bisa. Dengan dilindungi, kelas turunan dan kelas apa pun yang berasal dapat melihatnya.

Dan Olson
sumber