Apa perbedaan antara
public
,private
danprotected
warisan di C ++?
Semua pertanyaan yang saya temukan di SO menangani kasus-kasus tertentu.
Apa perbedaan antara
public
,private
danprotected
warisan di C ++?
Semua pertanyaan yang saya temukan di SO menangani kasus-kasus tertentu.
Jawaban:
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
, protected
dan private
.
Membiarkan:
class Base {
public:
int publicMember;
protected:
int protectedMember;
private:
int privateMember;
};
Base
juga sadar yang Base
berisi publicMember
.Base
berisi protectedMember
.Base
yang menyadari privateMember
.Dengan "menyadari", maksud saya "mengakui keberadaan, dan dengan demikian dapat mengakses".
Hal yang sama terjadi dengan warisan publik, swasta dan dilindungi. Mari kita pertimbangkan kelas Base
dan kelas Child
yang mewarisi dari Base
.
public
, segala sesuatu yang sadar Base
dan Child
juga sadar yang Child
mewarisi dari Base
.protected
, hanya Child
, dan anak-anaknya, sadar bahwa mereka mewarisinya Base
.private
, tidak ada orang lain Child
yang menyadari warisan itu.SomeBase
sama 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.
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 .
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_cast
dari 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
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
Dilindungi diimplementasikan dalam istilah-of. Sangat berguna. Digunakan boost::compressed_pair
untuk 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
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
Agregat
class pair {
public:
First first;
Second second;
};
Pengakses
class window {
public:
int getWidth() const;
};
anggota yang dilindungi
Memberikan peningkatan akses untuk kelas turunan
class stack {
protected:
vector<element> c;
};
class window {
protected:
void registerClass(window_descriptor w);
};
anggota pribadi
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.
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.
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
, r
di 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
, z
di kelas Sub ini dilindungi dan untuk variabel x
adalah 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 Super
atau Sub
kelas yang berasal dari Super
kelas. The Sub
memperkenalkan kelas tidak variabel baru atau fungsi baru. Apakah ini berarti bahwa objek apa pun dari Sub
kelas mewarisi semua sifat setelah Super
kelas sebenarnya merupakan salinan dari objek Super
kelas?
Tidak ada . Tidak.
Jika kita mengkompilasi kode berikut, kita tidak akan mendapatkan apa-apa selain kesalahan kompilasi yang mengatakan bahwa put
dan get
metode 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 Sub
kelas dapat melakukan "hampir" hal yang sama seperti saudara kandung mereka yang dibuat dari Super
kelas. "Hampir" karena fakta menjadi subclass juga berarti bahwa kelas kehilangan akses ke komponen pribadi dari superclass . Kami tidak dapat menulis fungsi anggota Sub
kelas 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 Sub
kelas 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
Ini berkaitan dengan bagaimana anggota publik dari kelas dasar diekspos dari kelas turunan.
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.
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
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.
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 D
adalah tidak satu B
, tapi setiap D
menggunakan yang B
dalam pelaksanaannya. Warisan pribadi selalu dapat dihilangkan dengan menggunakan penahanan:
class B {};
class D {
private:
B b_;
};
Ini D
juga 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 protected
model pewarisan apa . Setidaknya saya belum melihat penjelasan yang meyakinkan.
D
berasal dari pribadi D
, itu dapat mengesampingkan fungsi virtual B
. (Jika, misalnya, B
adalah antarmuka pengamat, maka D
dapat mengimplementasikannya dan beralih this
ke fungsi yang memerlukan antarmuka, tanpa semua orang dapat menggunakan D
sebagai pengamat.) Juga, D
secara selektif dapat membuat anggota yang B
tersedia di antarmuka dengan melakukan using B::member
. Keduanya secara sintaksis tidak nyaman untuk diterapkan ketika B
menjadi anggota.
protected
warisan yang saya temukan berguna dengan virtual
kelas dasar dan protected
ctor:struct CommonStuff { CommonStuff(Stuff*) {/* assert !=0 */ } }; struct HandlerMixin1 : protected virtual CommonStuff { protected: HandlerMixin1() : CommonStuff(nullptr) {} /*...*/ }; struct Handler : HandlerMixin1, ... { Handler(Stuff& stuff) : CommonStuff(&stuff) {} };
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
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.myPrivateMember
tidak akan berfungsi. Namun, this.myProtectedMember
akan. Nilainya masih dienkapsulasi, jadi jika kita memiliki instance kelas ini dipanggil myObj
, maka myObj.myProtectedMember
tidak akan berfungsi, jadi fungsinya mirip dengan anggota data pribadi.
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 :)
Ringkasan:
Saat mewarisi, Anda dapat (dalam beberapa bahasa) mengubah jenis perlindungan anggota data ke arah tertentu, misalnya dari terlindung ke publik.
Anggota pribadi dari kelas dasar hanya dapat diakses oleh anggota kelas dasar itu.
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.
Anggota yang dilindungi dari kelas dasar dapat diakses oleh anggota kelas dasar serta anggota kelas turunannya.
pribadi : basis
dilindungi : basis + berasal
publik : basis + berasal + anggota lain
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
}
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.