Kalıtım: "A", "B" nin erişilemez bir temelidir


82
$ cat inheritance.cpp 
#include <iostream>

using namespace std;

class A { };
class B : private A { };

int main() {
    A* ab = new B;
}
$
$ g++ inheritance.cpp
inheritance.cpp: In function 'int main()':
inheritance.cpp:9: error: 'A' is an inaccessible base of 'B'
$

Sadece bu hatayı anlamıyorum.

Anladığım kadarıyla ve bu öğreticinin de onayladığı gibi, privatemiras yalnızca üyelerinin class Bdış dünya tarafından nasıl göründüğünü değiştirmelidir .

Özel tanımlayıcının class Bburadaki üyelerin görünürlüğünü değiştirmekten daha fazlasını yaptığını düşünüyorum .

  • Bu hatayı ne alıyorum ve bu ne anlama geliyor?
  • Temel olarak, C ++ 'da bu tür bir koda izin vermenin nesi yanlış? Tamamen zararsız görünüyor.

Yanıtlar:


100

Kalıtımı özel hale getirerek, temel olarak B'nin A'dan miras almasının bile (hiç) özel olduğunu - dış dünya tarafından erişilebilir / görünür olmadığını söylüyorsunuz.

İzin verilirse ne olacağına dair uzun soluklu bir tartışmaya girmeden, basit gerçek, buna izin verilmemesidir. Türetilmiş türdeki bir nesneye başvurmak için tabana bir işaretçi kullanmak istiyorsanız, genel kalıtım kullanmakta oldukça sıkışıp kaldınız demektir.

Özel miras değil mutlaka (ya da normal) izlenmesi amaçlanan Liskov ikame prensibi . Açık miras türetilmiş bir amacı, ana sınıfı bir nesne ile ikame edilebilir, ve uygun anlam iddia edecek yine sonuçlanır. Özel miras yok değil buna da düşünmektedirler. Özel mirasın ima ettiği ilişkinin olağan açıklaması "açısından uygulanır" dır.

Genel miras, türetilmiş bir sınıfın temel sınıfın tüm yeteneklerini koruduğu ve bunun yanında potansiyel olarak daha fazlasını eklediği anlamına gelir. Özel miras genellikle aşağı yukarı tam tersi anlamına gelir: türetilmiş sınıf, daha kısıtlı bir arayüzle bir şeyi uygulamak için genel bir temel sınıf kullanır.

Örneğin, şimdilik C ++ standart kitaplığındaki kapsayıcıların şablonlar yerine kalıtım kullanılarak uygulandığını varsayalım. Mevcut sistemde, std::dequeve std::vectorkaplar, ve std::stackdaha kısıtlı bir arayüz sağlayan bir kap adaptörüdür. Şablonlara dayandığından, veya std::stackiçin bir adaptör olarak kullanabilirsiniz .std::dequestd::vector

Aynı şeyi mirasla sağlamak isteseydik, muhtemelen özel mirası kullanırdık, bu nedenle std::stackşöyle bir şey olurdu:

class stack : private vector {
    // ...
};

Bu durumda, biz kesinlikle yok değil kullansın manipüle edebilmek istiyorum stackbu bir sanki vector. Bunu yapmak, bir yığının beklentilerini ihlal edebilir (ve büyük olasılıkla) (örneğin, kullanıcı amaçlandığı gibi tamamen yığın benzeri bir moda yerine ortadaki öğeleri ekleyebilir / çıkarabilir). Biz temelde kullandığınız vectorbizim yığınını uygulamak için uygun bir yol olarak, ama (örneğin) biz uygulanmasını değiştirdiyseniz stackya da (hayır bir temel sınıf bağımlılıktan birlikte) tek başına standı açısından bunu yeniden uygulamak std::deque, biz do not bunu istiyorum herhangi bir müşteri kodunu etkilemek için - müşteri kodu için, bunun sadece bir yığın olması gerekir, özel bir vektör (veya deque) çeşidi değil.


1
bu aynı zamandaprotected
SubMachine

12

özel miras, yalnızca B sınıfı üyelerinin dış dünyaya nasıl göründüğünü değiştirmelidir

Öyle. Ve eğer

A* p = new B;

izin verildi, sonra herhangi birinin miras kalan üyelerine Bdış dünyadan sadece bir A*. Özel olarak miras alındıkları için, bu erişim yasa dışıdır ve yukarı yayın da öyle.


8

clang++ biraz daha anlaşılır bir hata mesajı veriyor:

example.cpp:9:13: error: cannot cast 'B' to its private base class 'A'
    A* ab = new B;
            ^
example.cpp:6:11: note: declared private here
class B : private A { };
          ^~~~~~~~~
1 error generated.

C ++ uzmanı değilim, ancak görünüşe göre buna izin verilmiyor. Spesifikasyonun etrafından dolaşıp ne bulduğuma bakacağım.

Düzenleme: İşte spesifikasyondaki ilgili referans - Bölüm 4.10 İşaretçi dönüştürmeleri , paragraf 3:

Tipte bir prvalue "işaretçi cv D ", Dbir sınıf tipidir, tip bir prvalue "cv için işaretçi dönüştürülebilir BB bir temel sınıftır" D. Eğer Bbir ulaşılmaz veya belirsiz temel sınıftır Dbu dönüşümü gerektiren bir program, kötü şekillendirilmiş olduğunu.


5

Oldukça basit: Aözel olarak miras alınan gerçeği, Bgenişlemenin Abir sır olduğu ve yalnızca B"bildiği" anlamına gelir. Özel mirasın tanımı budur.


4
Ben değiştirirseniz Ama aynı hatayı alıyorum privateile protected.
Lazer

2
Aslında. "Korumalı", bilginin sınırlı olduğu Bve alt sınıfları (ve arkadaşları) olduğu anlamına gelir B. " A* ab = new B;" Calt sınıfı olan varsayımsal bir sınıfta yasal olacaktır B.
Ernest Friedman-Hill

3

Özel miras, türetilmiş sınıfın dışında, miras bilgilerinin gizlendiği anlamına gelir. Bu, türetilmiş sınıfı temel sınıfa dönüştüremeyeceğiniz anlamına gelir: ilişki çağıran tarafından bilinmez.


Teşekkürler, ama bir şekilde mantıklı gelmiyor. privateTek iş, üyelerin nasıl davrandığını kontrol etmek olmalıdır. Miras bilgisi gizli kalmazsa ne zararı olur?
Lazer

1
Özel miras, bir toplama / kompozisyon biçimidir. Bu bir yolu var olmadan, bir temel sınıf özelliklerini olmanın temel sınıfın bir nesnesi. İstediğin bu değilse, özel miras sana göre değil. İşte böyle çalışıyor.
tmpearce

0

Bu çalışıyor

#include <iostream>

using namespace std;

class A{
    public:
        virtual void update() = 0;
};

class B: public A{
    public:
    virtual void update(){std::cout<<"hello";};
};

int main()
{
    A *a = new B();

    a->update();

    return 0;
}
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.