Özel, genel ve korumalı miras arasındaki fark


Yanıtlar:


1064

Bu soruyu cevaplamak için önce üye erişimcilerini kendi kelimelerimle tanımlamak istiyorum. Bunu zaten biliyorsanız, "next:" başlığına atlayın.

Orada Bildiğim üç erişimciler şunlardır: public, protectedve private.

İzin Vermek:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • Farkında olan her şey, içerdiğinin Basede farkındadır .BasepublicMember
  • Sadece çocuklar (ve onların çocukları) biliyoruz Baseiçerir protectedMember.
  • Hiç kimse Basefarkında değil privateMember.

"Farkında" demekle "varlığını kabul etmeyi ve dolayısıyla erişebilmeyi" kastediyorum.

Sonraki:

Aynı şey kamu, özel ve korunmuş miras için de geçerlidir. Bir sınıfı Baseve Childmiras kalan bir sınıfı ele alalım Base.

  • Eğer miras ise public, farkında olan Baseve Childbunun da Childmiras olduğunun farkında olan her şey Base.
  • Eğer miras protectedsadece Childve çocuklarıysa, miras aldıklarının farkındadırlar Base.
  • Miras ise private, mirastan başka kimse Childbilmez.

182
C ++ görünürlük nesne yerine sınıfa dayalı birkaç kelime eklemek istiyorum, yani aynı sınıftaki nesneler kısıtlama olmadan birbirlerinin özel alanlarına erişebilirsiniz anlamına gelir.
Zhe Chen

48
Bunu anlamakta zorlanıyorsanız, Kirill V. Lyadvinsky'nin cevabını okuyun, sonra geri dönün ve bunu okuyun.
Vivandiere

6
Bu, çoğu zaman, SomeBaseanonim bir tür üyesini oluşturmak için nasıl zor kodlanmış bir yol gibi olduğunu gösteren başka bir durumdur SomeBase. Bu, diğer tüm üyeler gibi, aynı erişimi harici erişim üzerinde kullanan bir erişim belirtecine sahiptir.
underscore_d

1
@ZheChen Tom ve Jerry sınıflarım varsa Özel alan yaşına sahip kişi Tom'u kullanarak Tom'un yaşına nasıl erişirsiniz (ve değiştirirsiniz?)
gen

2
Ne demek istediğinizi "kalıtım" ın farkında olarak anlatabilir misiniz? Anlayabiliyorum "buna erişebiliyorum buna erişemiyorum" ama biri "A'nın B'den miras aldığını biliyorum" derken anlamıyorum. Burada ne yapıyorum mirasımı kontrol ediyorum?
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
};

ÖNEMLİ NOT: B, C ve D sınıflarının tümü x, y ve z değişkenlerini içerir. Bu sadece erişim meselesidir.

Korumalı ve özel miras kullanımı hakkında burada okuyabilirsiniz .


35
Anzurio'nun yazdıkları , hemen aşağıdaki cevabınızla birlikte tıklandı. Плус 1.
Iwillnotexist Idonotexist

2
Bunun nasıl çalıştığına dair anlayışım ÇOK UZAKTIR! Açıklığa kavuştuğunuz için çok teşekkür ederim.
tjwrona1992

bunu anlamam biraz zaman aldı. Ama şimdi açık. Teşekkürler!
Chan Kim

115

Kalıtımın görünürlüğünü sınırlamak, kodun bazı sınıfların başka bir sınıfı miras aldığını görememesini sağlar: Türetilmiş olandan tabana örtülü dönüşümler işe yaramaz ve static_casttabandan türetilene kadar da çalışmaz.

Yalnızca bir sınıfın üyeleri / arkadaşları özel kalıtım görebilir ve yalnızca üyeler / arkadaşlar ve türetilmiş sınıflar korumalı kalıtım görebilir.

halk mirası

  1. IS-A mirası. Düğme - bir penceredir ve bir pencerenin gerekli olduğu herhangi bir yerde, bir düğme de geçirilebilir.

    class button : public window { };

korumalı kalıtım

  1. Korumalı-terimler-içinde-uygulanır. Nadiren kullanışlıdır. Kullanılan boost::compressed_pair(Aşağıdaki örnek noktasında olmaya devam şablonu kullanmaz) boş taban sınıfı optimizasyonu kullanarak boş sınıflardan ve bellek tasarrufu türetmek için:

    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!
      }
    };

özel miras

  1. Uygulanan-terimler-in. Temel sınıfın kullanımı yalnızca türetilmiş sınıfın uygulanması içindir. Özelliklerle ve boyut önemliyse kullanışlıdır (yalnızca işlevler içeren boş özellikler, boş temel sınıf optimizasyonundan faydalanır). Bununla birlikte, genellikle muhafaza daha iyi bir çözümdür. Dizelerin boyutu kritiktir, bu yüzden burada sık görülen bir kullanımdır

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

kamu üyesi

  1. toplam

    class pair {
    public:
      First first;
      Second second;
    };
  2. Erişimciler

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

korunan üye

  1. Türetilmiş sınıflar için gelişmiş erişim sağlama

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

özel üye

  1. Uygulama ayrıntılarını sakla

    class window {
    private:
      int width;
    };

C-stil dökümlerin, türetilmiş bir sınıfın korumalı veya özel bir temel sınıfa tanımlanmış ve güvenli bir şekilde dökülmesine ve diğer yöne de dökülmesine izin verdiğini unutmayın. Her ne pahasına olursa olsun bundan kaçınılmalıdır, çünkü kodu uygulama ayrıntılarına bağlı hale getirebilir - ancak gerekirse bu tekniği kullanabilirsiniz.


7
Sanırım Scott Myers (eşyalarını sevdiğim kadarıyla) genel karışıklığa cevap verecek çok şey var. Şimdi IS-A ve IS-UYGULANAN-TERİMLER-OF benzerliklerinin olup bitenler için yeterli olduğunu düşünüyorum.
DangerMouse

65

Bu üç anahtar kelime, görünürlük devralma modelini belirtmek için tamamen farklı bir bağlamda da kullanılır .

Bu tablo, alt sınıf tamamen tanımlandığında bileşenlere sonuç olarak erişilmesini sağlayan bileşen bildirimi ve miras modelinin tüm olası birleşimlerini toplar.

resim açıklamasını buraya girin

Yukarıdaki tablo aşağıdaki şekilde yorumlanmıştır (ilk satıra bir göz atın):

Bir bileşen ise beyan olarak kamuoyuna ve sınıf edilir miras olarak kamuoyuna çıkan erişim olduğunu kamu .

Bir örnek:

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

 class Sub : private Super {};

 class Subsub : public Sub {};

Değişkenler için çıkan erişim p, q, rsınıfta Subsub olduğu hiçbiri .

Başka bir örnek:

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

Değişkenler için çıkan erişim y, zsınıf içinde Sub edilir korumalı ve değişken için xolan yok .

Daha ayrıntılı bir örnek:

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;
}

Şimdi bir alt sınıf tanımlayalım:

class Sub : Super { };

int main(void) {
    Sub object;

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

Ad adlı bir sınıfın alt sınıfı olan Sub adlı tanımlı sınıf Super, Subsınıftan türetilir Super. SubYeni değişkenler ne de yeni fonksiyonlar ne sınıf tanıtır. SubSınıfın herhangi bir nesnesinin, sınıfın Superaslında bir Supersınıfın nesnelerinin bir kopyası olması sonrasında tüm özellikleri miras aldığı anlamına mı geliyor ?

Hayır . Öyle değil.

Aşağıdaki kodu derlersek, derleme hatalarından başka bir şey elde edemeyiz putve derleme hataları ve getyöntemlere erişilemez. Neden?

Görünürlük belirtecini atladığımızda, derleyici özel miras olarak adlandırılacağımızı varsayar . Bu, tüm genel üst sınıf bileşenlerinin özel erişime dönüştüğü , özel üst sınıf bileşenlerine erişilemeyeceği anlamına gelir . Sonuç olarak, alt sınıfın içinde ikincisini kullanma izniniz olmadığı anlamına gelir.

Derleyiciye önceden kullanılan erişim politikasını korumak istediğimizi bildirmeliyiz.

class Sub : public Super { };

Yanlış yönlendirmeyin : bu, Super sınıfının özel bileşenlerinin (depolama değişkeni gibi) biraz büyülü bir şekilde herkese açık hale geleceği anlamına gelmez. Özel bileşenler kalacaktır özel , kamu kalacaktır kamu .

SubSınıftaki nesneler, sınıftan yarattıkları büyük kardeşleriyle "neredeyse" aynı şeyleri yapabilir Super. "Neredeyse" çünkü bir alt sınıf olması, sınıfın üst sınıfın özel bileşenlerine erişimi kaybettiği anlamına da gelir . SubDepolama değişkenini doğrudan işleyebilecek sınıfın üye işlevini yazamıyoruz .

Bu çok ciddi bir kısıtlama. Herhangi bir çözüm var mı?

Evet .

Üçüncü erişim seviyesine korumalı denir . Korumalı anahtar kelime, onunla işaretlenen bileşenin , alt sınıflardan herhangi biri tarafından kullanıldığında genel bir bileşen gibi davrandığı ve dünyanın geri kalanına özel bir bileşen gibi göründüğü anlamına gelir . - Bu yalnızca herkese açık olarak devralınan sınıflar için geçerlidir (örneğimizdeki Süper sınıf gibi) -

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;
}

Örnek kodda gördüğünüz gibi, Subsınıfa yeni bir işlevsellik kazandırır ve önemli bir şey yapar: depolama sınıfına Super sınıfından erişir .

Değişkenin özel olarak bildirilmesi mümkün olmazdı. Ana işlev kapsamında değişken yine de gizli kalır, böylece şöyle bir şey yazarsanız:

object.storage = 0;

Derleyici bunun bir olduğunu bildirecektir error: 'int Super::storage' is protected.

Son olarak, son program aşağıdaki çıktıyı üretecektir:

storage = 101

4
Bir değiştiricinin eksikliğinden bahseden ilk kişi (Sınıf: SuperClass'ta olduğu gibi) özel verir. Bu, ayrıntılı açıklamalarla birlikte, diğerlerinin kaçırdığı önemli bir parçadır. +1
Su

2
IMO'yu gereğinden fazla doldurdum, ama başlangıçta tabloyu beğendim.
cp.engr

63

Temel sınıfın kamu üyelerinin türetilmiş sınıftan nasıl açığa çıkmalarıyla ilgilidir.

  • public -> temel sınıfın herkese açık üyeleri herkese açık olur (genellikle varsayılan)
  • korumalı -> temel sınıfın kamu üyeleri korunacak
  • private -> base class'ın herkese açık üyeleri özel olacak

Litb'in işaret ettiği gibi, kamu mirası çoğu programlama dilinde göreceğiniz geleneksel mirastır. Yani "IS-A" ilişkisini modeller. Özel kalıtım, AFAIK C ++ 'a özgü bir şey, "ŞARTLARDA UYGULANAN" bir ilişkidir. Yani türetilmiş sınıfta ortak arabirimi kullanmak istiyorsunuz , ancak türetilmiş sınıf kullanıcısının bu arabirime erişmesini istemiyorsunuz. Birçoğu, bu durumda, temel sınıfı özel bir temel olarak kullanmak yerine, temel sınıfı bir araya getirmeniz gerektiğini, temel sınıfın işlevselliğini yeniden kullanmak için türetilmiş bir üye oluşturduğunu iddia eder.


13
"Herkese açık: miras herkes tarafından görülecektir" diyelim. korumalı: kalıtım sadece türetilmiş sınıflar ve arkadaşlar tarafından görülecektir "," özel: kalıtım sadece sınıfın kendisi ve arkadaşları tarafından görülecektir ". IS-A ilişkisi görünmez olabilir
Johannes Schaub - litb

4
Özel kalıtım kullandığım bir zaman, Doug T'nin açıkladığı şeyi yapmaktı, yani "türetilmiş sınıfta ortak arabirimi kullanmak istiyorsunuz, ancak türetilmiş sınıf kullanıcısının bu arabirime erişmesini istemiyorsunuz". Temelde eski arayüzü kapatmak ve türetilmiş sınıf üzerinden başka bir göstermek için kullandım.
Zengin

36
Member in base class : Private   Protected   Public   

Kalıtım türü :              Nesne şu şekilde miras alınır :

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

23
Bu yanıltıcı. Bir temel sınıfın özel üyeleri sıradan özel sınıf üyelerinden oldukça farklı davranırlar - türetilmiş sınıftan erişemezler. Üç "Özel" sütununuzun "Erişilemez" sütunu olması gerektiğini düşünüyorum. Kirill V. Lyadvinsky'nin bu soruya verdiği cevaba bakınız.
Sam Kauffman

27

1) Kamu Mirası :

a. Temel sınıftaki özel üyelere Türetilmiş sınıfta erişilemez.

b. Base sınıfının korumalı üyeleri Derived sınıfında korunur.

c. Temel sınıfın kamu üyeleri Türetilmiş sınıfta kamuya açıktır.

Böylece, diğer sınıflar Temel sınıfın ortak üyelerini Derived sınıf nesnesi aracılığıyla kullanabilir.

2) Korumalı Kalıtım :

a. Temel sınıftaki özel üyelere Türetilmiş sınıfta erişilemez.

b. Base sınıfının korumalı üyeleri Derived sınıfında korunur.

c. Temel sınıfın kamu üyeleri de Türetilmiş sınıfın korunan üyeleri haline gelir.

Bu nedenle, diğer sınıflar Temel sınıfın ortak üyelerini Derived sınıf nesnesi aracılığıyla kullanamaz; ancak Derived'in alt sınıfında kullanılabilirler.

3) Özel Miras :

a. Temel sınıftaki özel üyelere Türetilmiş sınıfta erişilemez.

b. Base sınıfının korunan ve kamu mensupları Derived sınıfının özel üyeleri olurlar.

Bu nedenle, Base sınıfının hiçbir üyesine, Derived sınıfında özel oldukları için Derived sınıf nesnesi aracılığıyla diğer sınıflar tarafından erişilemez. Böylece, Türetilmiş sınıfın alt sınıfı bile onlara erişemez.


20

Kamu kalıtımı bir IS-A ilişkisini modeller. İle

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

her D biri bir B .

Özel miras IS-UYGULANAN-KULLANMA ilişkisini (veya ne denirse) modeller. İle

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

Bir Dolduğu değil bir B, ama her DKullanımları Buygulanmasında. Özel kalıtım her zaman kısıtlama kullanılarak ortadan kaldırılabilir:

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

Bu Dda, Bbu durumda onun kullanılarak uygulanabilir b_. Muhafaza, türler arasında kalıtımdan daha az sıkı bir bağlantıdır, bu nedenle genel olarak tercih edilmelidir. Bazen özel miras yerine çevreleme kullanmak özel miras kadar uygun değildir. Genellikle tembel olmak için topal bir bahane.

Kimsenin hangi protectedmiras modellerini bildiğini sanmıyorum . En azından henüz ikna edici bir açıklama görmedim.


Bazıları bir ilişki olarak diyor. Sandalyeyi çekiç gibi kullanmak gibi. Burada sandalye: korumalı çekiç
user4951

özel miras yerine çevreyi kullanırken özel miras kadar uygun değildir? Lütfen bir örnek kullanarak açıklar mısınız?
Yıkıcı

@Pravasi: Eğer Dözel olarak türetilirse D, sanal işlevlerini geçersiz kılabilir B. (Örneğin, Bbir gözlemci arabirimiyse, o zaman Dbunu uygulayabilir ve thisherkes Dbir gözlemci olarak kullanamadan bir arabirim gerektiren işlevlere geçebilir .) Ayrıca, Dseçerek Barabirimindeki üyeleri seçerek kullanılabilir hale getirebilir using B::member. Her ikisi de Bbir üye olduğunda sözdizimi açısından elverişsizdir .
sbi

@sbi: eskisi ama ... çevreleme CRTP ve / veya sanallar için bir hareketsizdir (yorumda doğru bir şekilde tanımladığınız gibi - ama B'nin soyut yöntemleri varsa ve dokunmasına izin verilmez). protectedkalıtım Bir virtualtemel sınıf ve protectedctor ile yararlı buldum :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

Herkese açık olarak başka bir sınıftan miras alırsanız, herkes miras aldığınızı bilir ve bir temel sınıf işaretçisi aracılığıyla herkes tarafından polimorfik olarak kullanılabilir.

Korumalı olarak miras alırsanız, sadece çocuk sınıflarınız sizi polimorfik olarak kullanabilir.

Özel olarak miras alırsanız, yalnızca kendiniz üst sınıf yöntemlerini uygulayabilirsiniz.

Temel olarak, sınıfların geri kalanının ana sınıfınızla olan ilişkiniz hakkındaki bilgilerini sembolize eder.


9

Korumalı veri üyelerine, sınıfınızdan devralınan herhangi bir sınıf tarafından erişilebilir. Ancak özel veri üyeleri bunu yapamazlar. Diyelim ki aşağıdakiler var:

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

Uzantınızdan bu sınıfa kadar gönderme this.myPrivateMemberişe yaramaz. Ancak, this.myProtectedMemberolacak. Değer hala kapsüllenir, bu nedenle bu sınıfın bir örneğine sahipsek myObj, o myObj.myProtectedMemberzaman işe yaramaz, bu nedenle işlevde özel bir veri üyesine benzer.


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

Java için bu örneğe dayanarak ... Bence bin kelimeye bedel küçük bir tablo :)


Java sadece kamu mirasına sahiptir
Zelldon

Bu java hakkında konuşmak için konu değil ama HAYIR, yanılıyorsun ... Detaylar için yukarıdaki
cevabımdaki

Java'dan bahsettiniz, konu bu. Örneğiniz, jakada kullanılan belirteçleri ele alır. Soru, Java'da olmayan ve bir fark yaratan miras belirleyicileri hakkındadır. Üst sınıftaki bir alan herkese açıksa ve miras özelse, alan yalnızca alt sınıfın içinde erişilebilir olur. Dışarıda, alt sınıfın üst sınıfı genişletip genişletmediğine dair bir gösterge yoktur. Ancak tablonuzda yalnızca alan ve yöntemler için tanımlayıcılar açıklanmaktadır.
Zelldon

7

Özet:

  • Özel: sınıf dışında hiç kimse göremez
  • Korumalı: Özel + türetilmiş sınıflar bunu görebilir
  • Kamu: dünya görebilir

Devralınırken, (bazı dillerde) bir veri üyesinin koruma türünü belirli bir yönde, örneğin korumalıdan herkese açık olarak değiştirebilirsiniz.


6

Özel:

Bir temel sınıfın özel üyelerine yalnızca o temel sınıfın üyeleri erişebilir.

Halka açık:

Bir temel sınıfın kamu üyelerine, o temel sınıfın üyeleri, türetilmiş sınıfın üyeleri ve temel sınıf ve türetilmiş sınıfın dışındaki üyeler tarafından erişilebilir.

Korumalı:

Bir temel sınıfın korunan üyelerine, temel sınıfın üyeleri ve ayrıca türetilmiş sınıfın üyeleri tarafından erişilebilir.


Kısacası:

özel : temel

korumalı : baz + türetilmiş

public : base + türetilmiş + diğer herhangi bir üye


5

Kolay bir cevap buldum ve gelecekteki referansım için de göndermeyi düşündüm.

Http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/ bağlantılarından

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
}

3

Temelde, türetilmiş sınıftaki temel sınıfın kamusal ve korunan üyelerinin erişim korumasıdır. Toplumsal kalıtımla, türetilmiş sınıf üssün kamusal ve korunan üyelerini görebilir. Özel miras ile olamaz. Korumalı olarak, türetilmiş sınıf ve bundan türetilmiş sınıflar onları görebilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.